Skip to content

Latest commit

 

History

History
520 lines (423 loc) · 21.3 KB

File metadata and controls

520 lines (423 loc) · 21.3 KB

GameFrameX Logo

GameFrameX Server

.NET License Documentation

獨立遊戲前後端一體化解決方案 · 獨立遊戲開發者的圓夢大使

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


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


項目簡介

GameFrameX Server 是基於 C# .NET 10.0 開發的高效能遊戲伺服器框架,採用 Actor 模型設計,支援熱更新機制。框架將持久化狀態與業務邏輯嚴格分離,專為多人線上遊戲場景設計。

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

核心特性

  • Actor 模型 — 基於 TPL DataFlow 的無鎖高並行架構,透過訊息傳遞避免傳統鎖競爭
  • 狀態-邏輯分離 — 持久化資料(Apps 層)與可熱更業務邏輯(Hotfix 層)嚴格分離
  • 零停機熱更新 — 執行時替換業務邏輯組件,無需重啟伺服器
  • 多協定網路 — 支援 TCP、WebSocket、HTTP 協定,內建訊息編解碼與壓縮
  • MongoDB 持久化 — 基於 CacheState 的透明 ORM 映射,自動序列化/反序列化
  • 原始碼產生器 — 基於 Roslyn 的 Agent 程式碼產生,自動處理 Actor 訊息佇列排程
  • 設定表系統 — 整合 Luban 設定產生,支援 JSON 熱載入
  • OpenTelemetry — 內建 Prometheus 指標匯出、健康檢查、效能監控

架構概覽

┌──────────────────────────────────────────────────────────────┐
│                         客戶端層                              │
├──────────────────────────────────────────────────────────────┤
│                         網路層                                │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │
│  │   TCP    │  │WebSocket │  │   HTTP   │  │   KCP    │    │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘    │
├──────────────────────────────────────────────────────────────┤
│                     Hotfix 層(可熱更)                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  ComponentAgent  │  HttpHandler  │  EventHandler     │   │
│  └──────────────────────────────────────────────────────┘   │
├──────────────────────────────────────────────────────────────┤
│                      Apps 層(不可熱更)                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                  │
│  │  State   │  │Component │  │ActorType │                  │
│  └──────────┘  └──────────┘  └──────────┘                  │
├──────────────────────────────────────────────────────────────┤
│                    框架層(NuGet 套件)                       │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │
│  │  Core    │  │ NetWork  │  │ DataBase │  │ Monitor  │    │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘    │
├──────────────────────────────────────────────────────────────┤
│                      資料庫層                                │
│  ┌──────────────────────────────────────────────────────────┐ │
│  │                      MongoDB                             │ │
│  └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘

快速開始

環境要求

依賴 版本要求
.NET SDK 10.0+
MongoDB 4.x+
IDE Visual Studio 2022 / JetBrains Rider / VS Code

安裝與執行

# 1. 克隆倉庫
git clone https://github.com/GameFrameX/Server_main.git
cd Server_main

# 2. 還原依賴
dotnet restore

# 3. 建置
dotnet build

# 4. 執行遊戲伺服器
dotnet run --project GameFrameX.Launcher \
    --ServerType=Game \
    --ServerId=1000 \
    --APMPort=29090

驗證部署

端點 位址 說明
健康檢查 http://localhost:29090/health 服務健康狀態
指標監控 http://localhost:29090/metrics Prometheus 指標
測試介面 http://localhost:28080/game/api/test HTTP 連通性測試

專案結構

Server_main/
├── GameFrameX.Launcher/         # 應用入口點(可執行程式)
│   ├── Program.cs               # 啟動引導:註冊狀態類型與協定訊息
│   └── StartUp/
│       └── AppStartUpGame.cs    # 遊戲伺服器啟動流程
│
├── GameFrameX.Hotfix/           # 熱更新層(業務邏輯,可執行時替換)
│   ├── Logic/
│   │   ├── Http/                # HTTP 請求處理器
│   │   │   ├── TestHttpHandler.cs
│   │   │   ├── ReloadHttpHandler.cs
│   │   │   ├── Player/          # 帳戶登入、線上查詢
│   │   │   └── Bag/             # 道具發放
│   │   ├── Player/
│   │   │   ├── Bag/             # 背包組件代理
│   │   │   ├── Login/           # 登入/登出邏輯
│   │   │   └── Pet/             # 寵物組件代理
│   │   ├── Account/             # 帳號組件代理
│   │   └── Server/              # 伺服器全域組件代理
│   └── StartUp/                 # 熱更新啟動流程
│       ├── AppStartUpHotfixGameByEntry.cs    # 載入入口
│       ├── AppStartUpHotfixGameByMain.cs     # 網路/連線管理
│       ├── AppStartUpHotfixGameByHeart.cs    # 心跳處理
│       └── AppStartUpHotfixGameByGateWay.cs  # 網關通訊
│
├── GameFrameX.Apps/             # 應用狀態層(不可熱更)
│   ├── ActorType.cs             # Actor 類型列舉定義
│   ├── Account/Login/           # 登入狀態 + 組件
│   ├── Player/
│   │   ├── Bag/                 # 背包狀態 + 組件
│   │   ├── Player/              # 玩家狀態 + 組件
│   │   └── Pet/                 # 寵物狀態 + 組件
│   ├── Server/                  # 伺服器全域狀態 + 組件
│   └── Common/
│       ├── Session/             # 工作階段管理(SessionManager)
│       ├── Event/               # 事件 ID 定義
│       └── EventData/           # 事件參數
│
├── GameFrameX.Config/           # 設定表系統(Luban 產生)
│   ├── ConfigComponent.cs       # 設定載入單例
│   ├── Tables/                  # 產生的設定表類別
│   ├── TablesItem/              # 設定資料模型
│   └── json/                    # JSON 設定資料檔案
│
├── GameFrameX.Proto/            # 網路協定定義
│   ├── Basic_10.cs              # 基礎協定(心跳等)
│   ├── Bag_100.cs               # 背包協定
│   ├── User_300.cs              # 使用者/帳號協定
│   └── BuiltIn/                 # 內建系統協定
│
├── GameFrameX.Architecture.Analyzers/        # 編譯期架構規則檢查器
│
├── Server.sln                   # Visual Studio 解決方案
├── Server.slnx                  # XML 解決方案
├── Dockerfile                   # Docker 多階段建置
├── docker-compose.yml           # Docker Compose 編排
└── LICENSE.md                   # Apache License 2.0

使用範例

核心模式:狀態-組件-代理

GameFrameX 採用三層分離的開發模式,確保業務邏輯可以在不停服的情況下熱更新。

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   State      │────▶│  Component   │◀────│ ComponentAgent│
│  (資料定義)  │     │  (組件外殼) │     │  (業務邏輯)  │
│   Apps 層    │     │   Apps 層    │     │  Hotfix 層   │
│  不可熱更    │     │  不可熱更    │     │   可熱更      │
└──────────────┘     └──────────────┘     └──────────────┘

第 1 步:定義狀態(Apps 層)

繼承 CacheState,定義持久化資料結構。框架自動處理 MongoDB 序列化。

// 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; }
}

第 2 步:建立組件(Apps 層)

繼承 StateComponent<TState>,作為狀態和邏輯的橋樑。

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

第 3 步:實作業務邏輯(Hotfix 層)

繼承 StateComponentAgent<TComponent, TState>,撰寫可熱更的業務程式碼。

// GameFrameX.Hotfix/Logic/Player/Bag/BagComponentAgent.cs
public class BagComponentAgent : StateComponentAgent<BagComponent, BagState>
{
    public async Task OnAddBagItem(INetWorkChannel netWorkChannel,
        ReqAddItem message, RespAddItem response)
    {
        // 校驗物品設定是否存在
        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(); // 自動持久化到 MongoDB
        return bagState;
    }
}

HTTP 處理器

繼承 BaseHttpHandler,使用 [HttpMessageMapping] 註冊路由。

// GameFrameX.Hotfix/Logic/Http/TestHttpHandler.cs
[HttpMessageMapping(typeof(TestHttpHandler))]
[HttpMessageResponse(typeof(HttpTestResponse))]
[Description("測試通訊介面")]
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 訊息處理器

框架提供兩種 RPC 處理器基類,自動注入 ComponentAgent:

// 玩家級別訊息(綁定特定玩家 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);
    }
}

// 全域級別訊息(綁定伺服器 Actor)
[MessageMapping(typeof(ReqHeartBeat))]
internal sealed class HeartBeatHandler
    : GlobalRpcComponentHandler<ServerComponentAgent, ReqHeartBeat, RespHeartBeat>
{
    protected override Task ActionAsync(ReqHeartBeat request, RespHeartBeat response)
    {
        return Task.CompletedTask;
    }
}

事件處理

使用 [Event] 特性綁定事件 ID,框架自動分發給對應的 ComponentAgent。

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

Agent 方法標註

使用 Roslyn 原始碼產生器自動處理 Actor 訊息佇列排程。透過特性標註控制呼叫行為:

特性 說明 適用場景
[Service] 預設模式,方法呼叫進入 Actor 訊息佇列排隊執行 所有業務方法
[ThreadSafe] 跳過訊息佇列,直接呼叫(要求方法執行緒安全) 純讀操作、無狀態計算
[Discard] 即發即棄,不等待傳回值 日誌、統計等不需要結果的場景
[TimeOut(ms)] 為訊息佇列呼叫設定逾時時間 需要逾時控制的長操作
public class ServerComponentAgent : StateComponentAgent<ServerComponent, ServerState>
{
    // 進入 Actor 訊息佇列排隊執行
    [Service]
    public virtual Task<bool> IsOnline(long roleId) { ... }

    // 跳過訊息佇列,執行緒安全直接呼叫
    [Service]
    [ThreadSafe]
    public virtual long FirstStartTime()
    {
        return State.FirstStartTime;
    }

    // 即發即棄,不阻塞呼叫方
    [Service]
    [Discard]
    public virtual ValueTask AddOnlineRole(long roleId)
    {
        OwnerComponent.OnlineSet.Add(roleId);
        return ValueTask.CompletedTask;
    }
}

設定表存取

使用 ConfigComponent 單例存取 Luban 產生的設定表:

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

// 使用 TryGet 安全查詢
if (config.TryGet(itemId, out var itemConfig))
{
    // 使用 itemConfig.Name, itemConfig.Type 等
}

資料庫操作

透過 GameDb 靜態類別進行 MongoDB CRUD 操作:

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

// 新增/更新
await GameDb.AddOrUpdateAsync(loginState);

// 列表查詢
var list = await GameDb.FindListAsync<LoginState>(m => m.Id != 0);

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

熱更新機制

熱更新系統允許在不停服的情況下替換業務邏輯。

  • Apps 層GameFrameX.Apps):包含狀態定義和組件外殼,不可熱更
  • Hotfix 層GameFrameX.Hotfix):包含所有業務邏輯,可熱更
  • Hotfix 組件輸出到 hotfix/ 目錄,執行時由 HotfixManager 載入
# 透過 HTTP 介面觸發(指定版本號)
curl "http://localhost:28080/game/api/Reload?version=1.0.1"

架構分析器

GameFrameX.Architecture.Analyzers 是 Roslyn 分析器專案,用於在編譯期強制約束 Apps/Hotfix 分層架構。它只作為 analyzer 參考到 GameFrameX.AppsGameFrameX.HotfixGameFrameX.LauncherGameFrameX.ConfigGameFrameX.Proto 和測試組件會依設計忽略。

ID 規則
GFX0001 BaseCacheState 子類別必須定義在 GameFrameX.Apps
GFX0002 StateComponent<TState> 子類別必須定義在 GameFrameX.Apps
GFX0003 BaseHttpHandler 子類別必須定義在 GameFrameX.Hotfix
GFX0004 IHotfixBridge 實作類別必須定義在 GameFrameX.Hotfix
GFX0005 IComponentAgent 實作類別必須定義在 GameFrameX.Hotfix
GFX0006 [MessageMapping] 處理器必須定義在 GameFrameX.Hotfix
GFX0007 [MessageRpcMapping] 處理器必須定義在 GameFrameX.Hotfix
GFX0008 IEventListener 實作類別必須定義在 GameFrameX.Hotfix
GFX0009 ITimerHandler 實作類別必須定義在 GameFrameX.Hotfix
GFX0010 [MessageMapping] 處理器必須標記為 sealed
GFX0011 IEventListener 實作類別必須標記為 sealed
GFX0012 [MessageMapping] 處理器型別名稱必須以 Handler 結尾。
GFX0013 IEventListener 實作類別型別名稱必須以 EventListener 結尾。
GFX0014 IComponentAgent 實作類別型別名稱必須以 ComponentAgent 結尾。

文檔與資源

設定項 說明 預設值 範例
ServerType 伺服器類型 Game
ServerId 伺服器唯一識別 1000
InnerPort TCP 內部通訊埠 29100
HttpPort HTTP 服務埠 0 28080
WsPort WebSocket 服務埠 0 29110
MetricsPort Prometheus 指標埠 0 29090
DataBaseUrl MongoDB 連線字串 mongodb://localhost:27017
DataBaseName 資料庫名稱 gameframex

[!NOTE] 上表僅列出最小啟動參數。完整配置項(網路、日誌、Actor、監控、安全等)請查閱 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 部署

docker-compose up --build
協定 說明
29090 HTTP APM 指標 / 健康檢查
29100 TCP 遊戲客戶端連線
29110 WebSocket WebSocket 連線
28080 HTTP HTTP API

訊息協定

訊息 ID 由模組 ID 位移計算:(moduleId << 16) + seqId

模組 ID 範圍 檔案 說明
系統 -10 ~ -1 Player_-10.cs, Service_-3.cs 內建系統協定
基礎 10 Basic_10.cs 心跳、伺服器就緒通知
背包 100 Bag_100.cs 物品增刪改查、使用、合成
使用者 300 User_300.cs 登入、註冊、角色列表

技術棧

元件 技術
執行時 .NET 10.0
資料庫 MongoDB
網路框架 SuperSocket
序列化 protobuf-net
設定產生 Luban
程式碼產生 Roslyn Source Generator
監控 OpenTelemetry + Prometheus
物件映射 Mapster
容器化 Docker + Docker Compose

社區與支援

貢獻指南

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

開源協議

本專案採用 Apache License 2.0 分發。詳見 LICENSE.md 檔案。