fb is a 2D MMORPG game server written in C++20.
- High-performance: Designed for scalability and real-time gameplay
- Microservices Architecture: Separate components for gateway, login, game, internal services, and write-back operations
- Cross-platform: Supports both Windows and Linux environments for development and production deployment
- Comprehensive Testing: Bot testing framework for load testing and integration testing
- Lua Scripting: Flexible game logic implementation through Lua scripts
- Cloud Deployment: Kubernetes deployment support with Pulumi infrastructure management
The server is organized into three layers:
- MySQL (Global): Stores global data shared across all servers (accounts, global configuration)
- MySQL (Data): Sharded databases for game data (characters, items, etc.)
- MySQL (Log): Sharded databases dedicated to logging (player actions, system events)
- Redis: Distributed cache layer for hot data, reducing database load
- RabbitMQ (Data): Message broker for inter-server notifications and events
- RabbitMQ (Log): Message broker for asynchronous log processing
- Internal: Enables communication between the gateway, login, and game servers, and manages database operations. It synchronizes global resources (e.g., parties, clans) and broadcasts notifications via RabbitMQ (Data).
- Write-back: A standalone process that persists cached data from Redis to MySQL (Data/Global). It batches database writes for optimal performance.
- Log Scheduler: Consumes log messages from RabbitMQ (Log) and writes them directly to MySQL (Log) without going through the write-back process.
Publicly accessible services that clients can directly connect to:
- Gateway: The first point of contact for clients. It checks client version, issues encryption keys, and provides a list of available login servers.
- Login: Handles account-related tasks like character creation and password changes, then directs clients to a game server. It communicates with other servers via the internal service.
- Game: Runs one process per zone rather than scaling out. It also uses the internal service to communicate with other game servers.
The game server divides each map into sectors. When an object's position changes, it may move to a different sector. For spatial queries, only nearby sectors are considered, reducing search costs.
All game logic for objects on the same map runs on the same logic thread. The I/O thread receives data and posts packets to the appropriate logic thread's queue. The logic thread parses the packet and runs the handler. We assign the logic thread by map ID:
thread_id = character.map.id % (logic_thread.length+1)This ensures objects on the same map are always processed by the same thread, eliminating locks between nearby objects. However, uneven map distribution can overload a single thread, and communication between different maps becomes more complex. You can configure the counts of I/O and logic threads in the config file.


