模组实现目录
本子树记录 Forge 侧遗址系统的实现契约。我们把已经验证的 API、建议实现的对象和仍未落地的类分开写。
已验证的运行时事实
| 问题 | 已验证的 API 或事件 | 结论 |
|---|---|---|
| 原版刷扫链路 | BrushItem.useOn(...)、BrushItem.onUseTick(...)、BrushableBlockEntity.brush(...) | 前期发现可直接复用原版考古主链路 |
| 世界级持久化 | ServerLevel.getDataStorage()、DimensionDataStorage.computeIfAbsent(...) | 世界账本应使用 SavedData |
| 持久化写盘 | SavedData.setDirty()、LevelEvent.Save | 修改账本后必须标脏,写盘在 world save 时完成 |
| 区块 NBT | ChunkDataEvent.Load / Save | 适合辅助数据,不适合世界真相 |
| 区块生命周期 | ChunkEvent.Load / Unload | 可做缓存和资源释放,不能替代账本 |
| 区块可见性 | ChunkWatchEvent.Watch / UnWatch | 适合按玩家同步区块局部数据 |
| 方块提取交互 | Block#use(BlockState, Level, BlockPos, Player, InteractionHand, BlockHitResult) | 揭露态与提取态可以分离 |
| 玩家交互 | PlayerInteractEvent.RightClickItem / RightClickBlock | 适合做正式勘探提交面和激活适配器 |
| 玩家知识迁移 | PlayerEvent.Clone | 长期知识如挂在玩家上,重生时必须复制 |
| 客户端 tooltip | ItemTooltipEvent | 玩家对象可能为 null |
数据所有权总表
| 数据 | 推荐权威位置 | 不该放在哪里 |
|---|---|---|
| 前期发现节点是否已耗尽 | 世界方块状态 | 世界账本主表 |
| 遗址实例是否存在 | SiteLedgerSavedData | 玩家短标记 |
| 遗址当前是否运行中 | SiteRuntimeRegistry | 区块缓存 |
| 区块局部表现或辅助信息 | chunk data 或 chunk capability | 世界账本主表 |
| 玩家待提交遗址 | player.getPersistentData() | 世界账本主表 |
| 遗物结果 | 物品快照或独立记录 | live runtime |
写入时机总表
同一条数据该在什么时候写,比“写到哪”同样重要。
| 数据 | 首次写入时机 | 后续读取方 |
|---|---|---|
DiscoveredSiteRecord | 正式勘探确认后 | 激活、运行态、回收 |
lc_pending_site_ref 这类玩家短标记 | 正式勘探结束、激活之前 | 激活层 |
ActiveSiteRuntime | 激活服务通过后 | 运行态服务、结算服务 |
| 区块辅助缓存 | chunk load、watch 或局部计算完成后 | 客户端同步、局部表现 |
ResonanceResult | 激活或现场启动阶段 | runtime、recovery |
RecoveredRelicSnapshot | 回收结算时 | tooltip、图鉴、后续处理 |
| 玩家长期知识 | 回收、鉴定或长期推进节点 | tooltip、后续勘探门槛 |
如果写入时机错了,哪怕对象放对了,也会出现重复初始化、过期状态或错误回写。
建议实现的第一批对象
| 对象 | 作用 | 当前状态 |
|---|---|---|
CivilizationShellDefinition | 定义前期发现的文明外壳 | 待实现 |
EarlyExcavationNodeDefinition | 定义一种前期考古节点 | 待实现 |
SiteTypeDefinition | 定义一种遗址类型 | 待实现 |
SiteTypeRegistry | 注册遗址类型 | 待实现 |
SiteRef | 引用一座具体遗址 | 待实现 |
DiscoveredSiteRecord | 世界账本中的一条实例记录 | 待实现 |
SiteLedgerSavedData | 维度级账本 | 待实现 |
ActivationContext | 一次激活提交的统一输入 | 待实现 |
ActivationResult | 激活层的统一返回值 | 待实现 |
ActivationService | 激活主干服务 | 待实现 |
ActivationAdapter | 把不同交互面转成统一上下文 | 待实现 |
SiteRuntimeBridge | 在服务通过后打开运行态 | 待实现 |
SiteRuntimeRegistry | 管理活跃运行态 | 待实现 |
ActiveSiteRuntime | 现场状态核心 | 待实现 |
RecoveredRelicSnapshot | 回收快照 | 待实现 |
RelicTooltipView | 格式化已保存结果 | 待实现 |
最小调用链
第一条可玩的实现链,建议固定为下面五步:
- 前期发现或正式勘探入口确认一座合法遗址。
- 正式勘探把结果写入
SiteLedgerSavedData,并生成SiteRef。 - 激活层通过
ActivationAdapter -> ActivationService把SiteRef接入SiteRuntimeRegistry。 - 运行态读取
ResonanceResult并推进ActiveSiteRuntime。 - 回收层把结果折叠成
RecoveredRelicSnapshot,之后只允许视图层读取快照。
这条链的价值在于把“正式记录”“运行态”“回收结果”三种状态完全拆开。只要某一步跳过前一步,后面就会失去稳定引用。
世界真相、区块缓存、玩家短标记
| 层 | 具体建议 | 生命周期 |
|---|---|---|
| 世界真相 | SiteLedgerSavedData | 跟随维度存档 |
| 区块缓存 | ChunkDataEvent 或 AttachCapabilitiesEvent<LevelChunk> | 跟随区块 load / unload |
| 玩家短标记 | lc_pending_site_ref | 只跨正式勘探和激活两个阶段 |
物品快照与玩家知识的分离
回收阶段至少要分开两条写入:
| 数据 | 推荐落点 | 原因 |
|---|---|---|
RecoveredRelicSnapshot | ItemStack 自身的 NBT | 物品流转时结果必须跟着物品走 |
lc_identification_level 这类长期知识 | 玩家长期数据 | 这是玩家理解能力,不是物品本体 |
这两条数据不能合并。玩家知识跟着角色走,遗物快照跟着物品走,两者生命周期不同。
第一批证明
- 前期发现能产出线索,并把节点稳定耗尽成不可再考古状态。
- 正式勘探能把交互落成
SiteRef。 - 激活能从
SiteRef打开且只打开一个 runtime。 - 运行态能在
LevelEvent.Save前后保持账本一致。 ChunkEvent.Unload不会误删世界账本。- tooltip 能从保存结果独立渲染。
- 遗物结果跟随
ItemStack流转,而不是只存在于玩家数据里。