Files

564 lines
46 KiB
Markdown
Raw Permalink Normal View History

2026-10-12 16:22:04 +08:00
# 捕鱼游戏模块(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 或端口配置,请同步更新本文件。