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