Files
BuYuHouDuan/docs/05-捕鱼游戏模块-FishGame.md
2026-10-12 16:22:04 +08:00

46 KiB
Raw Permalink Blame History

捕鱼游戏模块(FishGame)—— 功能与代码目录文档

本文档为「捕鱼游戏模块(FishGame)」的完整上下文说明,供其他对话/开发者在不阅读源码的情况下理解该模块的定位、职责、核心业务流程、项目结构、代码目录与模块间交互。文档内容全部基于对真实源代码的通读整理,未读到的内容不作臆测。


一、平台背景与模块位置

1.1 平台总览

本平台是一套「捕鱼 + 棋牌」游戏运营平台后端,解决方案文件为 Template0524.sln(位于仓库根目录 d:\BUYUHouDuanNet\BuYu)。

技术栈(依据各项目 .csproj 与配置核对):

  • 运行时/框架:.NET 8(net8.0,Microsoft.NET.Sdk.Web / Microsoft.NET.Sdk)
  • 数据存储:MongoDB(MongoRepository / MongoDB.Driver,[BsonCollection(..., "data_0524")])
  • 缓存:Redis(StackExchange.Redis、RedisService、RedisHelper)
  • 消息队列:RabbitMQ,通过 DotNetCore.CAP(DotNetCore.CAP + .RabbitMQ + .PostgreSql + .Dashboard)封装发布/订阅
  • 实时通信:SignalR(Microsoft.AspNetCore.SignalR,JSON 协议 + MessagePack 协议包引用)
  • 网关:Ocelot(Gateway\ocelot.json,BaseUrl http://localhost:8001)
  • 日志:NLog(NLog.Web.AspNetCore + 根目录 nlog.config)
  • DI:Autofac(Autofac + Autofac.Extensions.DependencyInjection)
  • 对象映射:AutoMapper

1.2 网关路由(来自 Gateway\ocelot.json)

网关全局 BaseUrl:http://localhost:8001。各上游路径映射到的下游服务与端口如下:

上游路径(网关) 下游路径模板 下游端口 对应服务
/adminapi/{everything} /adminapi/{everything} 5241 AdminHost
/api/{everything} /api/{everything} 5245 UserHost
/loginhub/{everything} /loginhub/{everything} 5245 UserHost
/customerapi/{everything} /customerapi/{everything} 5247 CustomerHost
/customerHub/{everything} /customerHub/{everything} 5247 CustomerHost
/chess/{everything} /chess/{everything} 5242 ChessGameHost
/chessgamehub/{everything} /chessgamehub/{everything} 5242 ChessGameHost
/fishingroomhub/{everything} /fishingroomhub/{everything} 5244 FishRoomHost(本模块·房间层)
/gamehub/{everything} /fishinghub/{everything} 5248 FishGameHost(本模块·对局层)

注意:ocelot 中捕鱼「对局层」的上游是 /gamehub,下游实际转发到 FishGameHost 的 /fishinghub(端口 5248)。这是本模块一个容易混淆的点。

1.3 本模块两个进程入口

本模块由两个独立进程(微服务)构成:

  • 房间层:FishGameSrc\FishRoomHost —— 监听端口 5244,SignalR Hub 路径 /fishingroomhub(网关上游同名),负责大厅房间列表、房间初始化、房间分组广播等。
  • 对局层:FishGameSrc\FishGameHost —— 网关侧端口 5248,SignalR Hub 路径 /fishinghub(网关上游为 /gamehub),负责进房、对局(开炮/击杀)、出鱼、结算、掉线重连等核心玩法逻辑。

两个进程各自引用一个类库:

  • FishGameSrc\FishGameService(被 FishGameHost 引用,承载对局层业务逻辑)
  • FishRoomService(位于仓库根目录,被 FishRoomHost 引用,承载房间层业务逻辑)

二、模块简介

2.1 定位与职责

捕鱼游戏模块是整个运营平台的「捕鱼玩法」业务域,划分为 房间层 与 对局层 两层职责:

  • 房间层(FishRoomHost + FishRoomService)

    • 维护「大区/分区 → 房间列表」,按后台下发的 GameConfig(房间配置)批量生成房间,并结合「空房率配置(EmptyRoomRateConfig)」与「机器人配置(BotConfig)」决定每个房间预置的机器人数量。
    • 玩家在大厅请求房间列表时,将其连接加入一个「分区 SignalR 分组」,并单独推送房间列表。
    • 订阅「房间变化」消息,向对应分区分组广播房间状态变化;订阅「用户资产同步前端」消息,向玩家推送资产变更。
  • 对局层(FishGameHost + FishGameService)

    • 玩家从大厅进入某个房间 → 连接到对局层 Hub(/fishinghub)→ 绑定用户 → 加入房间(占座、生成玩家对象、推送房间信息与活跃鱼)→ 对局(开炮、击杀、道具、鱼雷、炮倍切换、挂机)→ 离房/掉线结算。
    • 由后台服务 FishSpawnService 负责每个房间的「出鱼」(按概率配置按类型/航线定时刷鱼)、活跃鱼快照、出鱼权租约、命中校验与击杀标记;RobotKillAnnounceService 负责按配置定时伪造「机器人爆金击杀」全局公告。

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

  1. 服务启动初始化房间(房间层)

    • FishRoomHost\Program.cs 启动时,若 IRedisService.GetGameRoomAllList() 为空,则调用 IFishingRoomService.InitRoom() 初始化房间。房间初始化失败会记录日志并抛出(throw)。
  2. 大厅 → 房间列表(房间层)

    • 客户端连接 /fishingroomhub,调用 Hub 方法 GetRoomList(userId, gameType, roomLevel, roomPartition)。
    • FishingRoomService.GetRoomList 计算分区字符串 partition = $"{(int)gameType}{roomLevel}{roomPartition}";写入/更新 RedisUserCid(含 PartitionId、FishRoomCId、CId);把当前连接加入该分区的 SignalR 分组;读取该分区房间列表,若为空则即时 InitRoom(...) 生成;最后通过 FishingRoomSendService.GetRoomListResult 单独回推 GetRoomListResult(按 RoomNumber 排序)。
    • 另有 GetRoomInfo(roomId) 直接从 Redis 读取单个房间回推 GetRoomInfoResult。
  3. 房间初始化(房间层,InitRoom)

    • 依据 GameConfig.RoomConfigs(可用 gameType/roomLevel 过滤)逐条房间配置,遍历 RoomPartitionNum × RoomCount 生成 RedisGameRoom。
    • 读取该 GameType/RoomLevel 的 EmptyRoomRateConfig(空房率);结合 GameConfig.BotConfig.Enabled:机器人关闭时空房率为 100%(无机器人房间);否则按 100 - EmptyRoomRate 的比例随机挑选要预置机器人的房间,RobotCount = Random(1, MaxPlayerCount)。
    • 每生成一个房间前先 RemoveGameRoom(partition)(清除旧数据)再重建;RoomId = $"{(int)GameType}{RoomLevel}{RoomPartition}{c:00}"。
    • 房间上限:星际迷航/中国象棋 为 2 人,其余为 4 人(MaxPlayerCount)。
    • RoomBotFactory.FixedBotSeats 当前为空数组,故 FixedBotSeatsEnabled == false,固定座位机器人逻辑(CreateFixedSeatBots)当前不会生效。
    • 最后逐个 SetGameRoom 写回 Redis。
  4. 进房(对局层,FishingGameService.JoinRoom)

    • 若玩家此前在其它房间,先 SettleGoldAsync 结算旧房间金币。
    • 从 Redis 取房间;若房间不存在则以默认「新手渔场(风雷之渊/1)」房间创建兜底。
    • 已有玩家(重连/重复加入):刷新座位 CId、重置 State、必要时接管房主,推送 RoomInfo、OnPlayerInfo、SendRoomChange 后返回。
    • 新玩家:校验座位(固定座位、手动选座权限 SeatSelectLimit:3=全部可手选,1=VIP,2=代理),校验 RoomGoldLimit 金币门槛;构建 RedisGamePlayer(金币、钻石、炮台/翅膀/战神、初始炮倍、BeginCoin、PlayerFactor 等)加入房间;CurrentOnlinePlayerCount++、加入房间分组、设置房主。
    • 依据 BotConfig 决定是否创建机器人(CreateRoomBots)或移除机器人;随后推送 RoomInfo(含活跃鱼)、RoomJoinNotice、OnSeatChange(join)、OnPlayerInfo,并 SendRoomChange(CAP 发布「房间变化」)。
  5. 对局中(对局层)

    • 开炮 FireCannon:校验签名与时间窗、玩家身份、金币、扣费、生成子弹 Id 存入 BulletTracker、广播 RoomFireNotice、累加消耗进度与「开炮任务」进度。
    • 击杀 KillFish:校验签名/子弹/鱼命中(FishSpawnService.ValidateFishHit);按玩家因子(PlayerFactor)、系统因子、鱼 KillWeight 加权随机判定是否击杀;击杀后计算爆金(CalcSkillGold,支持 Boss 轮盘/扑克/飞盘/全屏/范围/概率/星际巡航/烈焰风暴/炸弹/机械蝎/神龙等玩法)、掉落、经验、任务进度,并处理补偿/罚款配额;广播 RoomKillNotice;超阈值爆金触发全局击杀公告(CAP 发布「全局击杀公告」+ Redis 频道广播)。
    • 道具/鱼雷:UseProp(消耗钻石或背包道具,40003 触发冻结鱼 FishFrozen,40004 触发狂暴任务)、UseTorpedo(按权重抽奖加金币)。
    • 炮倍/挂机/信息:ChangeGunMultiple、SetPlayerAfk/CancelPlayerAfk、GetPlayerInfo。
    • 出鱼:FishSpawnService 以 1 秒 Tick 驱动机器人房间出鱼逻辑,并通过 Redis 租约(fish:spawn:owner:{roomId})保证同一房间只有一台实例出鱼,快照写 fish:spawn:snapshot:{roomId} 供无租约实例读取。
  6. 离房 / 掉线 / 结算(对局层)

    • 主动离房 LeaveRoom:在分布式锁 lock:fish:gold:{roomId}:{userId} 下,先「标记离房(State=2)」,再在满足条件时执行 LeaveRoomInternal(累加在线时长、结算钓鱼进度与 GameCoinsSettlement、清理运行时数据、移除玩家、房主转移、NormalizeRoomPlayerCounts、无人时清空并 UnregisterRoom、广播 OnSeatChange(leave)/RoomLeaveNotice、SendRoomChange)。
    • 掉线 HandleDisconnect:玩家 State 置 1,房主转移;启动 60 秒延迟任务;超时后 OnDisconnectTimeoutInternal 结算并清理房间。
    • 重连 Reconnect / JoinRoom:恢复连接、取消待掉线定时器、恢复座位与房主、补发活跃鱼同步。
  7. 结算(结算链)

    • TryFlushFishingSettlement → GameCoinsSettlement(记录本局金币变化),TryFlushFishingProgress 结算经验(UpdateAssets)与消耗记录(RecordFishingConsume),FlushFishingTaskProgress 发布各「任务完成」事件。

三、业务功能清单

3.1 房间层(FishRoomHost / FishRoomService)

SignalR Hub:FishRoomService\Hubs\FishRoomHub.cs(挂载于 /fishingroomhub)

类型 名称 说明
Hub 方法 OnConnectedAsync / OnDisconnectedAsync 仅透传基类实现
Hub 方法 GetRoomList(userId, gameType, roomLevel, roomPartition) 大厅请求房间列表(含分组加入与即时初始化)
Hub 方法 GetRoomInfo(roomId) 读取单房间并回推 GetRoomInfoResult
服务端推送 GetRoomListResult 房间列表结果(GameRoomReponse 列表)
服务端推送 GetRoomInfoResult 单房间信息
服务端推送 RoomChange 房间变化广播(向分区分组)
服务端推送 AssetUpdated 用户资产变更推送

业务服务

接口/类 职责
IFishingRoomService / FishingRoomService GetRoomList(大厅房间列表)、InitRoom(按配置初始化房间)
IFishingRoomSendService / FishingRoomSendService GetRoomListResult(回推列表)、RoomChange(向分区分组广播)
IRoomMQService / RoomMQService(实现 ICapSubscribe) 订阅「房间变化」与「用户资产同步前端」

消息订阅者(CAP)

订阅方法 主题(TopicKeys) 行为
RoomMQService.RoomChange 房间变化 = Topic_0524_RoomChage 调用 FishingRoomSendService.RoomChange,向房间分区分组广播 RoomChange
RoomMQService.UserAssetSync 用户资产同步前端 = Topic_0524_UserAssetSyncFrontend 按 RedisUserCid(FishRoomCId/CId)定位连接,推送 AssetUpdated

HTTP 控制器:无(房间层仅 Hub + MQ)。

3.2 对局层(FishGameHost / FishGameService)

SignalR Hub:FishGameService\Hubs\FishGameHub.cs(挂载于 /fishinghub)

类型 名称 说明
Hub 方法 OnConnectedAsync 建立连接(异常记录日志)
Hub 方法 OnDisconnectedAsync 断线处理(调用 HandleDisconnect)
Hub 方法 Reconnect(userId) 重连恢复(座位、房主、活跃鱼同步)
Hub 方法 JoinRoom(roomId, userId, posituin) 加入房间
Hub 方法 GetRoomInfo(roomId) 读取房间并回推 GetRoomInfoResult(需连接在房)
Hub 方法 SyncGameData(roomId, data) 房间内同步自定义数据
Hub 方法 UseProp(roomId, userId, propNumber, diamond) 使用道具,返回剩余数量
Hub 方法 UseTorpedo(roomId, userId, propNumber) 使用鱼雷,返回金币
Hub 方法 FireCannon(roomId, userId, gold, count, timestamp, sign, extra) 开炮,返回投递的子弹 Id 列表与金币
Hub 方法 KillFish(roomId, userId, fishNumber, fihsId, gold, timespan, bulletId, timestamp, sign) 击杀鱼,返回当前金币
Hub 方法 LeaveRoom(roomId, userId) 主动离房
Hub 方法 ChangeGunMultiple(roomId, userId, multiple) 切换炮倍
Hub 方法 GetPlayerInfo(roomId, userId) 请求玩家信息
Hub 方法 SetPlayerAfk / CancelPlayerAfk 挂机 / 取消挂机
Hub 方法 BotFireCannon / BotKillFish 机器人开炮 / 击杀(返回子弹 Id / 无返回)
服务端推送 RoomInfo 房间信息(含活跃鱼 activeFishes)
服务端推送 OnFishSpawn 出鱼/首屏鱼同步(type = init/spawn/sync)
服务端推送 RoomKillNotice 房间内击杀公告(含倍数、掉落、玩法结果 param)
服务端推送 RoomFireNotice 开炮广播
服务端推送 RoomJoinNotice / RoomLeaveNotice / BotLeaveRoomNotice 加入/离开/机器人离开
服务端推送 RoomDisconnectNotice / HostDisconnect 断线通知 / 房主断线
服务端推送 ChangeControllerUser 房主变更
服务端推送 OnSeatChange 座位变化(join/leave)
服务端推送 OnPlayerInfo 本玩家信息(金币、钻石、炮倍、炮台、翅膀、座位等)
服务端推送 SyncPlayerGold / SendPlayerInfoResult 金币同步 / 玩家信息结果
服务端推送 ChangeGunMultipleNotice / UsePropNotice / TorpedoResultNotice 炮倍/道具/鱼雷结果
服务端推送 PlayerAfkNotice / PlayerCancelAfkNotice 挂机状态
服务端推送 Exception / BindSuccess / KickToMainPage 错误 / 绑定成功 / 踢回主页
服务端推送 AssetUpdated 资产变更(道具消耗等)
服务端推送 FishFrozen / SummonCardFishNotice 冻结鱼 / 召唤卡出鱼
全局推送 KillNotice 经 Redis 频道 fishgame:global 广播的全服击杀公告

HTTP 控制器(FishGameHost\Controllers)

控制器 路由 方法 说明
TimeController fishapi/Time/GetDateTime GET 返回服务端时间/时间戳/时区/容器名(供客户端校时)
RoomController api/Room/QuickJoin GET 按 gameType/level 从未满房间随机快速匹配,返回 RoomId 与 WebSocket 地址
RoomController api/Room/Assign GET 按 roomId 返回求 WebSocket 地址(读取配置 GameServerInstances)
PlayerController api/Player/login POST 演示用登录:生成 JWT(uid 倒序 + uname),返回固定玩家数据

后台服务

服务 基类 职责
FishSpawnService BackgroundService(同时注册为 IHostedService) 房间出鱼主循环:租约、刷鱼、活跃鱼快照、命中/击杀校验、系统因子同步、冻结延时、临时/召唤卡出鱼
RobotKillAnnounceService BackgroundService 按 RobotKillConfig 定时(最小 30 秒)伪造机器人爆金击杀并发布「全局击杀公告」;仅 INSTANCE_ID 为 1 或 default 的实例运行
GlobalBroadcastSubscriber(FishGameHost\Services) BackgroundService 订阅 Redis 频道 fishgame:global,按 Target=All 或 Room 通过 Hub 广播事件

消息订阅者(CAP)

订阅方法 主题(TopicKeys) 行为
PlayerFactorSubscriber.HandlePlayerFactorChanged 因子变更 = Topic_0524_PlayerFactorChanged 清理本地玩家因子缓存,并把最新因子同步到 Redis 房间与玩家
PlayerFactorSubscriber.HandleConfigChanged 配置变更 = Topic_0524_ConfigChanged 清空配置缓存、失效出鱼配置、重载所有房间配置
LoginBindSubscriber.HandleLoginBind 登录绑定 = Topic_0524_LoginBind 结算并清理玩家在房状态,回发「登录结果通知」
LoginBindSubscriber.HandleDismissPendingRoom 拒绝回房 = Topic_0524_DismissPendingRoom 强制执行 CleanupRoomAsync(userId, force: true)
BackgroundAssetSubscriber.HandleNotify BackgroundOperation.NotifyUser 后台加减金币(仅 CurrencyType==1),分布式锁下更新房间内玩家金币并 SyncPlayerGold
TempSpawnFishSubscriber.HandleTempSpawnFish 临时强制出鱼 = Topic_0524_TempSpawnFish 调用 FishSpawnService.SpawnTemporaryFish
TempSpawnFishSubscriber.HandleSummonCardFish 召唤卡出鱼 = Topic_0524_SummonCardFish 调用 SpawnSummonCardFish 并推送 SummonCardFishNotice

对局层对外发布的消息

发布者 主题(TopicKeys) 触发点
FishingGameService.SendRoomChange 房间变化 = Topic_0524_RoomChage 进房/离房/清理房间等(PublishAsync)
FishingGameService.UseProp / UseTorpedo 用户资产变更 = Topic_0524_UserAssetsChanged 消耗钻石/背包道具/鱼雷(Publish)
FishingGameService.FishKillControl 全局击杀公告 = Topic_0524_GlobalKillAnnounce 房间内爆金达到阈值
FishingGameService.FlushFishingTaskProgress 任务完成 = Topic_0524_CompletedTask 离房/结算时汇总任务进度
RobotKillAnnounceService 全局击杀公告 = Topic_0524_GlobalKillAnnounce 定时伪造机器人爆金
LoginBindSubscriber.HandleLoginBind 登录结果通知 = Topic_0524_LoginBindResult 登录结算成功/失败回执

说明:对局层 Hub 的 KillNotice 还有一条「非 CAP」的广播通道——FishingSendService.KillNotice 通过 IConnectionMultiplexer 向 Redis 频道 fishgame:global 发布 JSON 消息,由 GlobalBroadcastSubscriber 消费后经 Hub 下发。


四、项目结构与技术要点

4.1 各项目 csproj(框架版本与依赖)

项目 相对路径 SDK/TFM 项目引用 关键 NuGet
FishRoomHost FishGameSrc\FishRoomHost\FishRoomHost.csproj Microsoft.NET.Sdk.Web / net8.0 FishRoomService、Infrastructure\CommonInfrastructure、Infrastructure\SharpAbp.Infrastructure.Api SignalR.StackExchangeRedis 8.0.0、StackExchange.Redis 2.7.4、NLog.Web.AspNetCore 6.1.2、Autofac 8.3.0、AutoMapper 14.0.0、DotNetCore.CAP(.Dashboard/.PostgreSql/.RabbitMQ) 8.3.4、SignalR.Protocols.MessagePack 8.0.17
FishGameHost FishGameSrc\FishGameHost\FishGameHost.csproj Microsoft.NET.Sdk.Web / net8.0 FishGameService、Infrastructure\CommonInfrastructure、Infrastructure\SharpAbp.Infrastructure.Api StackExchange.Redis 2.7.4、SignalR.Protocols.MessagePack 8.0.0、NLog.Web.AspNetCore 6.1.2、Autofac 8.3.0、AutoMapper 14.0.0、DotNetCore.CAP(.Dashboard/.PostgreSql/.RabbitMQ) 8.3.4
FishGameService FishGameSrc\FishGameService\FishGameService.csproj Microsoft.NET.Sdk / net8.0(类库) CommonDomain、CommonService、RedisService、UserSrc\UserService AutoMapper 14.0.0、DotNetCore.CAP 8.3.4
FishRoomService FishRoomService\FishRoomService.csproj Microsoft.NET.Sdk / net8.0(类库) CommonService、RedisService、UserSrc\UserService AutoMapper 14.0.0、DotNetCore.CAP 8.3.4、Microsoft.AspNetCore.SignalR.Core 1.2.9

三个 Host/Service 项目均以 None 方式引入根目录 nlog.config,并拷贝 docker-compose.yaml、Dockerfile 到输出目录。

4.2 两个进程入口要点

FishRoomHost\Program.cs

  • 设置环境变量 SERVICE_NAME、INSTANCE_ID(默认 default),并注册单例 AppInstanceId。
  • 配置加载顺序:默认 appsettings*.json 之后追加 Config\system.json(builder.Configuration.AddJsonFile(Path.Combine("Config", "system.json"), optional: true))。
  • 绑定 MongoDbSettings(IOptions<MongoDbSettings> + IMongoDbSettings)。
  • Redis 连接串优先取 ConnectionStrings:Redis,否则由 RedisConfig(Host/Port/Password/Database)拼装,注册单例 IConnectionMultiplexer。
  • SignalR:MaximumReceiveMessageSize = 64KB、StreamBufferCapacity = 512、ClientTimeoutInterval = 60s、KeepAliveInterval = 5s,注册 Hub 过滤器 MovementFilter 与 HubExceptionFilter,使用 .AddJsonProtocol()。
  • 其他注册:FormOptions 上传上限 16MB、内存缓存、DatetimeJsonConverter、IHttpContextAccessor、IHubSend<FishRoomHub>、IRequestApi、AddAutoMapper(typeof(AutoMapperConfig))、健康检查 self、CORS(Cors 策略,允许任意源+凭证)、AddCustomJwt、AddRedisCacheSingleton。
  • Autofac:UseServiceProviderFactory<AutofacServiceProviderFactory> + RegisterModule<AutofacModule>()。
  • CAP:builder.Services.AddCap(builder.Configuration)(见 4.4)。
  • 管道:UseApiLogging → UseRouting → UseGlobalExceptionHandler → UseStaticFiles → UseCors("Cors") → UseAuthentication → UseAuthorization → MapHub<FishRoomHub>("/fishingroomhub", WebSockets) → MapControllers → MapHealthChecks("/health")。
  • 启动后若房间列表为空则 InitRoom()。

FishGameHost\Program.cs

  • 与 FishRoomHost 结构基本一致(环境变量、AppInstanceId、配置、Redis、SignalR、CORS、JWT、RedisCache)。
  • 额外注册 BulletConfig(GetSection("BulletConfig"))。
  • CAP 相关:显式注册 4 个 ICapSubscribe 订阅者(PlayerFactorSubscriber、LoginBindSubscriber、BackgroundAssetSubscriber、TempSpawnFishSubscriber),再 AddCap。
  • 后台服务:AddHostedService<GlobalBroadcastSubscriber>()、AddHostedService<RobotKillAnnounceService>()(FishSpawnService 在 AutofacModule 中注册为单例 IHostedService)。
  • 管道:MapHub<FishGameHub>("/fishinghub", WebSockets)。

4.3 DI 注册位置(AutofacModule)

FishRoomHost\Middleware\AutofacModule.cs

  • 泛型注册 MongoBaseRepository<> → IMongoBaseRepository<>、MongoBaseService<> → IMongoBaseService<>(InstancePerLifetimeScope)。
  • 注册 RedisService → IRedisService。
  • 按程序集批量注册以 Service 结尾的类型(ApiLogService 所在程序集、FishingRoomService 所在程序集、UserService.User.UserService 所在程序集),AsImplementedInterfaces。

FishGameHost\Middleware\AutofacModule.cs

  • 上述 Mongo/Redis/批量服务注册之外,额外:
    • ReconnectTracker → IReconnectTracker(单例)
    • BulletTracker → IBulletTracker(单例)
    • FishKillTracker → IFishKillTracker(单例)
    • FishSpawnConfigStore(AsSelf,单例)
    • FishSpawnService → AsSelf 且 As<IHostedService>(单例)
    • 批量注册 Service 结尾类型(排除 FishSpawnService、RobotKillAnnounceService)与 Subscriber 结尾类型(AsSelf)。

4.4 SignalR / CAP / Redis 配置

SignalR:两进程均在 Program.cs 配置过滤器和消息包参数;Hub 均只启用 WebSockets 传输。房间层 MovementFilter 内附一个令牌桶式 RateLimiter(速率常量 30、间隔 33ms),但调用点目前被注释;对局层 MovementFilter 记录非跳过方法(SyncGameData、FireCannon、KillFish、BotFireCannon、BotKillFish 被跳过)的调用日志。

CAP(两个 CapExtension.cs):

  • 均启用 UseDashboard();RabbitMQ 读取 CapConfig:Host/UserName/Password/VirtualHost,ExchangeName = "cap.exchange";存储用 PostgreSQL(CapConfig:PGLogHost,Schema public);SucceedMessageExpiredAfter = 7*24*3600、FailedRetryCount = 5、FailedRetryInterval = 10,并设置失败阈值回调。
  • 差异:FishGameHost\Extension\CapExtension.cs 额外设置 x.DefaultGroupName = $"FishGameHost-{instanceId}"(INSTANCE_ID 环境变量),用于多实例分组订阅;FishRoomHost 的 CapExtension 额外注册 IRoomMQService → RoomMQService。

Redis:

  • 房间层 Config\system.json:RedisConfig Host localhost、Port 6378、Database 2、密码 123456。
  • 对局层 Config\system.json:RedisConfig Host localhost、Port 6379、Database 1、密码 123456。
  • 数据存储:房间层 Mongo mongodb://localhost:27018/?authSource=admin;对局层 mongodb://localhost:27017(Database data_buyu)。
  • CAP 存储库:两进程 PostgreSQL 均指向 data_0524 库。

对局层独有配置(FishGameHost\Config\system.json):

"BulletConfig": { "SignKey": "63215f0afa3f5b25", "MaxBulletPerUser": 100, "TimeWindowSeconds": 5 },
"GameServerInstances": [ "http://localhost/fishinghub?instance=1" ]
  • BulletConfig 用于开炮/击杀签名校验(SignHelper:MD5(raw + "|" + key) 取前 8 位小写十六进制)与时间窗防重放(TimeWindowSeconds 默认 5 秒)。
  • GameServerInstances 供 RoomController 返回 WebSocket 地址。

端口补充说明(以代码与配置文件实际值为准,存在多处不一致,需注意):

  • 房间层 Program.cs 将 Hub 挂载在 /fishingroomhub;Config\system.json 中 "urls": "http://*:8004";launchSettings.json 开发 URL 为 http://localhost:8004;docker-compose.yaml(服务名 0524fishroom)映射 5244:80;ocelot 下游指向 5244。
  • 对局层 Program.cs 将 Hub 挂载在 /fishinghub;Config\system.json 中 "urls": "http://*:8003";launchSettings.json 开发 URL 为 http://localhost:5263;docker-compose.yaml(服务名 0524fishgame)映射 5243:80;ocelot 下游指向 5248。

即:容器内监听 80,docker-compose 将房间层映射到宿主机 5244;对局层的 compose 映射到 5243,而 ocelot 指向 5248——两部分配置本身不一致,文档如实记录,未作统一。

4.5 docker-compose 端口

  • FishGameSrc\FishRoomHost\docker-compose.yaml:name: webapi,服务 0524fishroom,镜像 0524fishroom,ports: 5244:80,restart: always。
  • FishGameSrc\FishGameHost\docker-compose.yaml:name: webapi,服务 0524fishgame,镜像 0524fishgame,ports: 5243:80,restart: always。

五、代码目录说明

以下目录树覆盖 FishGameSrc\** 与 FishRoomService\** 下的全部文件夹与 .cs/.json 文件,并标注关键文件职责。

5.1 FishGameSrc\FishRoomHost(房间层进程,5244 / /fishingroomhub)

FishGameSrc\FishRoomHost\
├── Config\
│   └── system.json                 # 运行配置:urls=8004、JwtConfig、PgSql、Cap(RabbitMQ+PG)、RedisConfig、MongoDbSettings、WXConfig
├── Extension\
│   └── CapExtension.cs             # AddCap 扩展:RabbitMQ(cap.exchange)+PostgreSQL 存储+Dashboard,并注册 IRoomMQService
├── Middleware\
│   ├── ApiLoggingMiddleware.cs     # /api 请求响应日志中间件(脱敏 Data 后写 ApiLog 到 Mongo),含 UseApiLogging 扩展
│   ├── AutofacModule.cs            # Autofac 注册:Mongo 泛型仓储/服务、RedisService、按程序集批量注册 Service
│   ├── HubExceptionFilter.cs       # SignalR Hub 异常过滤器(记录并吞掉异常,返回 null)
│   └── MovementFilter.cs           # SignalR Hub 过滤器(含未启用的 RateLimiter 令牌桶)
├── Properties\
│   └── launchSettings.json         # 开发启动配置(applicationUrl 8004)
├── .dockerignore                   # Docker 忽略规则
├── appsettings.json                # 基础日志配置
├── appsettings.Development.json    # 开发日志配置
├── docker-compose.yaml             # 容器编排:0524fishroom,5244:80
├── FishRoomHost.csproj             # 房间层进程项目文件
└── Program.cs                      # 进程入口:DI、SignalR、CAP、JWT、Redis、MapHub(/fishingroomhub)、启动即 InitRoom

5.2 FishGameSrc\FishGameHost(对局层进程,5248 / /fishinghub)

FishGameSrc\FishGameHost\
├── Config\
│   └── system.json                 # urls=8003、JwtConfig、PgSql、Cap、RedisConfig、MongoDbSettings、WXConfig、BulletConfig、GameServerInstances
├── Controllers\
│   ├── PlayerController.cs         # api/Player/login:演示登录签发 JWT 并返回固定玩家数据
│   ├── RoomController.cs           # api/Room/QuickJoin、api/Room/Assign:快速匹配与游戏服地址分配
│   └── TimeController.cs           # fishapi/Time/GetDateTime:服务端校时
├── Extension\
│   └── CapExtension.cs             # AddCap 扩展:含 DefaultGroupName=FishGameHost-{instanceId} 的多实例分组订阅
├── Middleware\
│   ├── ApiLoggingMiddleware.cs     # 同房间层,/api 日志中间件
│   ├── AutofacModule.cs            # Autofac:额外注册 Tracker/ConfigStore/FishSpawnService(IHostedService)/Subscriber
│   ├── HubExceptionFilter.cs       # Hub 异常过滤器
│   └── MovementFilter.cs           # Hub 过滤器(日志,跳过高频方法的参数打印)
├── Properties\
│   └── launchSettings.json         # 开发启动配置(applicationUrl 5263)
├── Services\
│   └── GlobalBroadcastSubscriber.cs# 订阅 Redis 频道 fishgame:global,按 All/Room 经 Hub 广播(含 GlobalBroadcastMessage 定义)
├── .dockerignore                   # Docker 忽略规则
├── appsettings.json                # 基础日志配置
├── appsettings.Development.json    # 开发日志配置
├── docker-compose.yaml             # 容器编排:0524fishgame,5243:80
├── FishGameHost.csproj             # 对局层进程项目文件
└── Program.cs                      # 进程入口:DI、SignalR、CAP 订阅者注册、托管服务、MapHub(/fishinghub)

5.3 FishGameSrc\FishGameService(对局层类库)

FishGameSrc\FishGameService\
├── Config\
│   └── BulletConfig.cs             # 开炮/击杀签名配置:SignKey、MaxBulletPerUser、TimeWindowSeconds
├── GameSend\
│   ├── IFishingSendService.cs      # 对局层推送服务接口(房间信息/击杀/开炮/座位/道具等全部服务端事件)
│   └── FishingSendService.cs       # 实现:Hub 发送封装 + 经 Redis 频道 fishgame:global 发布 KillNotice 全局公告
├── GameService\
│   ├── FishSpawnConfigStore.cs     # 出鱼配置存储:从 Redis(GetFishSpawnConfig) 读取并按 {gameType}:{roomLevel} 缓存,缺失时从 GameConfig 提取
│   ├── FishingGameService.cs       # 对局核心服务(进房/开炮/击杀/道具/鱼雷/离房/掉线/结算/因子/机器人),实现 IPendingSettlementService
│   ├── IBulletTracker.cs           # 子弹追踪(BulletTracker) 与 击杀标记(FishKillTracker) 接口与实现(内存,带上限 LRU)
│   ├── IFishingGameService.cs      # 对局核心服务接口
│   └── ReconnectTracker.cs         # 重连追踪(内存 ConcurrentDictionary)
├── Hubs\
│   └── FishGameHub.cs              # 对局 Hub:全部客户端方法入口与基础校验
├── Services\
│   ├── FishSpawnService.cs         # 出鱼后台服务(IHostedService):租约/刷鱼/快照/命中击杀校验/临时出鱼/冻结,含 RoomFishState、ActiveFish、SpawnFishItem
│   ├── KillAnnouncePolicy.cs       # 击杀公告阈值策略:gold >= minGold(默认 10,000,000)
│   └── RobotKillAnnounceService.cs # 机器人爆金公告后台服务(RobotKillConfig 驱动)
├── Subscribers\
│   ├── BackgroundAssetSubscriber.cs# 订阅 BackgroundOperation.NotifyUser:后台加减金币并同步房间
│   ├── LoginBindSubscriber.cs      # 订阅「登录绑定」「拒绝回房」
│   ├── PlayerFactorSubscriber.cs   # 订阅「因子变更」「配置变更」
│   └── TempSpawnFishSubscriber.cs  # 订阅「临时强制出鱼」「召唤卡出鱼」
├── Utils\
│   └── SignHelper.cs               # 签名工具:MD5(raw|key) 取前 8 位 + 校验
└── FishGameService.csproj          # 对局层类库项目文件

5.4 FishRoomService(仓库根目录,房间层类库)

FishRoomService\
├── Hubs\
│   └── FishRoomHub.cs              # 房间 Hub:GetRoomList、GetRoomInfo
├── MQ\
│   ├── IRoomMQService.cs           # 房间 MQ 服务接口(RoomChange)
│   └── RoomMQService.cs            # ICapSubscribe:订阅「房间变化」「用户资产同步前端」
├── RoomSend\
│   ├── FishingRoomSendService.cs   # 房间推送实现:GetRoomListResult、RoomChange
│   ├── IFishingRoomSendService.cs  # 房间推送接口
│   └── Response\
│       └── GameRoomReponse.cs      # 房间列表响应 DTO(RoomId/MaxPlayerCount/CurrentOnlinePlayerCount/RobotCount/RoomNumber)
├── RoomService\
│   ├── FishingRoomService.cs       # 房间业务:GetRoomList(分组+列表)、InitRoom(按配置+空房率+机器人初始化)
│   └── IFishingRoomService.cs      # 房间业务接口
├── AutoMapperConfig.cs             # AutoMapper 配置:RedisGameRoom → GameRoomReponse
└── FishRoomService.csproj          # 房间层类库项目文件

六、关键文件索引

文件相对路径 职责
FishGameSrc\FishRoomHost\Program.cs 房间层进程入口:DI、Redis、SignalR(/fishingroomhub)、CAP、JWT、启动 InitRoom
FishGameSrc\FishRoomHost\Extension\CapExtension.cs 房间层 CAP 配置(RabbitMQ+PostgreSQL+Dashboard)与 IRoomMQService 注册
FishGameSrc\FishRoomHost\Middleware\AutofacModule.cs 房间层 Autofac 容器注册
FishGameSrc\FishRoomHost\Middleware\ApiLoggingMiddleware.cs 房间层 /api 日志中间件
FishGameSrc\FishRoomHost\Config\system.json 房间层运行配置(端口/Redis/Mongo/CAP/JWT)
FishGameSrc\FishRoomHost\docker-compose.yaml 房间层容器编排(5244:80)
FishGameSrc\FishGameHost\Program.cs 对局层进程入口:DI、SignalR(/fishinghub)、CAP 订阅者、托管服务
FishGameSrc\FishGameHost\Extension\CapExtension.cs 对局层 CAP 配置(含多实例 DefaultGroupName)
FishGameSrc\FishGameHost\Middleware\AutofacModule.cs 对局层 Autofac 容器注册(Tracker/ConfigStore/FishSpawnService)
FishGameSrc\FishGameHost\Services\GlobalBroadcastSubscriber.cs 订阅 Redis 频道 fishgame:global 并广播
FishGameSrc\FishGameHost\Controllers\RoomController.cs api/Room/QuickJoin、api/Room/Assign
FishGameSrc\FishGameHost\Controllers\TimeController.cs fishapi/Time/GetDateTime 校时接口
FishGameSrc\FishGameHost\Controllers\PlayerController.cs api/Player/login 演示登录
FishGameSrc\FishGameHost\Config\system.json 对局层运行配置(BulletConfig、GameServerInstances 等)
FishGameSrc\FishGameHost\docker-compose.yaml 对局层容器编排(5243:80)
FishGameSrc\FishGameService\Hubs\FishGameHub.cs 对局 Hub:全部客户端方法入口
FishGameSrc\FishGameService\GameService\FishingGameService.cs 对局核心业务(进房/开炮/击杀/结算/掉线/机器人/因子)
FishGameSrc\FishGameService\GameService\IFishingGameService.cs 对局核心服务接口
FishGameSrc\FishGameService\GameService\IBulletTracker.cs 子弹追踪与击杀标记(内存实现)
FishGameSrc\FishGameService\GameService\ReconnectTracker.cs 重连追踪
FishGameSrc\FishGameService\GameService\FishSpawnConfigStore.cs 出鱼配置缓存与从 GameConfig 提取
FishGameSrc\FishGameService\Services\FishSpawnService.cs 出鱼后台服务(租约/刷鱼/快照/命中校验/冻结)
FishGameSrc\FishGameService\Services\RobotKillAnnounceService.cs 机器人爆金公告后台服务
FishGameSrc\FishGameService\Services\KillAnnouncePolicy.cs 击杀公告阈值策略
FishGameSrc\FishGameService\GameSend\FishingSendService.cs 对局层推送实现 + Redis 全局击杀公告
FishGameSrc\FishGameService\GameSend\IFishingSendService.cs 对局层推送接口
FishGameSrc\FishGameService\Subscribers\LoginBindSubscriber.cs 订阅登录绑定/拒绝回房
FishGameSrc\FishGameService\Subscribers\PlayerFactorSubscriber.cs 订阅因子变更/配置变更
FishGameSrc\FishGameService\Subscribers\TempSpawnFishSubscriber.cs 订阅临时出鱼/召唤卡出鱼
FishGameSrc\FishGameService\Subscribers\BackgroundAssetSubscriber.cs 订阅后台资产变更
FishGameSrc\FishGameService\Config\BulletConfig.cs 签名与子弹配置模型
FishGameSrc\FishGameService\Utils\SignHelper.cs 签名计算与校验
FishRoomService\Hubs\FishRoomHub.cs 房间 Hub:GetRoomList、GetRoomInfo
FishRoomService\RoomService\FishingRoomService.cs 房间业务:大厅列表与房间初始化
FishRoomService\RoomService\IFishingRoomService.cs 房间业务接口
FishRoomService\RoomSend\FishingRoomSendService.cs 房间推送实现
FishRoomService\MQ\RoomMQService.cs 房间级 CAP 订阅(房间变化、资产同步前端)
FishRoomService\RoomSend\Response\GameRoomReponse.cs 房间列表响应 DTO
FishRoomService\AutoMapperConfig.cs 房间层 AutoMapper 配置
Gateway\ocelot.json 网关路由(含 /fishingroomhub→5244、/gamehub→/fishinghub 5248)
CommonDomain\TopicKeys.cs 全局 CAP 主题常量定义
CommonDomain\GameConfig.cs 游戏配置(房间/鱼/机器人/击杀/出鱼因子等)
CommonDomain\EmptyRoomRateConfig.cs 空房率配置
CommonDomain\BotProfileEntity.cs 机器人昵称/头像配置
CommonDomain\CapMessageModels.cs CAP 消息模型(登录绑定/临时出鱼/召唤卡/因子变更/配置变更/后台操作)
Infrastructure\Common\Redis\RedisKey.cs Redis Key 生成器(含捕鱼相关 Key)
RedisService\IRedisService.cs Redis 服务接口(房间/玩家/配置/因子/进度等读写)
RedisService\Param\RedisGameRoom.cs 房间模型
RedisService\Param\RedisGamePlayer.cs 房间内玩家模型
RedisService\Param\RedisUserCid.cs 用户-连接-房间映射模型
RedisService\Param\RoomBotFactory.cs 机器人工厂(FixedBotSeats 当前为空)

七、与其他模块的交互

7.1 CAP / RabbitMQ 消息(主题常量见 CommonDomain\TopicKeys.cs)

本模块「订阅」的消息

主题常量 实际主题名 订阅者
房间变化 Topic_0524_RoomChage FishRoomService\MQ\RoomMQService(房间层向分区分组广播 RoomChange)
用户资产同步前端 Topic_0524_UserAssetSyncFrontend RoomMQService(房间层推送 AssetUpdated)
因子变更 Topic_0524_PlayerFactorChanged PlayerFactorSubscriber(对局层)
配置变更 Topic_0524_ConfigChanged PlayerFactorSubscriber(对局层)
登录绑定 Topic_0524_LoginBind LoginBindSubscriber(对局层,登录前结算离房)
拒绝回房 Topic_0524_DismissPendingRoom LoginBindSubscriber(对局层强制清房)
临时强制出鱼 Topic_0524_TempSpawnFish TempSpawnFishSubscriber(对局层)
召唤卡出鱼 Topic_0524_SummonCardFish TempSpawnFishSubscriber(对局层)
BackgroundOperation.NotifyUser(字符串常量) BackgroundOperation.NotifyUser BackgroundAssetSubscriber(对局层后台加减币)

本模块「发布」的消息

主题常量 实际主题名 发布者 消费方(平台其它模块,来自全局定义)
房间变化 Topic_0524_RoomChage FishingGameService.SendRoomChange(对局层) 房间层 RoomMQService(本模块内闭环)
用户资产变更 Topic_0524_UserAssetsChanged FishingGameService.UseProp/UseTorpedo 用户资产模块(UserService)
全局击杀公告 Topic_0524_GlobalKillAnnounce FishingGameService.FishKillControl、RobotKillAnnounceService 全服公告消费方(UserService\Hubs\KillAnnounceSubscriber.cs 等)
任务完成 Topic_0524_CompletedTask FishingGameService.FlushFishingTaskProgress 任务系统(CompletedTaskParam,UserService 侧)
登录结果通知 Topic_0524_LoginBindResult LoginBindSubscriber.HandleLoginBind 登录模块(UserService LoginResultSubscriber)

说明:全局击杀公告 由 UserService\Hubs\KillAnnounceSubscriber.cs 承接(全服广播);登录绑定/登录结果通知/用户资产变更 等由 UserService 侧订阅者处理,跨进程完成「登录前结算离房」「资产落库与前端同步」等协作。以上消费方文件位于本模块之外,此处仅据主题名与命名对应关系指出大致去向,具体实现不在本模块范围内。

7.2 Redis Key

来源 Infrastructure\Common\Redis\RedisKey.cs + RedisKeyGenerator.cs。RedisKeyGenerator 按服务名加前缀(game→game-service、user→user-service、common→app-shared),故实际 Key 形如 game-service:...:

属性/常量 生成方式 实际 Key 用途
GameConfig GameKey("config") game-service:config 游戏配置(GameConfig)
ActivityConfig GameKey("activity:config") game-service:activity:config 活动配置
FishingKillConfig GameKey("fishing:killconfig") game-service:fishing:killconfig 击杀/玩法配置(FishingKillConfig)
FishSpawnConfig GameKey("fish:spawn:config:v1") game-service:fish:spawn:config:v1 出鱼配置 JSON
SystemGoldDayKey GameKey("fish:gamestatic") game-service:fish:gamestatic 系统当日金币(系统因子计算)
GameRoomIdKey GameKey("room:model:{0}_{1}") game-service:room:model:{0}_{1} 房间模型 Key
DistributedLockPrefix CommonKey("lock:") app-shared:lock: 分布式锁前缀
UserCIDGID UserKey("uid:{0}") user-service:uid:{0} 用户 → 连接/房间映射
CIDUser / LoginCIDUser UserKey("cid:{0}") user-service:cid:{0} 连接 → 用户映射

FishSpawnService 内自定义 Redis Key:

常量前缀 完整 Key 用途
fish:spawn:global:id 同左 全局自增鱼 Id
SpawnOwnerKeyPrefix fish:spawn:owner:{roomId} 房间出鱼权租约(10 秒)
ActiveFishSnapshotKeyPrefix fish:spawn:snapshot:{roomId} 活跃鱼快照(60 秒)
FishKilledKeyPrefix fish:spawn:killed:{roomId}:{fishId} 鱼已击杀标记
SpawnStopKeyPrefix fish:spawn:stop:{roomId} 房间停止出鱼标记

FishingGameService 使用分布式锁 Key:{lock:}fish:gold:{roomId}:{userId}(金币/结算互斥)。

Redis 发布/订阅频道(非 CAP):fishgame:global —— FishingSendService.KillNotice 发布,GlobalBroadcastSubscriber 订阅。

7.3 HTTP 调用

  • 本模块内 FishGameHost\Controllers\RoomController.cs 读取配置 GameServerInstances 返回游戏服 WebSocket 地址(当前取列表第 0 项),并读取 Redis 房间列表做快速匹配。
  • 通过 IRequestApi(注册于 Program.cs)提供对外 HTTP 请求能力;FishingGameService、房间层服务通过 IUserService(UserService 项目)读写用户资产、属性、结算等(GameCoinsSettlement、UpdateAssets、UpdateUser、RecordFishingConsume、GetUser)。
  • 校时接口 fishapi/Time/GetDateTime 供客户端对齐服务器时间。

7.4 共享实体 / 项目引用

  • 项目引用链:
    • FishRoomHost → FishRoomService、CommonInfrastructure、SharpAbp.Infrastructure.Api
    • FishGameHost → FishGameService、CommonInfrastructure、SharpAbp.Infrastructure.Api
    • FishGameService → CommonDomain、CommonService、RedisService、UserService
    • FishRoomService → CommonService、RedisService、UserService
  • 共享实体/模型:RedisService.Param(RedisGameRoom、RedisGamePlayer、RedisUserCid、RoomBotFactory)、CommonDomain(GameConfig、EmptyRoomRateConfig、BotProfileEntity、FishingKillConfig、ActiveFish 相关、TopicKeys、CapMessageModels、KillAnnounceParam)、UserDomain.Entity(UserEntity)、CommonDomain.Enum(GameTypeEnum、FishTypeEnum、ProductTypeEnum、TaskEvent、ErrorCodes 等)。
  • 公共基础设施:MongoRepository(IMongoBaseRepository<> / IMongoBaseService<>)、RedisService / RedisHelper(ICache、IDistributedLock)、SharpAbp.Infrastructure.Api(UseGlobalExceptionHandler 等中间件)、JWTHelper(AddCustomJwt、JwtTools)、CommonService(IHubSend<>、HubSend<>、ApiLogService、AppInstanceId)。

本文档为一次性通读源码后整理的静态说明;如后续修改了 Hub 方法、CAP 主题、Redis Key 或端口配置,请同步更新本文件。