A high-performance, modern C++23 multiplayer card game server framework with async networking
Features • Architecture • Quick Start • Documentation • Contributing
Local Gameplay Engine is a production-ready, highly scalable multiplayer card game server framework built with modern C++23. It provides a complete infrastructure for hosting real-time card games over LAN with automatic server discovery, state machine-driven game logic, and thread-safe concurrent operations.
Originally designed for Teen Patti (Indian Poker), the engine's extensible architecture supports any turn-based card game with minimal modifications.
| Feature | Benefit |
|---|---|
| Modern C++23 | Leverages cutting-edge language features for safety and performance |
| Async I/O | Non-blocking networking with ASIO for high concurrency |
| State Machine | Clean, maintainable game logic with 11 distinct states |
| Auto Discovery | UDP multicast for seamless LAN server discovery |
| Thread-Safe | Comprehensive mutex protection and atomic operations |
| Extensible | Strategy pattern for easy game mode additions |
- Real-time Multiplayer - Support for up to 8 players per room (5 active at table)
- TCP Game Server - Reliable message delivery with automatic session management
- UDP Discovery - Multicast-based server broadcasting for LAN discovery
- State Machine Logic - 11-state game action system for complex game flows
- Card Comparison - Extensible ranking system (High Card → Trail)
- Timeout Handling - Automatic actions on player inactivity
- Zero Raw Pointers - Smart pointers throughout for memory safety
- RAII Everywhere - Deterministic resource cleanup
- C++23 Features -
std::print,std::expected,std::jthread, ranges, and more - Cross-Platform - Linux, macOS, and Windows support
- Modern CMake - Clean build configuration with vcpkg integration
| Feature | Description |
|---|---|
| Boot Collection | Initial ante collection from all players |
| Blind/Seen Play | Players can bet blind or view their cards |
| Chaal (Bet) | Standard betting with raise capability |
| Pack (Fold) | Fold and exit current hand |
| Show | Reveal cards for comparison |
| Side Show | Private card comparison between two players |
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLIENT APPLICATIONS │
│ (Mobile Apps, Desktop Clients, Web) │
└──────────────────────────────┬──────────────────────────────────────────────┘
│
┌────────────────┴────────────────┐
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ UDP Discovery │ │ TCP Game Server │
│ (Port 33407) │ │ (Port 45400+) │
│ │ │ │
│ • Multicast Broadcast │ │ • Session Management │
│ • Server Announcement │ │ • Message Routing │
│ • Auto-Discovery │ │ • Async I/O (ASIO) │
└─────────────────────────┘ └────────────┬────────────┘
│
┌───────────────┴───────────────┐
│ │
▼ ▼
┌────────────────────────────┐ ┌────────────────────────────┐
│ LocalGameplayController │ │ GameServerClientSession │
│ │ │ │
│ • Entry Point │ │ • Per-Client Handler │
│ • Lifecycle Management │ │ • Message Parsing │
│ • Delegate Implementation │ │ • Async Read/Write │
└─────────────┬──────────────┘ └────────────────────────────┘
│
▼
┌────────────────────────────┐
│ RoomController │
│ │
│ • Game Loop Thread │
│ • State Machine Driver │
│ • Player Management │
│ • Heartbeat Broadcasting │
└─────────────┬──────────────┘
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌─────────────┐ ┌──────────────────┐
│ IGameAction │ │ GameState │ │ LocalGameplay │
│ State Machine │ │ │ │ Messenger │
│ │ │ • Players │ │ │
│ • IdleAction │ │ • Amounts │ │ • Broadcasts │
│ • BootCollect │ │ • Timers │ │ • Notifications │
│ • UserInput │ │ • Cards │ │ • Game Events │
│ • Chaal/Fold │ │ • Status │ │ │
│ • Show/SideShow │ │ │ │ │
│ • GameEnd │ │ │ │ │
└──────────────────┘ └─────────────┘ └──────────────────┘
┌──────────────┐
│ IDLE │◄─────────────────────┐
│ (Waiting) │ │
└──────┬───────┘ │
│ ≥2 players │
▼ │
┌──────────────┐ │
│BOOT COLLECT │ │
│(Ante + Deal) │ │
└──────┬───────┘ │
│ │
▼ │
┌────────────────────────┐ │
│ USER INPUT │◄──────┐ │
│ (Waiting for Action) │ │ │
└───────────┬────────────┘ │ │
│ │ │
┌─────────────────┬───────────┼───────────┬────────┘ │
│ │ │ │ │
▼ ▼ ▼ ▼ │
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ CHAAL │ │ FOLD │ │ SHOW │ │ SIDE SHOW │ │
│ (Bet) │ │ (Pack) │ │ (Reveal) │ │ (Request) │ │
└────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ │ ▼ │
│ │ │ ┌──────────────┐ │
│ │ │ │SIDE SHOW │ │
│ │ │ │ACCEPT/REJECT │ │
│ │ │ └──────┬───────┘ │
│ │ │ │ │
└────────┬────────┴────────────┴──────────────┘ │
│ │
▼ │
┌──────────────┐ │
│ GAME END │──────────────────────────────────────────────┘
│(Winner/Pot) │
└──────────────┘
┌─────────────────────────────────────────────────────────────┐
│ APPLICATION LAYER │
│ LocalGameplayController, RoomController │
├─────────────────────────────────────────────────────────────┤
│ GAME LOGIC LAYER │
│ IGameAction States, GameState, ICardComparator │
├─────────────────────────────────────────────────────────────┤
│ COMMUNICATION LAYER │
│ GameServer, GameServerClientSession, LocalGameplayMessenger│
├─────────────────────────────────────────────────────────────┤
│ DATA LAYER │
│ GamePlayerInfo, CardDeck, UserAction, GameEndDetails │
├─────────────────────────────────────────────────────────────┤
│ INFRASTRUCTURE LAYER │
│ ASIO, Threads │
└─────────────────────────────────────────────────────────────┘
| Requirement | Version | Notes |
|---|---|---|
| C++ Compiler | GCC 14+, Clang 18+, MSVC 19.35+ | C++23 support required |
| CMake | 3.28+ | Modern CMake features |
| ASIO | Latest | Standalone (non-Boost) |
include(FetchContent)
FetchContent_Declare(
local_gameplay
GIT_REPOSITORY https://github.com/ayushmaanbhav/local_gameplay.git
GIT_TAG main
)
FetchContent_MakeAvailable(local_gameplay)
target_link_libraries(your_target PRIVATE local_gameplay)# Clone the repository
git clone https://github.com/ayushmaanbhav/local_gameplay.git
cd local_gameplay/cpp23
# Configure
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build
cmake --build build --parallel
# Install (optional)
sudo cmake --install build# Coming soon
vcpkg install local-gameplay#include <local_gameplay/LocalGameplayController.hpp>
int main() {
using namespace local_gameplay;
// Get the singleton controller
auto& controller = LocalGameplayController::getInstance();
// Start as host
bool success = controller.startAsHost(
"player_123", // Player ID
"HostPlayer", // Display name
1, // Avatar ID
"game_room_456", // Room ID
"High Stakes Table" // Table name
);
if (!success) {
std::println(stderr, "Failed to start game server");
return 1;
}
std::println("Server started on port: {}", controller.tcpPort());
std::println("Room ID: {}", controller.roomId());
// Server runs until stopped
// ... game logic ...
// Cleanup
controller.stop();
return 0;
}// Room configuration
RoomControllerConfiguration config;
config.setRoomInfo({
.boot_amount = 100, // Initial ante
.boot_limit = 1024, // Maximum boot
.max_chaal = 2048, // Maximum bet
.pot_limit = 100000, // Pot limit
.max_blind = 4, // Max blind rounds
.countdown_timer = 6000, // Game start countdown (ms)
.user_timer = 30000, // Player decision timeout (ms)
.side_show_timer = 12000 // Side show response timeout (ms)
});
config.setGameMode(GameMode::Normal);local_gameplay/
├── cpp23/ # Modern C++23 implementation
│ ├── CMakeLists.txt # Build configuration
│ ├── LocalGameplayController.* # Main entry point
│ ├── discovery/ # UDP multicast discovery
│ │ ├── UDPMessage.* # Discovery message format
│ │ ├── UDPMulticastClient.* # Discovery client
│ │ └── UDPMulticastServer.* # Discovery broadcaster
│ └── server/ # Game server components
│ ├── GameServer.* # TCP server
│ ├── GameServerClientSession.*
│ ├── LocalGameplayMessenger.*
│ ├── RoomController.*
│ ├── card_comparator/ # Card ranking logic
│ ├── entities/ # Data models
│ └── game_action/ # State machine actions
├── .github/ # GitHub configuration
│ ├── workflows/ # CI/CD pipelines
│ ├── ISSUE_TEMPLATE/ # Issue templates
│ └── FUNDING.yml # Sponsorship info
├── CONTRIBUTING.md # Contribution guidelines
├── CODE_OF_CONDUCT.md # Community standards
├── SECURITY.md # Security policy
└── LICENSE # License file
Represents a player in the game:
struct GamePlayerInfo {
std::string pid; // Player ID
std::string name; // Display name
UserGameState state; // Current state (Blind, Seen, Pack, etc.)
std::array<int, 3> cards; // Player's 3 cards
int64_t amount_in_hand; // Available chips
int64_t amount_in_game; // Chips in current pot
bool seen; // Has viewed cards
bool is_raise; // Raised this round
// ... additional fields
};
enum class UserGameState {
Inactive, Boot, Blind, Seen, Chaal, Pack, Show, SideShow
};Cards are represented as integers 0-51:
- Value:
card % 13(0=Ace, 1-9=2-10, 10=J, 11=Q, 12=K) - Suit:
card / 13(0=Spades, 1=Hearts, 2=Clubs, 3=Diamonds)
| Rank | Pattern | Description |
|---|---|---|
| 1 | High Card | Highest single card |
| 2 | Pair | Two cards of same value |
| 3 | Color (Flush) | All three cards same suit |
| 4 | Sequence (Straight) | Three consecutive values |
| 5 | Pure Sequence | Consecutive cards, same suit |
| 6 | Trail (Three of a Kind) | Three cards of same value |
Messages are delimited by backtick (`) character:
{message_type}|{payload_json}`
Multicast address: 239.255.116.91:33407
{game_mode};{server_ip};{table_name};{avatar_id}`
| Thread | Component | Purpose |
|---|---|---|
| Main | Caller context | Application control |
| I/O Thread | GameServer | ASIO async operations |
| Game Thread | RoomController | Game loop execution |
| Heartbeat Thread | RoomController | Periodic broadcasts |
Used for core services requiring single instance:
class GameServer {
public:
static GameServer& getInstance() {
static GameServer instance;
return instance;
}
GameServer(const GameServer&) = delete;
GameServer& operator=(const GameServer&) = delete;
private:
GameServer() = default;
};Game actions implement a state machine:
class IGameAction {
public:
virtual ~IGameAction() = default;
virtual void processUserInput(GameState&, const UserAction&) = 0;
virtual void processAction(GameState&) = 0;
virtual std::unique_ptr<IGameAction> getNextAction(GameState&) = 0;
virtual void interrupt() = 0;
};Card comparison is pluggable:
class ICardComparator {
public:
virtual ~ICardComparator() = default;
virtual std::vector<std::shared_ptr<GamePlayerInfo>>
getWinners(const GamePlayerInfoMap& players) = 0;
};
// Implementations: NormalModeCardComparator, JokerModeCardComparator, etc.Decoupled message handling:
class GameServerClientSession {
public:
class Delegate {
public:
virtual void processMessage(int session_id, std::string_view msg) = 0;
virtual void removeClosedSession(int session_id) = 0;
};
};This codebase showcases modern C++23 capabilities:
| Feature | Usage |
|---|---|
std::print/println |
Type-safe formatted output |
std::expected |
Error handling without exceptions |
std::string_view |
Zero-copy string parameters |
std::jthread |
Auto-joining threads with stop tokens |
std::span |
Non-owning array views |
std::ranges |
Modern algorithm pipelines |
<=> operator |
Defaulted comparisons |
[[nodiscard]] |
Enforce return value checking |
| Designated initializers | Named struct initialization |
| Option | Default | Description |
|---|---|---|
BUILD_EXAMPLES |
OFF | Build example applications |
BUILD_TESTS |
OFF | Build unit tests |
BUILD_SHARED_LIBS |
OFF | Build as shared library |
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_EXAMPLES=ON \
-DBUILD_TESTS=ON| Metric | Value | Notes |
|---|---|---|
| Connection handling | 10+ concurrent | Per room instance |
| Message latency | < 1ms | Local network |
| Memory per session | ~4KB | Minimal overhead |
| State transition | < 100μs | Fast game logic |
- Zero-copy messaging with
std::string_view - Object pooling for session management
- Lock-free atomics where possible
- Async I/O prevents blocking
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
# Clone with submodules
git clone --recursive https://github.com/ayushmaanbhav/local_gameplay.git
# Install dependencies (Ubuntu/Debian)
sudo apt install build-essential cmake ninja-build
# Install ASIO
sudo apt install libasio-dev
# Build with debug symbols
cmake -B build -DCMAKE_BUILD_TYPE=Debug -G Ninja
cmake --build build- Follow the C++ Core Guidelines
- Use
clang-formatwith the provided configuration - Write self-documenting code with clear naming
- Add Doxygen comments for public APIs
- WebSocket support for browser clients
- Multiple game mode implementations (Joker, AK47)
- Comprehensive test suite
- Performance benchmarking suite
- Docker containerization
- Kubernetes deployment manifests
- Documentation website
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Support the development of Local Gameplay Engine:
- GitHub Sponsors: @ayushmaanbhav
- UPI (India):
8544130924@pthdfc
Your sponsorship helps maintain and improve this project!
This project is licensed under the MIT License - see the LICENSE file for details.
- ASIO - Excellent async I/O library
- CMake - Cross-platform build system
- C++ Standards Committee - For C++23 features
Built with ❤️ by Ayush Jain