6.6 KiB
Raw Permalink Blame History

ADDED Requirements

Requirement: MongoDB 数据库连接组件

服务端 MUST 在 Gate Scene 启动时初始化 DBComponent,封装 MongoDB.Driver 提供异步读写。连接配置从 StartZoneConfig.DBConnectionDBName 读取。

Scenario: 启动时建立连接

  • WHEN ET Server Gate Scene 启动
  • THEN DBComponent 从 StartZoneConfig 读取 mongodb 连接字符串
  • AND 创建 IMongoClient 实例
  • AND 测试连接成功PING
  • AND 失败时记录错误日志并按 StartConfig 决定是否阻塞启动

Scenario: 集合自动创建

  • WHEN 首次写入某类型 Entity如 Player
  • THEN DBComponent 自动创建对应 collection命名 playersheroesbags...
  • AND 创建索引(默认按 EntityId

Requirement: 玩家数据加载

玩家登录 Gate Scene 成功后,服务端 MUST 从 MongoDB 加载该玩家的 Player EntityHeroComponent + BagComponent。若玩家首次登录MUST 创建新 Player 并发放初始资源(由 InitialResourceConfig 配置)。

Scenario: 老玩家登录

  • WHEN 玩家 PlayerId=10001 通过 C2G_LoginGate 登录
  • AND DB 中存在记录
  • THEN 服务端从 DB 加载完整 Player Entity 到内存
  • AND Player.GetComponent() 包含所有英雄子 Entity
  • AND Player.GetComponent() 包含所有道具

Scenario: 新玩家首次登录

  • WHEN 玩家 PlayerId 在 DB 中不存在
  • THEN 服务端创建 Player Entity
  • AND 添加 HeroComponent + BagComponent
  • ANDInitialResourceConfig 发放初始道具/英雄
  • AND 立即写入 DB同步保证幂等

Requirement: 数据持久化策略

服务端 MUST 采用 脏标记 + 定时刷盘 策略,避免每次业务操作直写 DB

  • 业务系统通过 EntitySystem.SetDirty(entity) 标记脏数据
  • DBSaveComponentSystem 每隔 N 秒(默认 30s扫描所有脏 Entity 并批量落库
  • 玩家离线session disconnected时 MUST 立即强制刷盘

Scenario: 业务操作触发脏标记

  • WHEN C2G_SummonHeroHandler 修改 HeroComponent
  • THEN 通过 Player.SetDirty() 标记
  • AND Handler 立即返回(不等落库)

Scenario: 定时批量刷盘

  • WHEN DBSaveComponent 定时器触发
  • THEN 扫描所有标记 dirty 的 Player
  • AND 异步 DBComponent.Save(player) 批量写入
  • AND 写入成功后清除 dirty 标记
  • AND 失败时保留 dirty 等下次重试

Scenario: 玩家离线立即刷盘

  • WHEN Gate Scene 收到 SessionDispose 事件
  • AND 该 Session 对应的 Player 是 dirty
  • THEN 同步等待 DBComponent.Save(player).Coroutine() 完成
  • AND 再释放 Player Entity

Requirement: Entity → BSON 序列化

DBComponent MUST 使用 ET 的 MongoHelper基于 MongoDB.Bson序列化/反序列化 Entity。所有要持久化的 Component 字段 MUST 加 [MongoElement] 特性,子 Entity 通过 ET 的 Entity 关系自动遍历。

Scenario: 持久化 HeroComponent

  • WHEN DBComponent.Save(player) 触发
  • THEN 序列化 Player 的所有 Component 包含 HeroComponent + BagComponent
  • AND 子 Hero Entity 递归序列化
  • AND 写入 MongoDB players collection按 PlayerId 为 _id

Scenario: 反序列化恢复

  • WHEN DBComponent.Query<Player>(playerId) 触发
  • THEN 从 BSON 重建 Player Entity 树
  • AND 所有子 EntityHero、Item 等)的父子关系正确恢复
  • AND 通过 Player.GetComponent<HeroComponent>().GetHero(heroId) 能直接访问

Requirement: 并发与一致性

同一玩家的业务请求 MUST 在 Gate Scene 串行执行ET 单线程纤程天然保证。但跨玩家操作如交易、组队MUST 通过 ET 的消息机制传递,避免直接跨纤程访问。

Scenario: 同玩家串行请求

  • WHEN 客户端在 1 帧内连续发送 SummonHero 和 HeroAddExp
  • THEN Gate Scene 单线程依次处理两个请求
  • AND 第二个请求看到第一个的副作用(新英雄存在)

Scenario: 跨玩家通过消息

  • WHEN 玩家 A 给玩家 B 赠送道具(未来需求)
  • THEN 必须通过 ET 的 Actor 消息机制
  • AND 不允许 A 的纤程直接修改 B 的 BagComponent

Requirement: DB 索引

服务端 MUST 为常用查询字段建索引:

  • players._id (默认按 PlayerId)
  • players.account(玩家账号反查)
  • 业务表如 friendships(未来需求)需自定义索引

Scenario: 索引创建

  • WHEN DBComponent 首次连接 DB
  • THEN 检查并创建 players collection 上的必要索引
  • AND 通过 IMongoCollection<Player>.Indexes.CreateOneAsync 创建

Requirement: 数据迁移版本号

每个持久化 Entity MUST 包含 dataVersion (int32) 字段,用于未来数据结构变更时支持渐进式迁移。

Scenario: 版本号读取

  • WHEN 加载 Player 时 dataVersion < 当前版本
  • THEN DBMigrationComponent 运行该版本到当前版本的迁移函数
  • AND 迁移后更新 dataVersion = 当前版本
  • AND 立即保存到 DB

Scenario: 新建 Player 写入版本号

  • WHEN 创建新 Player Entity
  • THEN 自动设置 dataVersion = 当前最新版本

Requirement: 日志与监控

DB 操作 MUST 记录以下日志(基于 ET 的 Log 系统):

  • 慢查询:超过 100ms 的读写
  • 失败:连接断开、超时、序列化错误
  • 容量:每隔 1 小时记录 collection 文档数和大小

Scenario: 慢查询日志

  • WHEN DBComponent.Save(player) 耗时超过 100ms
  • THEN 输出 Log.Warning 包含 PlayerId、耗时
  • AND 不影响业务流程

Scenario: 失败重试

  • WHEN DB 写入抛 MongoConnectionException
  • THEN 框架 MUST 重试最多 3 次(指数退避)
  • AND 仍失败则保留 dirty 标记等下次刷盘
  • AND 输出 Log.Error

Requirement: 开发模式无 DB 选项

系统 MUST 支持开发期免 MongoDB 模式:当 StartZoneConfig.DBConnection == "memory" 时,服务端 MUST 启用 MemoryDBComponent,所有"持久化"只在进程内存中Dictionary重启清空。生产环境 MUST 禁止使用此模式(启动时 WARNING 日志提示)。

Scenario: 内存模式启动

  • WHEN StartZoneConfig.DBConnection == "memory"
  • THEN DBComponent 实例化为 MemoryDBComponent
  • AND 所有读写在 Dictionary<long, Player> 内存中完成
  • AND 不需要本地起 mongod

Scenario: 内存模式重启

  • WHEN 内存模式下 ET Server 重启
  • THEN 所有玩家数据丢失(仅开发期使用)
  • AND 日志输出 WARNING 提示此模式不可用于生产