
高性能・クロスプラットフォームのゲームサーバーフレームワーク
📖 ドキュメント • 🚀 クイックスタート • 💬 QQグループ: 467608841
🌐 言語: English | 简体中文 | 繁體中文 | 日本語 | 한국어
GameFrameX Server は、C# .NET 10.0 で開発された高性能・クロスプラットフォームのゲームサーバーフレームワークです。Actor モデルを採用し、ホットアップデート機構をサポートしています。マルチプレイヤーオンラインゲーム開発向けに設計されており、Unity3D、Godot、LayaBox など多様なクライアントプラットフォームとの統合をサポートします。
設計理念: 大道至簡、シンプルイズベスト
┌─────────────────────────────────────────────────────────────────┐
│ クライアント層 │
│ 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 テストスイート
リポジトリをクローン
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/healthGameFrameX はコマンドライン引数(--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 URL | 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 をビルドHotfixManager が回収可能な AssemblyLoadContext で新 DLL をロードHotfixModule が新アセンブリ内のエージェント、ハンドラ、イベントリスナーをスキャンActorManager.ClearAgent() がキャッシュされたエージェントインスタンスをクリア# ホットアップデートのトリガー(バージョン指定)
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 | ログイン API 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)# 全テストを実行
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 サーバールート登録テスト |
あらゆる形態の貢献を歓迎します!以下の手順に従ってください:
git checkout -b feature/amazing-feature)git commit -m 'feat: 機能を追加')git push origin feature/amazing-feature)コミットメッセージは Conventional Commits 仕様に従ってください。
本プロジェクトは MIT ライセンス と Apache License 2.0 のデュアルライセンスで配布されています。詳細は LICENSE ファイルを参照してください。
このプロジェクトが役に立ったら、Star をお願いします
Made by GameFrameX Team