Skip to content

GameFrameX/GameFrameX.Server

Repository files navigation

GameFrameX Logo

GameFrameX Server

.NET License Documentation

All-in-One Solution for Indie Game Development · Empowering Indie Developers' Dreams

📖 Documentation · 🚀 Quick Start · 💬 QQ Group: 467608841


🌐 Language: English | 简体中文 | 繁體中文 | 日本語 | 한국어


Project Overview

GameFrameX Server is a high-performance game server framework built on C# .NET 10.0, featuring an Actor Model architecture with hot-update support. The framework enforces strict separation between persistent state and business logic, designed specifically for multiplayer online game scenarios.

Design Philosophy: Simplicity over complexity

Core Features

  • Actor Model — Lock-free high-concurrency architecture based on TPL DataFlow, avoiding traditional lock contention through message passing
  • State-Logic Separation — Strict separation between persistent data (Apps layer) and hot-updatable business logic (Hotfix layer)
  • Zero-Downtime Hot Updates — Replace business logic assemblies at runtime without restarting the server
  • Multi-Protocol Networking — Support for TCP, WebSocket, and HTTP protocols with built-in message encoding/decoding and compression
  • MongoDB Persistence — Transparent ORM mapping based on CacheState with automatic serialization/deserialization
  • Source Generator — Roslyn-based Agent code generation for automatic Actor message queue scheduling
  • Config Table System — Integrated Luban config generation with JSON hot-reloading
  • OpenTelemetry — Built-in Prometheus metrics export, health checks, and performance monitoring

Architecture

┌──────────────────────────────────────────────────────────────┐
│                       Client Layer                           │
├──────────────────────────────────────────────────────────────┤
│                      Network Layer                           │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │
│  │   TCP    │  │WebSocket │  │   HTTP   │  │   KCP    │    │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘    │
├──────────────────────────────────────────────────────────────┤
│                  Hotfix Layer (Hot-updatable)                │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  ComponentAgent  │  HttpHandler  │  EventHandler     │   │
│  └──────────────────────────────────────────────────────┘   │
├──────────────────────────────────────────────────────────────┤
│                  Apps Layer (Non-hot-updatable)              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                  │
│  │  State   │  │Component │  │ActorType │                  │
│  └──────────┘  └──────────┘  └──────────┘                  │
├──────────────────────────────────────────────────────────────┤
│                 Framework Layer (NuGet Packages)             │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │
│  │  Core    │  │ NetWork  │  │ DataBase │  │ Monitor  │    │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘    │
├──────────────────────────────────────────────────────────────┤
│                     Database Layer                           │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │                      MongoDB                             │ │
│  └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘

Quick Start

Prerequisites

Dependency Version
.NET SDK 10.0+
MongoDB 4.x+
IDE Visual Studio 2022 / JetBrains Rider / VS Code

Installation & Run

# 1. Clone the repository
git clone https://github.com/GameFrameX/Server_main.git
cd Server_main

# 2. Restore dependencies
dotnet restore

# 3. Build
dotnet build

# 4. Run the game server
dotnet run --project GameFrameX.Launcher \
    --ServerType=Game \
    --ServerId=1000 \
    --APMPort=29090

Verify Deployment

Endpoint URL Description
Health Check http://localhost:29090/health Service health status
Metrics http://localhost:29090/metrics Prometheus metrics
Test API http://localhost:28080/game/api/test HTTP connectivity test

Project Structure

Server_main/
├── GameFrameX.Launcher/         # Application entry point (Executable)
│   ├── Program.cs               # Bootstrap: register state types & protocol messages
│   └── StartUp/
│       └── AppStartUpGame.cs    # Game server startup flow
│
├── GameFrameX.Hotfix/           # Hot-update layer (Business logic, runtime-replaceable)
│   ├── Logic/
│   │   ├── Http/                # HTTP request handlers
│   │   │   ├── TestHttpHandler.cs
│   │   │   ├── ReloadHttpHandler.cs
│   │   │   ├── Player/          # Account login, online queries
│   │   │   └── Bag/             # Item sending
│   │   ├── Player/
│   │   │   ├── Bag/             # Bag component agent
│   │   │   ├── Login/           # Login/logout logic
│   │   │   └── Pet/             # Pet component agent
│   │   ├── Account/             # Account component agent
│   │   └── Server/              # Server global component agent
│   └── StartUp/                 # Hot-update startup flow
│       ├── AppStartUpHotfixGameByEntry.cs    # Entry point
│       ├── AppStartUpHotfixGameByMain.cs     # Network/connection management
│       ├── AppStartUpHotfixGameByHeart.cs    # Heartbeat handling
│       └── AppStartUpHotfixGameByGateWay.cs  # Gateway communication
│
├── GameFrameX.Apps/             # Application state layer (Non-hot-updatable)
│   ├── ActorType.cs             # Actor type enum definition
│   ├── Account/Login/           # Login state + component
│   ├── Player/
│   │   ├── Bag/                 # Bag state + component
│   │   ├── Player/              # Player state + component
│   │   └── Pet/                 # Pet state + component
│   ├── Server/                  # Server global state + component
│   └── Common/
│       ├── Session/             # Session management (SessionManager)
│       ├── Event/               # Event ID definitions
│       └── EventData/           # Event arguments
│
├── GameFrameX.Config/           # Config table system (Luban generated)
│   ├── ConfigComponent.cs       # Config loading singleton
│   ├── Tables/                  # Generated config table classes
│   ├── TablesItem/              # Config data models
│   └── json/                    # JSON config data files
│
├── GameFrameX.Proto/            # Network protocol definitions
│   ├── Basic_10.cs              # Basic protocols (heartbeat, etc.)
│   ├── Bag_100.cs               # Bag protocols
│   ├── User_300.cs              # User/account protocols
│   └── BuiltIn/                 # Built-in system protocols
│
├── GameFrameX.Architecture.Analyzers/        # Compile-time architecture rules
│
├── Server.sln                   # Visual Studio solution
├── Server.slnx                  # XML solution
├── Dockerfile                   # Docker multi-stage build
├── docker-compose.yml           # Docker Compose orchestration
└── LICENSE.md                   # Apache License 2.0

Usage Examples

Core Pattern: State - Component - Agent

GameFrameX uses a three-layer separation pattern that enables hot-updating business logic without server downtime.

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   State      │────▶│  Component   │◀────│ ComponentAgent│
│  (Data Def)  │     │   (Shell)    │     │  (Logic)     │
│  Apps Layer  │     │  Apps Layer  │     │ Hotfix Layer │
│  Not Hot-fix │     │  Not Hot-fix │     │  Hot-fixable │
└──────────────┘     └──────────────┘     └──────────────┘

Step 1: Define State (Apps Layer)

Inherit CacheState to define persistent data structures. The framework handles MongoDB serialization automatically.

// GameFrameX.Apps/Player/Bag/Entity/BagState.cs
public sealed class BagState : CacheState
{
    public Dictionary<int, BagItemState> List { get; set; } = new();
}

public sealed class BagItemState
{
    public long ItemId { get; set; }
    public long Count { get; set; }
}

Step 2: Create Component (Apps Layer)

Inherit StateComponent<TState> to serve as the bridge between state and logic.

// GameFrameX.Apps/Player/Bag/Component/BagComponent.cs
[ComponentType(GlobalConst.ActorTypePlayer)]
public class BagComponent : StateComponent<BagState> { }

Step 3: Implement Business Logic (Hotfix Layer)

Inherit StateComponentAgent<TComponent, TState> to write hot-updatable business code.

// GameFrameX.Hotfix/Logic/Player/Bag/BagComponentAgent.cs
public class BagComponentAgent : StateComponentAgent<BagComponent, BagState>
{
    public async Task OnAddBagItem(INetWorkChannel netWorkChannel,
        ReqAddItem message, RespAddItem response)
    {
        // Validate item config exists
        foreach (var item in message.ItemDic)
        {
            if (!ConfigComponent.Instance.GetConfig<TbItemConfig>()
                .TryGet(item.Key, out var _))
            {
                response.ErrorCode = (int)OperationStatusCode.NotFound;
                return;
            }
        }

        await UpdateChanged(netWorkChannel, message.ItemDic);
    }

    public async Task<BagState> UpdateChanged(INetWorkChannel netWorkChannel,
        Dictionary<int, long> itemDic)
    {
        var bagState = OwnerComponent.State;
        var notify = new NotifyBagInfoChanged();

        foreach (var item in itemDic)
        {
            if (bagState.List.TryGetValue(item.Key, out var value))
            {
                value.Count += item.Value;
            }
            else
            {
                bagState.List[item.Key] = new BagItemState
                {
                    Count = item.Value, ItemId = item.Key
                };
            }
        }

        await netWorkChannel.WriteAsync(notify);
        await OwnerComponent.WriteStateAsync(); // Auto-persist to MongoDB
        return bagState;
    }
}

HTTP Handler

Inherit BaseHttpHandler and register with [HttpMessageMapping].

// GameFrameX.Hotfix/Logic/Http/TestHttpHandler.cs
[HttpMessageMapping(typeof(TestHttpHandler))]
[HttpMessageResponse(typeof(HttpTestResponse))]
[Description("Test API endpoint")]
public sealed class TestHttpHandler : BaseHttpHandler
{
    public override Task<string> Action(string ip, string url,
        Dictionary<string, object> parameters)
    {
        var response = new HttpTestResponse { Message = "hello" };
        return Task.FromResult(HttpJsonResult.SuccessString(response));
    }
}

RPC Message Handler

The framework provides two RPC handler base classes with automatic ComponentAgent injection:

// Player-level message (bound to a specific player Actor)
[MessageMapping(typeof(ReqAddItem))]
internal sealed class AddItemHandler
    : PlayerRpcComponentHandler<BagComponentAgent, ReqAddItem, RespAddItem>
{
    protected override async Task ActionAsync(ReqAddItem request, RespAddItem response)
    {
        await ComponentAgent.OnAddBagItem(NetWorkChannel, request, response);
    }
}

// Global-level message (bound to the server Actor)
[MessageMapping(typeof(ReqHeartBeat))]
internal sealed class HeartBeatHandler
    : GlobalRpcComponentHandler<ServerComponentAgent, ReqHeartBeat, RespHeartBeat>
{
    protected override Task ActionAsync(ReqHeartBeat request, RespHeartBeat response)
    {
        return Task.CompletedTask;
    }
}

Event Handling

Use the [Event] attribute to bind event IDs. The framework automatically dispatches to the corresponding ComponentAgent.

[Event(EventId.PlayerLogin)]
internal sealed class PlayerLoginEventHandler : EventListener<PlayerComponentAgent>
{
    protected override Task HandleEvent(PlayerComponentAgent agent, GameEventArgs args)
    {
        return agent.OnLogin();
    }
}

Agent Method Attributes

The Roslyn source generator automatically handles Actor message queue scheduling. Control invocation behavior through attributes:

Attribute Description Use Case
[Service] Default mode; method calls are enqueued to the Actor message queue All business methods
[ThreadSafe] Skip message queue, invoke directly (requires thread-safe implementation) Read-only operations, stateless computation
[Discard] Fire-and-forget, do not await the return value Logging, statistics where results are not needed
[TimeOut(ms)] Set timeout for message queue invocation Long operations requiring timeout control
public class ServerComponentAgent : StateComponentAgent<ServerComponent, ServerState>
{
    // Enqueued to Actor message queue
    [Service]
    public virtual Task<bool> IsOnline(long roleId) { ... }

    // Skip message queue, thread-safe direct call
    [Service]
    [ThreadSafe]
    public virtual long FirstStartTime()
    {
        return State.FirstStartTime;
    }

    // Fire-and-forget, non-blocking
    [Service]
    [Discard]
    public virtual ValueTask AddOnlineRole(long roleId)
    {
        OwnerComponent.OnlineSet.Add(roleId);
        return ValueTask.CompletedTask;
    }
}

Config Table Access

Use the ConfigComponent singleton to access Luban-generated config tables:

var config = ConfigComponent.Instance.GetConfig<TbItemConfig>();

// Safe query with TryGet
if (config.TryGet(itemId, out var itemConfig))
{
    // Use itemConfig.Name, itemConfig.Type, etc.
}

Database Operations

Use the GameDb static class for MongoDB CRUD operations:

// Query
var state = await GameDb.FindAsync<LoginState>(
    m => m.UserName == userName && m.Password == password);

// Add or update
await GameDb.AddOrUpdateAsync(loginState);

// List query
var list = await GameDb.FindListAsync<LoginState>(m => m.Id != 0);

// Delete
var count = await GameDb.DeleteAsync(state);

Hot Update Mechanism

The hot-update system allows replacing business logic without stopping the server.

  • Apps Layer (GameFrameX.Apps): Contains state definitions and component shells — not hot-updatable
  • Hotfix Layer (GameFrameX.Hotfix): Contains all business logic — hot-updatable
  • Hotfix assembly outputs to the hotfix/ directory, loaded at runtime by HotfixManager
# Trigger via HTTP endpoint (with version number)
curl "http://localhost:28080/game/api/Reload?version=1.0.1"

Architecture Analyzers

GameFrameX.Architecture.Analyzers is a Roslyn analyzer project that enforces the Apps/Hotfix architecture at compile time. It is referenced as an analyzer by GameFrameX.Apps, GameFrameX.Hotfix, and GameFrameX.Launcher only; GameFrameX.Config, GameFrameX.Proto, and test assemblies are ignored by design.

ID Rule
GFX0001 BaseCacheState subclasses must be defined in GameFrameX.Apps.
GFX0002 StateComponent<TState> subclasses must be defined in GameFrameX.Apps.
GFX0003 BaseHttpHandler subclasses must be defined in GameFrameX.Hotfix.
GFX0004 IHotfixBridge implementations must be defined in GameFrameX.Hotfix.
GFX0005 IComponentAgent implementations must be defined in GameFrameX.Hotfix.
GFX0006 [MessageMapping] handlers must be defined in GameFrameX.Hotfix.
GFX0007 [MessageRpcMapping] handlers must be defined in GameFrameX.Hotfix.
GFX0008 IEventListener implementations must be defined in GameFrameX.Hotfix.
GFX0009 ITimerHandler implementations must be defined in GameFrameX.Hotfix.
GFX0010 [MessageMapping] handlers must be sealed.
GFX0011 IEventListener implementations must be sealed.
GFX0012 [MessageMapping] handler type names must end with Handler.
GFX0013 IEventListener implementation type names must end with EventListener.
GFX0014 IComponentAgent implementation type names must end with ComponentAgent.

Documentation & Resources

Configuration

Parameter Description Default Example
ServerType Server type Game
ServerId Unique server ID 1000
InnerPort TCP internal port 29100
HttpPort HTTP service port 0 28080
WsPort WebSocket service port 0 29110
MetricsPort Prometheus metrics port 0 29090
DataBaseUrl MongoDB connection string mongodb://localhost:27017
DataBaseName Database name gameframex

[!NOTE] The table above lists only the minimum startup parameters. For the complete configuration reference (network, logging, actor, monitoring, security, etc.), see Configuration Management — GameFrameX.Server.Source.

dotnet GameFrameX.Launcher.dll \
    --ServerType=Game \
    --ServerId=1000 \
    --InnerPort=29100 \
    --HttpPort=28080 \
    --WsPort=29110 \
    --MetricsPort=29090 \
    --DataBaseUrl=mongodb://127.0.0.1:27017 \
    --DataBaseName=game_db

Docker Deployment

docker-compose up --build
Port Protocol Description
29090 HTTP APM metrics / Health check
29100 TCP Game client connections
29110 WebSocket WebSocket connections
28080 HTTP HTTP API

Message Protocol

Message IDs are calculated by module ID shift: (moduleId << 16) + seqId

Module ID Range File Description
System -10 ~ -1 Player_-10.cs, Service_-3.cs Built-in system protocols
Basic 10 Basic_10.cs Heartbeat, server ready notification
Bag 100 Bag_100.cs Item CRUD, use, compose
User 300 User_300.cs Login, register, character list

Tech Stack

Component Technology
Runtime .NET 10.0
Database MongoDB
Networking SuperSocket
Serialization protobuf-net
Config Generation Luban
Code Generation Roslyn Source Generator
Monitoring OpenTelemetry + Prometheus
Object Mapping Mapster
Containerization Docker + Docker Compose

Community & Support

Contributing

  1. Fork this repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add some feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Create a Pull Request

License

This project is licensed under the Apache License 2.0. See the LICENSE.md file for details.

About

High-performance game server framework built on C# .NET 10.0 with Actor Model architecture, hot-update support, multi-protocol networking (TCP/WebSocket/HTTP/KCP), MongoDB persistence, and OpenTelemetry monitoring.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages