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 測試套件
- .NET 10.0 SDK
- MongoDB 4.x+
- Visual Studio 2022 或 JetBrains Rider(推薦)
-
複製儲存庫
git clone https://github.com/GameFrameX/GameFrameX.git cd GameFrameX/Server -
還原相依套件
dotnet restore
-
建置專案
dotnet build
-
啟動 MongoDB
# 本地安裝方式 mongod --dbpath /path/to/data # 或使用 Docker docker run -d -p 27017:27017 --name mongo mongo:8.2
-
執行伺服器
dotnet run --project GameFrameX.Launcher -- \ --ServerType=Game \ --ServerId=1000 \ --OuterPort=29100 \ --HttpPort=28080 \ --DataBaseUrl=mongodb://127.0.0.1:27017 \ --DataBaseName=gameframex -
驗證啟動
- 健康檢查:
http://localhost:28080/game/api/health - 檢視控制檯日誌確認啟動成功
- 健康檢查:
GameFrameX 使用命令列參數 (--Key=Value) 進行配置,所有配置項定義在 StartupOptions 類別中。
| 配置項 | 說明 | 預設值 | 範例 |
|---|---|---|---|
ServerType |
伺服器類型(必填) | 無 | Game、Social |
ServerId |
伺服器唯一標識 ID | 無 | 1000 |
ServerInstanceId |
伺服器實例 ID(區分同類型不同實例) | 0 |
1001 |
IsSingleMode |
是否單程序模式 | false |
true |
MinModuleId |
業務模組起始 ID(模組分片) | 0 |
100 |
MaxModuleId |
業務模組結束 ID(模組分片) | 0 |
1000 |
TimeZone |
伺服器時區 | Asia/Shanghai |
UTC |
IsUseTimeZone |
是否啟用自訂時區 | false |
true |
Language |
語言設定 | 無 | zh-CN |
| 配置項 | 說明 | 預設值 | 範例 |
|---|---|---|---|
InnerHost |
內部通訊 IP(叢集間) | 0.0.0.0 |
0.0.0.0 |
InnerPort |
內部通訊埠 | 8888 |
29100 |
OuterHost |
外部通訊 IP(面向客戶端) | 0.0.0.0 |
0.0.0.0 |
OuterPort |
外部通訊埠 | 無 | 29100 |
IsEnableTcp |
是否啟用 TCP 服務 | true |
true |
IsEnableUdp |
是否啟用 UDP 服務 | false |
true |
IsEnableWebSocket |
是否啟用 WebSocket | false |
true |
WsPort |
WebSocket 埠 | 8889 |
29300 |
IsEnableHttp |
是否啟用 HTTP 服務 | true |
true |
HttpPort |
HTTP 服務埠 | 8080 |
28080 |
HttpsPort |
HTTPS 服務埠 | 無 | 443 |
HttpUrl |
API 介面根路徑 | /game/api/ |
/game/api/ |
HttpIsDevelopment |
HTTP 開發模式(啟用 Swagger) | false |
true |
| 配置項 | 說明 | 預設值 | 範例 |
|---|---|---|---|
DataBaseUrl |
MongoDB 連線字串 | 無 | mongodb://localhost:27017 |
DataBaseName |
資料庫名稱 | 無 | gameframex |
DataBasePassword |
資料庫密碼 | 無 | your_password |
| 配置項 | 說明 | 預設值 | 範例 |
|---|---|---|---|
ActorTimeOut |
Actor 任務執行逾時(毫秒) | 30000 |
60000 |
ActorQueueTimeOut |
Actor 佇列逾時(毫秒) | 30000 |
60000 |
ActorRecycleTime |
Actor 閒置回收時間(分鐘) | 15 |
30 |
SaveDataInterval |
資料儲存間隔(毫秒) | 30000 |
60000 |
SaveDataBatchCount |
批次儲存數量 | 500 |
1000 |
SaveDataBatchTimeOut |
批次儲存逾時(毫秒) | 30000 |
60000 |
| 配置項 | 說明 | 預設值 | 範例 |
|---|---|---|---|
IsDebug |
除錯日誌總開關 | false |
true |
LogIsConsole |
輸出到控制檯 | true |
false |
LogIsWriteToFile |
輸出到檔案 | true |
false |
LogEventLevel |
日誌級別 | Debug |
Information |
LogRollingInterval |
日誌滾動間隔 | Day |
Hour |
LogIsFileSizeLimit |
限制單個檔案大小 | true |
false |
LogFileSizeLimitBytes |
檔案大小限制 | 104857600 (100MB) |
52428800 |
LogRetainedFileCountLimit |
保留檔案數量 | 31 |
90 |
LogIsGrafanaLoki |
輸出到 Grafana Loki | false |
true |
LogGrafanaLokiUrl |
Grafana Loki 位址 | http://localhost:3100 |
— |
| 配置項 | 說明 | 預設值 | 範例 |
|---|---|---|---|
IsOpenTelemetry |
啟用 OpenTelemetry | false |
true |
IsOpenTelemetryMetrics |
啟用指標收集 | false |
true |
IsOpenTelemetryTracing |
啟用分散式追蹤 | false |
true |
MetricsPort |
Prometheus 指標埠 | 0(複用 HTTP 埠) |
9090 |
IsMonitorMessageTimeOut |
監控訊息處理逾時 | false |
true |
MonitorMessageTimeOutSeconds |
逾時閾值(秒) | 1 |
5 |
| 配置項 | 說明 | 預設值 | 範例 |
|---|---|---|---|
WorkerId |
雪花 ID 工作節點 ID | 1 |
2 |
DataCenterId |
雪花 ID 資料中心 ID | 1 |
2 |
# 最小啟動參數
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 處理器繼承 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 訊息處理器負責處理客戶端透過 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 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└───────────────────────────────────────────────────────┘
- 編譯新邏輯:建置更新後的
GameFrameX.Hotfix.dll - 部署組件:複製到伺服器指定目錄
- 觸發重新載入:透過 HTTP 端點發起熱更新請求
- 組件載入:
HotfixManager使用可回收的AssemblyLoadContext載入新 DLL - 型別掃描:
HotfixModule掃描新組件中的代理、處理器和事件監聽器 - 代理切換:
ActorManager.ClearAgent()清除快取的代理實例 - 優雅過渡:舊組件保留 10 分鐘寬限期,等待進行中請求完成後卸載
# 觸發熱更新(指定版本號)
curl -X POST "http://localhost:28080/game/api/Reload?version=1.7.2"使用 docker-compose.yml 啟動包含 MongoDB + Game + Social 的完整環境:
# 建置並啟動
docker compose up -d --build
# 檢視執行狀態
docker compose ps
# 檢視日誌
docker compose logs -f game social
# 停止
docker compose down服務埠映射:
| 服務 | 容器內埠 | 宿主機埠 | 說明 |
|---|---|---|---|
| MongoDB | 27017 | 37017 | 資料庫 |
| Game TCP | 29100 | 39100 | 遊戲伺服器 |
| Game HTTP | 28080 | 38080 | 遊戲伺服器 HTTP API |
| Social TCP | 29400 | 39400 | 社交伺服器 |
| Social HTTP | 28081 | 38081 | 社交伺服器 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叢集拓撲:
| 元件 | 實例數 | 說明 |
|---|---|---|
| MongoDB | 1 | 共享資料庫 |
| Social | 2 | 社交伺服器(social-1, social-2) |
| Game | 10 | 遊戲伺服器(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# 確保多實例環境已啟動
docker compose -f docker-compose.multi.yml up -d --build
# 執行跨程序冒煙測試
./scripts/multi/smoke-cross-process.sh指令碼驗證內容:
game-1→social跨程序呼叫game-2→social跨程序呼叫- 回傳
code=0且FriendCount >= 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_PORT |
TCP 連線埠 | 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>/metrics |
Prometheus 指標 |
- 資料庫:操作延遲(
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 伺服器路由註冊測試 |
我們歡迎任何形式的貢獻!請遵循以下步驟:
- Fork 本儲存庫
- 建立功能分支(
git checkout -b feature/amazing-feature) - 提交變更(
git commit -m 'feat: 新增某個功能') - 推送到分支(
git push origin feature/amazing-feature) - 建立 Pull Request
提交資訊請遵循 Angular 提交規範。
本專案採用 MIT 許可證 與 Apache License 2.0 雙許可證分發。詳見 LICENSE 檔案。
如果這個專案對你有幫助,請給我們一個 Star
Made by GameFrameX Team
