logo
0
0
WeChat Login
style(readme): 应用标准头部模板,添加居中布局和导航链接

GameFrameX Logo

GameFrameX Server

Version .NET License Documentation

高效能、跨平臺的遊戲伺服器框架

📖 文檔🚀 快速開始💬 QQ群: 467608841


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


目錄


框架簡介

GameFrameX Server 是基於 C# .NET 10.0 開發的高效能、跨平臺遊戲伺服器框架,採用 Actor 模型設計,支援熱更新機制。專為多人線上遊戲開發而設計,支援 Unity3D、Godot、LayaBox 等多種客戶端平臺整合。

設計理念:大道至簡,以簡化繁

核心特性

高效能架構

  • Actor 模型:基於 TPL DataFlow 構建的無鎖高併發系統,透過訊息傳遞機制避免傳統鎖效能損耗
  • 全非同步程式設計:完整的 async/await 非同步程式設計模型
  • 零鎖設計:Actor 內部狀態透過訊息佇列序列化存取,無需加鎖
  • 批次持久化:支援批次資料庫寫入,可配置批次大小和逾時時間
  • 雪花 ID 生成:內建分散式唯一 ID 生成器,支援工作節點和資料中心配置

熱更新系統

  • 零停機更新:執行時載入新邏輯組件,無需停止服務
  • 狀態邏輯分離:持久化狀態資料(Apps 層)與可熱更業務邏輯(Hotfix 層)嚴格分離
  • 優雅過渡:舊組件保留 10 分鐘寬限期,等待進行中請求完成後卸載
  • 版本管理:支援透過 HTTP 端點指定版本號載入

多協議網路通訊

  • TCP:基於 SuperSocket 的高效能 TCP 伺服器,主要遊戲通訊協議
  • UDP:可選的 UDP 協議支援
  • WebSocket:基於 SuperSocket WebSocket 的雙向通訊
  • HTTP/HTTPS:基於 Kestrel 的 HTTP 服務,支援 Swagger 文件、CORS、健康檢查
  • KCP:基於 KCP 協議的 UDP 可靠傳輸(實驗性)
  • 跨程序訊息:內建 RemoteMessaging 模組,支援斷路器、重試策略、一致性雜湊分片

資料庫與持久化

  • MongoDB 主資料庫:完整的 MongoDB 整合,支援健康狀態機(Healthy → Degraded → Unhealthy → Recovering)
  • 透明持久化:StateComponent 自動序列化/反序列化,透過定時批次 ReplaceOne 操作持久化
  • 連線池管理:可配置的連線池和重試策略
  • OpenTelemetry 整合:資料庫操作指標(延遲、重試次數、健康狀態)

監控與可觀測性

  • OpenTelemetry:全面的指標(Metrics)、追蹤(Tracing)和日誌(Logging)
  • Prometheus:原生指標匯出端點
  • Grafana Loki:日誌聚合輸出支援
  • Serilog:結構化日誌,支援控制檯、檔案、Loki 多輸出

系統架構

┌─────────────────────────────────────────────────────────────────┐
│                          客戶端層                                │
│         Unity3D / Godot / LayaBox / Cocos Creator               │
├─────────────────────────────────────────────────────────────────┤
│                          網路層                                  │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐           │
│  │   TCP    │ │WebSocket │ │   HTTP   │ │   KCP    │           │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘           │
├─────────────────────────────────────────────────────────────────┤
│                       訊息處理層                                  │
│  ┌────────────────┐ ┌────────────────┐ ┌────────────────┐      │
│  │ TCP 訊息處理器  │ │  HTTP 處理器   │ │ 跨程序訊息路由  │      │
│  └────────────────┘ └────────────────┘ └────────────────┘      │
├─────────────────────────────────────────────────────────────────┤
│                       Actor 層                                   │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐           │
│  │ 玩家     │ │ 伺服器   │ │  帳戶    │ │ 全域     │           │
│  │ Actor    │ │ Actor    │ │  Actor   │ │ Actor    │           │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘           │
├─────────────────────────────────────────────────────────────────┤
│                    元件-代理層(熱更新邊界)                        │
│  ┌─────────────────────┐  ┌─────────────────────────────┐      │
│  │ Apps 層 (不可熱更)   │  │ Hotfix 層 (可熱更)           │      │
│  │ StateComponent<T>   │←→│ StateComponentAgent<T,TState>│      │
│  │ CacheState          │  │ ComponentAgent               │      │
│  └─────────────────────┘  └─────────────────────────────┘      │
├─────────────────────────────────────────────────────────────────┤
│                       資料庫層                                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    MongoDB                               │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

專案結構

Server/
├── GameFrameX.Launcher/              # 應用入口點
├── GameFrameX.StartUp/               # 啟動編排和初始化
├── GameFrameX.Core/                  # 核心框架(Actor 系統、元件、事件、熱更新管理)
├── GameFrameX.Apps/                  # 狀態資料層(帳戶、玩家、伺服器模組)— 不可熱更
├── GameFrameX.Hotfix/                # 業務邏輯層(HTTP、玩家、伺服器處理器)— 可熱更
├── GameFrameX.Config/                # 遊戲配置表(JSON 格式,LuBan 生成)
├── GameFrameX.Core.Config/           # 核心配置管理
├── GameFrameX.Proto/                 # ProtoBuf 協議定義
├── GameFrameX.ProtoBuf.Net/          # ProtoBuf 序列化實作
├── GameFrameX.NetWork/               # 網路核心(訊息物件、傳送器、WebSocket)
├── GameFrameX.NetWork.Abstractions/  # 網路介面(IMessage、IMessageHandler、訊息映射)
├── GameFrameX.NetWork.HTTP/          # HTTP 伺服器(Swagger、Kestrel、BaseHttpHandler)
├── GameFrameX.NetWork.Kcp/           # KCP 協議支援(基於 UDP 的可靠傳輸)
├── GameFrameX.NetWork.Message/       # 訊息管道和編解碼
├── GameFrameX.NetWork.RemoteMessaging/ # 跨程序遠端訊息(斷路器、重試、一致性雜湊)
├── GameFrameX.DataBase/              # 資料庫抽象層
├── GameFrameX.DataBase.Mongo/        # MongoDB 實作(健康監控、重試、批次操作)
├── GameFrameX.Localization/          # 本地化系統(Keys.*.cs + .resx 資源檔案)
├── GameFrameX.Monitor/               # OpenTelemetry + Prometheus 指標整合
├── GameFrameX.Utility/               # 工具集(日誌、壓縮、物件池、Mapster、Harmony)
├── GameFrameX.Client/                # 測試客戶端(TCP 連線)
├── GameFrameX.CodeGenerator/         # Roslyn 原始碼生成器(熱更新代理包裝類別)
├── GameFrameX.AppHost/               # .NET Aspire 應用主機
├── GameFrameX.AppHost.ServiceDefaults/ # Aspire 共享預設配置(OTel、服務發現)
└── Tests/
    └── GameFrameX.Tests/             # xUnit 測試套件

快速開始

環境要求

安裝步驟

  1. 複製儲存庫

    git clone https://github.com/GameFrameX/GameFrameX.git
    cd GameFrameX/Server
    
  2. 還原相依套件

    dotnet restore
    
  3. 建置專案

    dotnet build
    
  4. 啟動 MongoDB

    # 本地安裝方式
    mongod --dbpath /path/to/data
    
    # 或使用 Docker
    docker run -d -p 27017:27017 --name mongo mongo:8.2
    
  5. 執行伺服器

    dotnet run --project GameFrameX.Launcher -- \
        --ServerType=Game \
        --ServerId=1000 \
        --OuterPort=29100 \
        --HttpPort=28080 \
        --DataBaseUrl=mongodb://127.0.0.1:27017 \
        --DataBaseName=gameframex
    
  6. 驗證啟動

    • 健康檢查:http://localhost:28080/game/api/health
    • 檢視控制檯日誌確認啟動成功

配置管理

GameFrameX 使用命令列參數 (--Key=Value) 進行配置,所有配置項定義在 StartupOptions 類別中。

伺服器配置

配置項說明預設值範例
ServerType伺服器類型(必填)GameSocial
ServerId伺服器唯一標識 ID1000
ServerInstanceId伺服器實例 ID(區分同類型不同實例)01001
IsSingleMode是否單程序模式falsetrue
MinModuleId業務模組起始 ID(模組分片)0100
MaxModuleId業務模組結束 ID(模組分片)01000
TimeZone伺服器時區Asia/ShanghaiUTC
IsUseTimeZone是否啟用自訂時區falsetrue
Language語言設定zh-CN

網路配置

配置項說明預設值範例
InnerHost內部通訊 IP(叢集間)0.0.0.00.0.0.0
InnerPort內部通訊埠888829100
OuterHost外部通訊 IP(面向客戶端)0.0.0.00.0.0.0
OuterPort外部通訊埠29100
IsEnableTcp是否啟用 TCP 服務truetrue
IsEnableUdp是否啟用 UDP 服務falsetrue
IsEnableWebSocket是否啟用 WebSocketfalsetrue
WsPortWebSocket 埠888929300
IsEnableHttp是否啟用 HTTP 服務truetrue
HttpPortHTTP 服務埠808028080
HttpsPortHTTPS 服務埠443
HttpUrlAPI 介面根路徑/game/api//game/api/
HttpIsDevelopmentHTTP 開發模式(啟用 Swagger)falsetrue

資料庫配置

配置項說明預設值範例
DataBaseUrlMongoDB 連線字串mongodb://localhost:27017
DataBaseName資料庫名稱gameframex
DataBasePassword資料庫密碼your_password

Actor 配置

配置項說明預設值範例
ActorTimeOutActor 任務執行逾時(毫秒)3000060000
ActorQueueTimeOutActor 佇列逾時(毫秒)3000060000
ActorRecycleTimeActor 閒置回收時間(分鐘)1530
SaveDataInterval資料儲存間隔(毫秒)3000060000
SaveDataBatchCount批次儲存數量5001000
SaveDataBatchTimeOut批次儲存逾時(毫秒)3000060000

日誌配置

配置項說明預設值範例
IsDebug除錯日誌總開關falsetrue
LogIsConsole輸出到控制檯truefalse
LogIsWriteToFile輸出到檔案truefalse
LogEventLevel日誌級別DebugInformation
LogRollingInterval日誌滾動間隔DayHour
LogIsFileSizeLimit限制單個檔案大小truefalse
LogFileSizeLimitBytes檔案大小限制104857600 (100MB)52428800
LogRetainedFileCountLimit保留檔案數量3190
LogIsGrafanaLoki輸出到 Grafana Lokifalsetrue
LogGrafanaLokiUrlGrafana Loki 位址http://localhost:3100

監控配置

配置項說明預設值範例
IsOpenTelemetry啟用 OpenTelemetryfalsetrue
IsOpenTelemetryMetrics啟用指標收集falsetrue
IsOpenTelemetryTracing啟用分散式追蹤falsetrue
MetricsPortPrometheus 指標埠0(複用 HTTP 埠)9090
IsMonitorMessageTimeOut監控訊息處理逾時falsetrue
MonitorMessageTimeOutSeconds逾時閾值(秒)15

ID 生成配置

配置項說明預設值範例
WorkerId雪花 ID 工作節點 ID12
DataCenterId雪花 ID 資料中心 ID12

啟動命令範例

# 最小啟動參數
dotnet GameFrameX.Launcher.dll \
    --ServerType=Game \
    --ServerId=1000 \
    --DataBaseUrl=mongodb://127.0.0.1:27017 \
    --DataBaseName=game_db

# 完整啟動參數
dotnet GameFrameX.Launcher.dll \
    --ServerType=Game \
    --ServerId=1000 \
    --ServerInstanceId=1 \
    --InnerHost=0.0.0.0 \
    --InnerPort=29100 \
    --OuterHost=0.0.0.0 \
    --OuterPort=29100 \
    --HttpPort=28080 \
    --IsEnableHttp=true \
    --HttpIsDevelopment=true \
    --IsEnableWebSocket=false \
    --DataBaseUrl=mongodb://127.0.0.1:27017 \
    --DataBaseName=gameframex \
    --IsDebug=true \
    --IsOpenTelemetry=true \
    --IsOpenTelemetryMetrics=true \
    --LogIsConsole=true \
    --LogIsWriteToFile=true

業務邏輯開發

元件-代理模式

框架的核心設計模式是狀態-邏輯分離,將持久化狀態(Apps 層,不可熱更)與業務邏輯(Hotfix 層,可熱更)嚴格分離。

1. 定義狀態(Apps 層)

// GameFrameX.Apps/Player/BagState.cs
public class BagState : BaseCacheState
{
    public List<ItemData> Items { get; set; } = new List<ItemData>();
    public int MaxSlots { get; set; } = 50;
}

2. 建立元件(Apps 層)

// GameFrameX.Apps/Player/BagComponent.cs
public class BagComponent : StateComponent<BagState>
{
    protected override async Task OnInit()
    {
        await base.OnInit();
        // 初始化元件狀態
    }
}

3. 實作業務邏輯(Hotfix 層)

// GameFrameX.Hotfix/Logic/Player/BagComponentAgent.cs
public class BagComponentAgent : StateComponentAgent<BagComponent, BagState>
{
    public async Task<bool> AddItem(int itemId, int count)
    {
        if (State.Items.Count >= State.MaxSlots)
        {
            return false;
        }

        var item = new ItemData { Id = itemId, Count = count };
        State.Items.Add(item);

        await Save();
        return true;
    }
}

4. 存取元件代理

// 透過 ActorManager 取得元件代理
var bagAgent = await ActorManager.GetComponentAgent<BagComponentAgent>(playerId);
var result = await bagAgent.AddItem(1001, 10);

HTTP 處理器

HTTP 處理器繼承 BaseHttpHandler,使用 [HttpMessageMapping] 特性註冊路由。

[HttpMessageMapping(typeof(GetPlayerInfoHandler))]
[Description("取得玩家資訊")]
public sealed class GetPlayerInfoHandler : BaseHttpHandler
{
    public override async Task<MessageObject> Action(
        string ip, string url,
        Dictionary<string, object> parameters,
        MessageObject messageObject)
    {
        var request = (GetPlayerInfoRequest)messageObject;
        var response = new GetPlayerInfoResponse();

        var agent = await ActorManager.GetComponentAgent<PlayerComponentAgent>(request.PlayerId);
        if (agent == null)
        {
            response.ErrorCode = (int)ResultCode.PlayerNotFound;
            return response;
        }

        response.PlayerInfo = await agent.GetPlayerInfo();
        return response;
    }
}

TCP/RPC 訊息處理器

TCP 訊息處理器負責處理客戶端透過 TCP 連線傳送的遊戲訊息。

單向訊息處理器:

[MessageMapping(typeof(ReqChatMessage))]
internal sealed class ChatMessageHandler : PlayerComponentHandler<ChatComponentAgent, ReqChatMessage>
{
    protected override async Task ActionAsync(ReqChatMessage request)
    {
        await ComponentAgent.ProcessChatMessage(request);
    }
}

RPC 處理器(請求-回應):

[MessageMapping(typeof(ReqAddItem))]
internal sealed class AddItemHandler : PlayerRpcComponentHandler<BagComponentAgent, ReqAddItem, RespAddItem>
{
    protected override async Task ActionAsync(ReqAddItem request, RespAddItem response)
    {
        try
        {
            // ComponentAgent 由基類自動注入
            await ComponentAgent.AddItem(request, response);
        }
        catch (Exception e)
        {
            LogHelper.Fatal(e);
            response.ErrorCode = (int)OperationStatusCode.InternalServerError;
        }
    }
}

事件處理器

事件系統用於 Actor 之間的鬆耦合通訊。

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

        // 處理玩家登入事件
        return agent.OnLogin();
    }
}

熱更新機制

架構原理

熱更新系統透過 AssemblyLoadContext(可回收)實作組件的執行時載入和卸載:

┌───────────────────────────────────────────────────────┐
│  Apps 層(不可熱更)                                     │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐   │
│  │ StateComponent│  │ StateComponent│  │ StateComponent│  │
│  │   持久化狀態   │  │   持久化狀態   │  │   持久化狀態   │  │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘   │
│         │                │                │           │
├─────────┼────────────────┼────────────────┼───────────┤
│         ▼                ▼                ▼           │
│  Hotfix 層(可熱更)— 透過 AssemblyLoadContext 載入     │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐   │
│  │ComponentAgent│  │ComponentAgent│  │ComponentAgent│  │
│  │   業務邏輯    │  │   業務邏輯    │  │   業務邏輯    │  │
│  └─────────────┘  └─────────────┘  └─────────────┘   │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐   │
│  │ Msg Handler  │  │ EventHandler│  │ HttpHandler  │   │
│  └─────────────┘  └─────────────┘  └─────────────┘   │
└───────────────────────────────────────────────────────┘

熱更新流程

  1. 編譯新邏輯:建置更新後的 GameFrameX.Hotfix.dll
  2. 部署組件:複製到伺服器指定目錄
  3. 觸發重新載入:透過 HTTP 端點發起熱更新請求
  4. 組件載入HotfixManager 使用可回收的 AssemblyLoadContext 載入新 DLL
  5. 型別掃描HotfixModule 掃描新組件中的代理、處理器和事件監聽器
  6. 代理切換ActorManager.ClearAgent() 清除快取的代理實例
  7. 優雅過渡:舊組件保留 10 分鐘寬限期,等待進行中請求完成後卸載

熱更新 API

# 觸發熱更新(指定版本號)
curl -X POST "http://localhost:28080/game/api/Reload?version=1.7.2"

Docker 部署

單實例部署

使用 docker-compose.yml 啟動包含 MongoDB + Game + Social 的完整環境:

# 建置並啟動
docker compose up -d --build

# 檢視執行狀態
docker compose ps

# 檢視日誌
docker compose logs -f game social

# 停止
docker compose down

服務埠映射:

服務容器內埠宿主機埠說明
MongoDB2701737017資料庫
Game TCP2910039100遊戲伺服器
Game HTTP2808038080遊戲伺服器 HTTP API
Social TCP2940039400社交伺服器
Social HTTP2808138081社交伺服器 HTTP API

多實例部署

使用 docker-compose.multi.yml 啟動包含 1 個 MongoDB + 2 個 Social + 10 個 Game 的叢集環境:

# 建置並啟動
docker compose -f docker-compose.multi.yml up -d --build

# 檢視執行狀態
docker compose -f docker-compose.multi.yml ps

# 停止
docker compose -f docker-compose.multi.yml down

叢集拓撲:

元件實例數說明
MongoDB1共享資料庫
Social2社交伺服器(social-1, social-2)
Game10遊戲伺服器(game-1 ~ game-10)

所有實例透過 Aspire 風格的環境變數進行服務發現:

environment:
  services__Social_2001__tcp__0: "tcp://social-1:29400"
  services__Social_2002__tcp__0: "tcp://social-2:29401"
  services__Game_1001__tcp__0: "tcp://game-1:29100"
  # ...

自訂建置

# 建置映像
docker build -t gameframex/server:custom .

# 執行
docker run -d \
    --name my-game-server \
    -p 29100:29100 \
    -p 28080:28080 \
    gameframex/server:custom \
    --ServerType=Game \
    --ServerId=2000 \
    --DataBaseUrl=mongodb://mongo-host:27017 \
    --DataBaseName=my_game

多程序跨程序聯調

跨程序 Smoke 測試

# 確保多實例環境已啟動
docker compose -f docker-compose.multi.yml up -d --build

# 執行跨程序冒煙測試
./scripts/multi/smoke-cross-process.sh

指令碼驗證內容:

  • game-1social 跨程序呼叫
  • game-2social 跨程序呼叫
  • 回傳 code=0FriendCount >= 1

機器人壓力測試

模擬真實客戶端反覆「登入 → 線上 → 主動斷開 → 重連登入」:

# 預設參數執行
./scripts/multi/run-bots-rpc.sh

# 自訂參數
BOT_COUNT=200 \
TCP_PORT=49100 \
LOGIN_URL=http://127.0.0.1:48080/game/api/ \
DISCONNECT_AFTER_LOGIN_SECONDS=20 \
RUN_SECONDS=300 \
./scripts/multi/run-bots-rpc.sh

可選環境變數:

變數說明預設值
BOT_COUNT機器人數量
TCP_PORTTCP 連線埠49100
LOGIN_URL登入介面位址http://127.0.0.1:48080/game/api/
DISCONNECT_AFTER_LOGIN_SECONDS登入後斷開延遲(秒)20
RUN_SECONDS總執行時長(秒)300

常用排查命令

# 檢視所有服務日誌
docker compose -f docker-compose.multi.yml logs -f

# 檢視指定服務日誌
docker compose -f docker-compose.multi.yml logs -f game-1 game-2 social-1 social-2

# 重建並啟動(程式碼變更後)
docker compose -f docker-compose.multi.yml up -d --build

監控與可觀測性

端點

端點說明
http://<host>:<HttpPort>/game/api/health健康檢查
http://<host>:<MetricsPort>/metricsPrometheus 指標

指標分類

  • 資料庫:操作延遲(db_operation_latency_ms)、重試次數(db_open_retry_total)、健康狀態(db_health_status
  • 網路:連線數、訊息吞吐量、位元組傳輸量
  • 業務:玩家登入數、活躍工作階段數
  • 系統:GC 效能、執行緒池狀態

測試

執行測試

# 執行所有測試
dotnet test

# 執行指定測試專案
dotnet test Tests/GameFrameX.Tests/GameFrameX.Tests.csproj

# 執行並顯示詳細輸出
dotnet test --logger "console;verbosity=detailed"

測試覆蓋範圍

測試專案基於 xUnit,覆蓋以下模組:

測試目錄說明
Utility/數學/定點數測試、壓縮、隨機數、ID 生成、單例
NetWork/Kcp/KCP 管道過濾器、工作階段管理、伺服器整合測試
DataBase/MongoDB 連線和查詢測試
ProtoBuff/Protobuf 序列化和物件池測試
Localization/本地化鍵值解析測試
RemoteMessaging/跨程序訊息測試
UnifiedMessaging/統一跨程序訊息測試
StartUp/HTTP 伺服器路由註冊測試

貢獻指南

我們歡迎任何形式的貢獻!請遵循以下步驟:

  1. Fork 本儲存庫
  2. 建立功能分支(git checkout -b feature/amazing-feature
  3. 提交變更(git commit -m 'feat: 新增某個功能'
  4. 推送到分支(git push origin feature/amazing-feature
  5. 建立 Pull Request

提交資訊請遵循 Angular 提交規範


許可證

本專案採用 MIT 許可證Apache License 2.0 雙許可證分發。詳見 LICENSE 檔案。


相關連結


如果這個專案對你有幫助,請給我們一個 Star

Made by GameFrameX Team