Files
BuYuHouDuan/docs/04-棋牌游戏模块-ChessGame.md
2026-10-12 16:22:04 +08:00

30 KiB
Raw Permalink Blame History

棋牌游戏模块(ChessGame)—— 功能与代码目录文档

本文档为 棋牌游戏模块(ChessGame) 的完整上下文说明,供其他对话 / 开发者在不阅读全部源码的情况下理解该模块。文中所有结论均以仓库 d:\BUYUHouDuanNet\BuYu 下的实际源码为准,路径均为相对该仓库根目录的相对路径。


一、平台背景与模块位置

本平台是一个捕鱼 + 棋牌游戏运营平台后端,解决方案文件为 Template0524.sln。整体技术栈:

  • 运行时 / 框架:.NET 8
  • 数据库:MongoDB(文档存储)、PostgreSQL(CAP 消息表 / 日志表)
  • 缓存:Redis
  • 消息队列:RabbitMQ(通过 DotNetCore.CAP 封装为事件总线)
  • 实时通信:SignalR(Hub,部分为 WebSocket-only)
  • 网关:Ocelot
  • 日志:NLog
  • 依赖注入:Autofac

网关(Ocelot) 监听 http://localhost:8001,按路由将请求转发到各 Host 进程:

网关前缀 目标 Host 端口
/adminapi AdminHost 5241
/api、/loginhub UserHost 5245
/customerapi、/customerHub CustomerHost 5247
/chess、/chessgamehub ChessGameHost 5242
/fishingroomhub FishRoomHost 5244
/gamehub FishGameHost 5248

本模块(棋牌游戏模块 ChessGame)的位置:

  • 入口进程:ChessGameHost(ChessGameHost/ChessGameHost.csproj)。
  • 网关前缀:/chess、/chessgamehub。
  • 实时对局通信:SignalR Hub,映射在 /chessgamehub 路由,并且仅启用 WebSockets 传输(见 ChessGameHost/Program.cs)。
  • 在 Template0524.sln 中已注册的项目:ChessGameSrc\ChessGameDomain、ChessGameSrc\ChessGameService、ChessGameHost(解决方案中存在 ChessGameSrc 解决方案文件夹)。
  • 端口说明(以实际配置为准):ChessGameHost/docker-compose.yaml 将容器内 80 映射到宿主 5242(与网关一致);ChessGameHost/Properties/launchSettings.json 本地 http 调试端口为 5290;ChessGameHost/Config/system.json 中另声明了 "urls": "http://*:8005"。三者用途不同(发布容器 / 本地调试 / 配置声明),实际生效端口取决于部署方式与启动参数。

二、模块简介

2.1 定位与职责

棋牌游戏模块负责中国象棋(真人 / 机器人)实时对局服务,核心职责:

  1. 房间的创建、加入、退出、后台踢人、房间重置与清理。
  2. 对局全生命周期:设金币 → 准备 → 开始 → 走子/操作转发 → 结束(认输 / 双方确认结束 / 断线超时 / 挂机超时)。
  3. 对局结算:按房间下注金币在胜者与败者之间进行用户资产(金币)加减,并发布资产变更通知。
  4. 通过 SignalR 向大厅(Lobby)与房间组实时推送房间状态、对局事件。
  5. 后台任务:断线/挂机超时自动判负、机器人填充空房、空房率维护、启动时重置异常房间。

房间的运行态数据存放在 Redis(通过 IRedisService 读写,见 RedisService/IRedisService.cs),并非存放于 MongoDB。

2.2 房间状态机(ChessGameRoom.state,依据代码推断)

state 含义(依据代码使用位置推断)
0 空闲 / 待开放房间(机器人服务 ChessBotService 会将 state==0 且无人的房间填充为机器人房;清理逻辑会将其重置回 0)
1 已创建 / 已有人进入,等待开始(StartGame 要求 state==1;CreateRoom / JoinGame 成功后置 1)
2 对局进行中(EndGame / 超时 / 断线均要求或针对 state==2)
3 对局结束 / 房间释放(EndGame 与 ExitRoom 均将 state 置 3)

2.3 核心业务流程(以代码为准)

① 进房 / 创建房间

  • CreateRoom(Hub)→ ChessGameService.CreateRoomAsync:
    • 校验用户存在、游戏配置(IRedisService.GetGameConfig() 的 ChessConfig)存在。
    • 使用分布式锁 lock:chess:room:{roomId}(RedisKey.DistributedLockPrefix + chess:room:{roomId},expiry=10s)串行化操作。
    • 若该用户已存在于其他房间,则从旧房间移除或清空旧房间。
    • 房间处于 state==0 或 state==3 且无人 时视为“开房/配置密码”场景,需满足 ChessConfig.CreateRoomLimit 权限(3=所有人、1=VIP、2=代理),否则返回“只有 VIP/代理才能配置密码”。
    • 否则按二/一号位(type,红黑方)加入,最多 2 人。
  • JoinGame(Hub)→ JoinGameAsync:必须携带正确密码(room.password 为空或错误均拒绝),随后入房、置 state==1。
    • 注意:CreateRoom 场景与 JoinGame 场景对密码的要求不同——JoinGameAsync 强制校验密码。

② 对局准备与开始

  • StartGame:仅房主(createUserId)可发起,人数需 ≥ 2,推送 GoldConfigRequired(要求红方配置金币)。
  • GoldConfig:仅红方(type==2)可配置,金币需 ≥ ChessConfig.MinBetGold,且不得超过红方玩家自身金币。
  • GameReady:玩家准备;两人全部准备后房间置 state==2(真正开始),推送 AllBeginTime。

③ 对局中的操作转发

  • GameOperation(gameId, type, data):校验调用者身份并刷新活跃时间;当 type==2 时视为“当前玩家获胜”,直接结束对局(另一方判负);否则把 {type,data} 广播给房间组。
  • SyncGameData(gameId, data):把数据仅转发给房间内另一个连接(对手),用于走子同步。
  • Heartbeat:刷新房间 LastActiveTime。

④ 结束对局(多种触发)

  • EndGame(gameId, winUserId)(Hub)→ ChessGameService.EndGame:
    • 在分布式锁内执行(lock:chess:room:{gameId},expiry=30s,不重试),房间置 state==3、IsGameEnded=true。
    • 计算实际下注 actualBet = min(room.gold, 败者真实金币);先扣败者(Source = RewardSource.象棋),再给胜者加币;任一失败则回滚(扣款失败回退房间状态为 2,胜者加币失败则给败者回退)。
    • 结算后发布 BackgroundOperation.NotifyUser 通知(胜方 ChangeType=1、败方 ChangeType=2)。
    • 最后清空房间(gold=0、gameType=0、robotCount=0、清空确认集合、清空 users),并对所有相关 userId 执行 UpdateUserGameType(userId, 0)。
  • RequestEndGame:双方确认制,玩家各自登记结束请求(EndGameRequests),当房间内所有玩家都确认(且人数 ≥ 2)时自动调用 EndGame;否则向对手推送 OpponentRequestEnd。
  • 断线超时:CheckTimeout(Hub 主动查询)与后台 ChessTimeoutService 周期扫描,玩家断线超过 room.TimeoutSeconds(默认 60s)判负。
  • 挂机超时:CheckRoomAfkTimeout,单方挂机超过 room.AfkTimeoutSeconds(默认 120s)判负;双方同时挂机时,先挂机的一方判负。

⑤ 退出与踢人

  • ExitRoom(Hub)按房主退出 / 对局中退出 / 普通退出分别处理,必要时重置房间。
  • KickPlayer(Hub):仅房主、非对局中、不能踢自己;被踢者收 KickedFromRoom 并回到大厅组。
  • 后台管理员踢人:由 AdminKickChessPlayerSubscriber 处理(见第七节)。

⑥ 机器人与空房维护

  • ChessBotService 定期把空闲房间填充为机器人房、并维护“空房率”(见第三节·后台服务)。

三、业务功能清单

3.1 SignalR Hub 方法(客户端 → 服务端可调用)

Hub 类:ChessGameService/ChessGameHub.cs(namespace ChessGameService),继承 Hub。大厅组常量:ChessGameHub.LobbyGroup = "chess_lobby"。

方法 说明
OnConnectedAsync() / OnDisconnectedAsync(Exception?) 连接 / 断开的生命周期处理;支持按 query 参数 userId 重连回房
CreateRoom(CreateRoomParam param) 创建 / 开房
JoinGame(gameId, pwd, userId) 凭密码加入房间
StartGame(gameId, userId) 房主开始游戏(进入金币配置环节)
GoldConfig(gameId, gold, userId) 红方配置本局下注金币
GameReady(gameId, userId) 玩家准备
EndGame(gameId, winUserId) 结束对局并结算(指定胜者)
RestartGame(gameId, userId) 对局结束后重开
RequestEndGame(gameId, userId, winUserId) 请求结束对局(双确认)
Heartbeat(gameId) 心跳,刷新活跃时间
SetPlayerAfk(gameId, userId) / CancelPlayerAfk(gameId, userId) 设置 / 取消挂机
CheckTimeout(gameId) 主动检查断线超时
ExitRoom(gameId, userId) 退出房间
KickPlayer(gameId, targetUserId) 房主踢人
GetRoomList(partition=0) 获取房间列表(最多 100,按房号分区过滤)
GetRoomState(gameId) 获取房间当前状态
SyncGameData(gameId, data) 走子/对局数据转发给对手
GameOperation(gameId, type, data) 对局操作透传;type==2 时结束对局

3.2 Hub 推送事件(服务端 → 客户端)

以下为代码中实际出现的事件名(Clients.*.SendAsync(...)):

事件名 说明
BeginGame 推送房间完整数据(进房 / 重连 / 状态刷新)
RoomStateNotice 房间状态通知
JoinRoom 加入房间成功(发给调用者)
JoinRoomNotice 有人加入房间(发给大厅)
CreateRoomNotice 房间被创建(发给大厅)
ExitRoomNotice 房间退出 / 重置(发给大厅或相关连接)
ExitRoomSuccess 退出房间成功
GameError 错误消息(发给调用者)
ReadyNotice / AllBeginTime 准备通知 / 全部准备开始
GoldConfigRequired / GoldConfigSuccess / GoldConfigRoomNotice 金币配置相关
GameEnd 对局结束(含胜者与房间数据)
RestartGameSuccess / RestartRoomNotice 重开相关
OpponentRequestEnd / EndGameRequestSent 请求结束对局相关
PlayerAfkNotice / PlayerCancelAfkNotice 挂机相关
KickedFromRoom 被踢出房间(含 gameId、userId、reason、source)
Disconnect / Reconnect 断线 / 重连通知
SyncGameData / GameOperation 对局数据转发
GetRoomList 房间列表响应

3.3 后台服务(ChessGameHost/Services/)

服务 周期 说明
ChessTimeoutService 每 10 秒 遍历所有 state==2 房间:断线超过 TimeoutSeconds 判负;随后对有挂机的房间执行 CheckRoomAfkTimeout(挂机超时判负)。判负后推送 GameEnd / ExitRoomNotice,并把相关连接移回大厅组
ChessBotService 启动延迟 10s,之后每 2 分钟 ① 启动时 CleanStaleRooms 清理空房间(state==3 或 state==1 且房主为空);② EnsureChessEmptyRoomRate 依据 MongoDB 中的 EmptyRoomRateConfig(按 GameType==中国象棋)维护空房率,必要时释放“纯机器人房”为空房;③ 从 state==0 且无人无机器人的房间中挑选候选,置为机器人房(robotCount=1、state=1、随机密码),并向大厅推送 JoinRoomNotice(单批最多 5 个)

3.4 CAP 消息订阅者(ChessGameService/Subscribers/)

订阅者 订阅主题 说明
ChessLoginSubscriber TopicKeys.登录绑定(Topic_0524_LoginBind) 处理“登录绑定”:查该用户是否正处于 state==2 未结束的对局中,若是则调用 EndGame 以对手为胜者结束并结算,随后发布 TopicKeys.登录结果通知
AdminKickChessPlayerSubscriber TopicKeys.后台踢出象棋玩家(Topic_0524_AdminKickChessPlayer) 处理后台管理员踢人:踢出后更新用户游戏状态、推送 KickedFromRoom,把连接移回大厅组并广播房间状态

四、项目结构与技术要点

4.1 各 csproj:目标框架与依赖关系

ChessGameSrc/ChessGameDomain/ChessGameDomain.csproj

  • 目标框架:net8.0(ImplicitUsings / Nullable 均开启)
  • 项目引用:Infrastructure\MongoRepository\MongoRepository.csproj
  • 说明:对局/房间实体层,无 NuGet 包直接引用(Mongo 相关特性来自 MongoRepository 项目)。

ChessGameSrc/ChessGameService/ChessGameService.csproj

  • 目标框架:net8.0(ImplicitUsings / Nullable 均开启)
  • NuGet 包:Microsoft.AspNetCore.SignalR.Core (1.2.9)、Microsoft.Extensions.Logging.Abstractions (10.0.3)
  • 项目引用:RedisService\RedisService.csproj、UserSrc\UserService\UserService.csproj、ChessGameDomain\ChessGameDomain.csproj
  • 说明:业务服务层,包含 Hub、服务接口/实现、订阅者、参数模型。

ChessGameHost/ChessGameHost.csproj

  • 目标框架:net8.0,SDK = Microsoft.NET.Sdk.Web(Web 进程入口)
  • NuGet 包:NLog.Web.AspNetCore (6.1.2)、Autofac (8.3.0)、Autofac.Extensions.DependencyInjection (10.0.0)、AutoMapper (14.0.0)、DotNetCore.CAP (8.3.4)、DotNetCore.CAP.Dashboard (8.3.4)、DotNetCore.CAP.PostgreSql (8.3.4)、DotNetCore.CAP.RabbitMQ (8.3.4)、Microsoft.AspNetCore.SignalR.Protocols.MessagePack (8.0.17)
  • 项目引用:ChessGameSrc\ChessGameService、CommonService、Infrastructure\CommonInfrastructure、Infrastructure\SharpAbp.Infrastructure.Api
  • 内容文件:链接引用仓库根 nlog.config;docker-compose.yaml、Dockerfile 设为始终复制(注意:Dockerfile 被 csproj 引用,但当前 ChessGameHost 目录下未发现该文件)。

依赖方向: ChessGameHost → ChessGameService → { ChessGameDomain、RedisService、UserService } → ChessGameDomain → MongoRepository。

4.2 进程入口要点(ChessGameHost/Program.cs)

  • 设置环境变量 SERVICE_NAME、INSTANCE_ID,并注册单例 AppInstanceId。
  • 日志:builder.Logging.AddNLog() + builder.Host.UseNLog()(NLog 6.x)。
  • 配置:加载 Config/system.json;绑定 MongoDbSettings 并注册为单例 IMongoDbSettings。
  • SignalR 配置(AddSignalR(...).AddJsonProtocol()):
    • MaximumReceiveMessageSize = 64 * 1024(64KB)
    • StreamBufferCapacity = 512
    • ClientTimeoutInterval = 70s、KeepAliveInterval = 15s
    • 全局 Hub 过滤器:MovementFilter、HubExceptionFilter
  • 其他:FormOptions.MultipartBodyLengthLimit = 16MB、AddMemoryCache()、JSON 转换器 DatetimeJsonConverter。
  • DI:IHubSend<ChessGameHub> → HubSend<ChessGameHub>、IRequestApi → RequestApi、AddAutoMapper(typeof(AutoMapperConfig))。
  • 后台服务:AddHostedService<ChessTimeoutService>()、AddHostedService<ChessBotService>()。
  • 健康检查:AddHealthChecks().AddCheck("self", ...)。
  • CORS 策略 "Cors":SetIsOriginAllowed(_ => true)、允许任意 Header / Method、AllowCredentials()。
  • AddCustomJwt(builder.Configuration)、AddRedisCacheSingleton(builder.Configuration)。
  • Autofac:builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) 并注册 AutofacModule。
  • CAP:builder.Services.AddCap(builder.Configuration)(见 Extension/CapExtension.cs)。
  • 启动自愈逻辑(app.Run() 前):redis.ClearAllLoginUserIds();遍历所有象棋房间,收集受影响 userId;对 state != 2 的房间执行 ExitRoom 释放,对 state == 2 的房间把用户标记为 IsLeave=true、DisconnectTime=now、Cid="" 并写回;最后对所有受影响用户 UpdateUserGameType(userId, 0)。整段包在 try/catch 中(失败不影响启动)。
  • 中间件管线顺序:UseApiLogging() → UseRouting() → UseGlobalExceptionHandler() → UseStaticFiles() → UseCors("Cors") → UseAuthentication() → UseAuthorization()。
  • 终结点:MapHub<ChessGameHub>("/chessgamehub", options => options.Transports = WebSockets)、MapControllers()、MapHealthChecks("/health", ...)(返回 JSON 健康报告)。

4.3 SignalR / CAP / Redis 配置

  • SignalR:单个 Hub ChessGameHub,映射路由 /chessgamehub,仅 WebSockets;启用 JSON 协议;消息封包协议包 MessagePack(8.0.17)已被引用。
  • CAP(ChessGameHost/Extension/CapExtension.cs):
    • UseDashboard()(CAP 面板)。
    • UseRabbitMQ:Host/UserName/Password/VirtualHost 取自配置节 CapConfig,交换机名 cap.exchange。
    • UsePostgreSql:连接串取自 CapConfig:PGLogHost,Schema=public。
    • SucceedMessageExpiredAfter = 7*24*3600、FailedRetryCount = 5、FailedRetryInterval = 10、FailedThresholdCallback。
    • 显式注册订阅者:ChessLoginSubscriber、AdminKickChessPlayerSubscriber(AddTransient<ICapSubscribe, ...>)。
  • Redis:AddRedisCacheSingleton(builder.Configuration);读取配置节 RedisConfig。房间键定义在 Infrastructure/Common/Redis/RedisKey.cs:ChessRoomList(...chess:room:list)、ChessRoomKey(...chess:room:{0}),分布式锁前缀 DistributedLockPrefix(...lock:)。

4.4 DI 注册位置

  • Autofac 模块 ChessGameHost/Middleware/AutofacModule.cs:
    • 注册泛型仓储/服务:MongoBaseRepository<> → IMongoBaseRepository<>、MongoBaseService<> → IMongoBaseService<>(InstancePerLifetimeScope)。
    • 注册 RedisService.RedisService → IRedisService。
    • 按程序集扫描注册:CommonService(ApiLogService 所在程序集)、ChessGameService、UserService 中所有以 Service 结尾的类型为“实现其接口”。
  • ChessGameHub 由 SignalR 框架实例化(不在 Autofac 模块中显式注册),其构造函数依赖 ILogger<ChessGameHub>、IChessGameService、IRedisService。

4.5 docker-compose 端口

ChessGameHost/docker-compose.yaml:

name: webapi
services:
  0524chess:
    image: 0524chess
    container_name: '0524chess'
    restart: always
    ports:
      - '5242:80'

即宿主 5242 → 容器 80。

4.6 配置文件(ChessGameHost/)

  • appsettings.json:仅 Logging(Default=Error、Microsoft.AspNetCore=Error)与 AllowedHosts=*。
  • appsettings.Development.json:仅 Logging。
  • Config/system.json(由 Program.cs 额外加载):包含 urls(http://*:8005)、JwtConfig、ConnectionStrings:PgSqlConnection、CapConfig(RabbitMQ + PG 日志库)、RedisConfig(Host localhost、Port 6378、Database 1)、MongoDbSettings(mongodb://localhost:27018)、WXConfig。

五、代码目录说明(完整目录树)

ChessGameSrc/                                  # 棋牌游戏业务源码解决方案文件夹
├── ChessGameDomain/                            # 领域层:对局/房间实体(net8.0)
│   ├── ChessGameDomain.csproj                  # 项目文件,引用 MongoRepository
│   ├── ChessGameRoom.cs                        # 房间实体(BsonCollection "game_room",库 data_0524_chess)
│   └── RedisChessGameUser.cs                   # 房间内玩家实体(存放在房间的 users 列表)
└── ChessGameService/                           # 业务服务层(net8.0)
    ├── ChessGameService.csproj                 # 项目文件,引用 RedisService / UserService / ChessGameDomain
    ├── IChessGameService.cs                    # 对局业务接口(房间/对局/结算/超时/踢人)
    ├── ChessGameService.cs                     # 对局业务核心实现(房间状态机 + 结算逻辑)
    ├── ChessGameHub.cs                         # SignalR Hub,映射路由 /chessgamehub
    ├── Param/
    │   └── CreateRoomParam.cs                  # 创建房间入参(roomId/userId/gameType/password/gold)
    └── Subscribers/
        ├── ChessLoginSubscriber.cs             # 订阅“登录绑定”,结束旧对局并回发登录结果
        └── AdminKickChessPlayerSubscriber.cs   # 订阅“后台踢出象棋玩家”,执行管理员踢人

ChessGameHost/                                  # 棋牌游戏进程入口(Web 主机,net8.0)
├── ChessGameHost.csproj                        # 项目文件,含 NLog/Autofac/CAP/SignalR MessagePack 等包
├── Program.cs                                  # 进程入口:DI/中间件/Hub 映射/启动自愈逻辑
├── appsettings.json                            # 基础日志配置
├── appsettings.Development.json                # 开发环境日志配置
├── docker-compose.yaml                         # 容器编排,端口 5242:80
├── .dockerignore                               # 容器构建忽略清单
├── Config/
│   └── system.json                             # 业务配置:JWT/PG/CAP(RabbitMQ)/Redis/Mongo/微信
├── Extension/
│   └── CapExtension.cs                         # CAP 配置扩展(RabbitMQ+PG+Dashboard+订阅者注册)
├── Middleware/
│   ├── AutofacModule.cs                        # Autofac 依赖注入模块(仓储/Redis/服务扫描)
│   ├── ApiLoggingMiddleware.cs                 # /api 请求响应日志中间件(含脱敏)
│   ├── HubExceptionFilter.cs                   # SignalR Hub 全局异常/接口日志过滤器
│   └── MovementFilter.cs                       # SignalR Hub 过滤器(内含预留的 RateLimiter 令牌桶)
├── Properties/
│   └── launchSettings.json                     # 本地调试配置(http 端口 5290 / IIS Express 21784)
└── Services/
    ├── ChessTimeoutService.cs                  # 后台服务:断线/挂机超时判负(每 10s)
    └── ChessBotService.cs                      # 后台服务:机器人填充/空房率维护/启动清理(每 2min)

六、关键文件索引

文件相对路径 职责
ChessGameSrc/ChessGameDomain/ChessGameRoom.cs 房间实体,定义 users、RoomId、gameType、password、createUserId、state、gold、robotCount、EndGameRequests、TimeoutSeconds、AfkTimeoutSeconds、IsGameEnded 等字段及默认值
ChessGameSrc/ChessGameDomain/RedisChessGameUser.cs 房间内玩家实体(Cid、userId、userName、userAvatar、type、IsLeave、IsReady、Gold、DisconnectTime、IsAfk、AfkTime)
ChessGameSrc/ChessGameService/IChessGameService.cs 对局业务接口,声明创建/加入/就绪/结束/重启/超时/踢人/结算等全部方法
ChessGameSrc/ChessGameService/ChessGameService.cs 对局业务核心实现:房间状态机、金币结算(EndGame)、超时判定、权限校验等
ChessGameSrc/ChessGameService/ChessGameHub.cs SignalR Hub:映射 /chessgamehub,处理连接/断开、进房、开始、准备、走子转发、结束、踢人等,并定义大厅组 chess_lobby
ChessGameSrc/ChessGameService/Param/CreateRoomParam.cs 创建房间参数模型
ChessGameSrc/ChessGameService/Subscribers/ChessLoginSubscriber.cs 订阅 Topic_0524_LoginBind,登录绑定触发旧对局结算,回发 Topic_0524_LoginBindResult
ChessGameSrc/ChessGameService/Subscribers/AdminKickChessPlayerSubscriber.cs 订阅 Topic_0524_AdminKickChessPlayer,后台踢人并广播
ChessGameHost/Program.cs 进程入口:服务注册、SignalR/CAP/Redis 装配、中间件与终结点、启动房间自愈
ChessGameHost/Extension/CapExtension.cs CAP 事件总线配置与订阅者注册
ChessGameHost/Middleware/AutofacModule.cs DI 容器装配(仓储、Redis、各 Service 程序集扫描)
ChessGameHost/Middleware/ApiLoggingMiddleware.cs /api 请求日志中间件
ChessGameHost/Middleware/HubExceptionFilter.cs Hub 调用日志与异常捕获(SyncGameData 除外)
ChessGameHost/Middleware/MovementFilter.cs Hub 过滤器(预留限流 RateLimiter)
ChessGameHost/Services/ChessTimeoutService.cs 断线/挂机超时后台判负服务
ChessGameHost/Services/ChessBotService.cs 机器人填充与空房率维护后台服务
ChessGameHost/Config/system.json 业务配置(JWT/PG/CAP/Redis/MongoDB/微信)
ChessGameHost/docker-compose.yaml 容器端口映射 5242:80
ChessGameHost/Properties/launchSettings.json 本地调试端口

七、与其他模块的交互

7.1 CAP / RabbitMQ 消息主题

主题常量定义在 CommonDomain/TopicKeys.cs,消息体定义在 CommonDomain/CapMessageModels.cs、CommonDomain/AdminKickChessPlayerMessage.cs。本模块相关的发布/订阅如下:

方向 主题(常量 → 实际值) 消息体 交互方
订阅 TopicKeys.登录绑定 → Topic_0524_LoginBind LoginBindMessage { UserId, OperationId } 发布方:UserHost(UserSrc/UserService/Hubs/LoginHub.cs);本模块 ChessLoginSubscriber 消费
发布 TopicKeys.登录结果通知 → Topic_0524_LoginBindResult LoginBindResultMessage { UserId, RoomId, OperationId, Success, Error } 消费方:UserHost(LoginResultSubscriber → LoginSettlementWaiter);本模块在结算后发布
订阅 TopicKeys.后台踢出象棋玩家 → Topic_0524_AdminKickChessPlayer AdminKickChessPlayerMessage { RoomId, UserId, Reason } 发布方:AdminHost(AdminSrc/AdminApi/GameConfigs/AdminRoomController.cs);本模块 AdminKickChessPlayerSubscriber 消费
发布 "BackgroundOperation.NotifyUser"(字符串字面量,非常量) BackgroundOperationNotifyMessage 消费方:UserHost(AdminNotifySubscriber)与 FishGame(BackgroundAssetSubscriber);本模块在 EndGame 结算后发布(胜方 ChangeType=1、败方 ChangeType=2,CurrencyType=1,Source="象棋对局胜利"/"象棋对局失败")

注意:登录绑定 主题除本模块的 ChessLoginSubscriber 外,FishGameSrc/FishGameService/Subscribers/LoginBindSubscriber.cs 也以相同主题订阅(处理捕鱼房旧房间)。二者是各自独立的订阅者。

7.2 登录绑定(与 User 模块)完整流程

  1. 用户在 UserHost 登录(LoginHub),若检测到存在待处理的捕鱼房/象棋房(IRedisService.GetPendingChessRoomId(userId)),生成 OperationId,注册 LoginSettlementWaiter,并通过 _capPublisher.PublishAsync(TopicKeys.登录绑定, new LoginBindMessage{ UserId, OperationId }) 发布“登录绑定”事件,然后等待结果(超时 15s)。
  2. 本模块 ChessLoginSubscriber.HandleLoginBind 消费该事件:遍历所有象棋房间,若发现该用户处于 state==2 且未结束的对局中,则以对手为胜者调用 ChessGameService.EndGame 结算,随后发布 TopicKeys.登录结果通知(成功 Success=true,异常 Success=false 并带 Error)。
  3. UserHost LoginResultSubscriber 消费“登录结果通知”,通过 LoginSettlementWaiter 唤醒等待中的登录流程;随后写入新的登录 Cid(SetRedisUserCId)。
  4. 另有 LoginHub.DismissPendingRoom 会发布 TopicKeys.拒绝回房(Topic_0524_DismissPendingRoom,消息体同为 LoginBindMessage)。

7.3 Redis

  • 本模块对局房间的运行时数据全部存放于 Redis,通过 IRedisService 读写(SetChessRoom / GetChessRoom / GetAllChessRooms / RemoveChessRoom 等)。相关键:ChessRoomList(...chess:room:list)、ChessRoomKey(...chess:room:{0})。
  • 使用分布式锁:键前缀 RedisKey.DistributedLockPrefix(...lock:)+ chess:room:{roomId},串行化房间的创建、准备、结束等操作。
  • 配置节 RedisConfig(localhost:6378,Database 1)。
  • 启动时调用 ClearAllLoginUserIds() 清理登录用户映射。

7.4 MongoDB

  • 房间实体 ChessGameRoom 标注了 [BsonCollection("game_room", ServiceDatabases.Chess)],其中 ServiceDatabases.Chess = "data_0524_chess"(见 Infrastructure/MongoRepository/Config/MongoDbSettings.cs)。但本模块代码实际通过 Redis 存取房间运行态,未在本模块中发现向该 Mongo 集合写房间的逻辑。
  • ChessBotService 通过 IMongoBaseRepository<EmptyRoomRateConfig> 读取空房率配置;EmptyRoomRateConfig 标注在集合 empty_room_rate_config、库 data_0524(见 CommonDomain/EmptyRoomRateConfig.cs),按 GameType == 中国象棋(GameTypeEnum.中国象棋 = 3)过滤。
  • 对局日志:HubExceptionFilter / ApiLoggingMiddleware 通过 IApiLogService 写入接口日志(Mongo 仓储)。

7.5 HTTP 调用

Program.cs 注册了 IRequestApi → RequestApi(Common.Request)单例,作为通用 HTTP 请求封装;在本模块已阅读的对局代码中未见直接调用。

7.6 共享实体 / 项目引用

  • ChessGameService 引用 RedisService、UserService、ChessGameDomain;ChessGameHost 引用 ChessGameService、CommonService、CommonInfrastructure、SharpAbp.Infrastructure.Api;ChessGameDomain 引用 MongoRepository。
  • 与 User 模块的耦合点:ChessGameService 通过 IUserService(UserSrc/UserService)执行 GetUser / UpdateUser / UpdateAssets;UpdateUserGameType 写入用户 Static.CurrentGameType 与 Static.RoomNumber(游戏状态标记);UpdateAssets 使用 Source = RewardSource.象棋、UserAssetChangeTypeEnum.增加/减少 完成金币加减。
  • 共享领域类型:CommonDomain(TopicKeys、LoginBindMessage、LoginBindResultMessage、AdminKickChessPlayerMessage、BackgroundOperationNotifyMessage、EmptyRoomRateConfig、GameTypeEnum 等)、Common.Redis(RedisKey)、CommonDomain.BaseModel.GameBaseConfig(ChessConfig:CreateRoomLimit / MinBetGold / BetGoldLimits / CreateRoomVipLevels)。

7.7 与 Admin 模块的交互

  • AdminHost 的 AdminRoomController(AdminSrc/AdminApi/GameConfigs/AdminRoomController.cs)在管理员执行“踢出象棋玩家”时发布 TopicKeys.后台踢出象棋玩家,由本模块 AdminKickChessPlayerSubscriber 消费并执行踢人 + 通知。
  • 象棋游戏配置(ChessConfig:开房权限、最小下注等)由 Admin 侧维护,本模块通过 IRedisService.GetGameConfig() 读取并据此校验开房权限与金币下限。