跳到主要内容

怪物赠礼(Grant ID)

当 NPC 把一只怪物交给玩家 —— 实验室里的初始伙伴、路上的赠礼、复活的化石 —— 单人游戏只需把它加入队伍。在线游戏不能这样做:能给自己任意怪物的客户端,也能给自己一只传说怪物。在 MCE Online 中,由服务器铸造赠礼,客户端只是请求它。

适用于 Pro 和 Source 层级。

赠礼在线上如何运作​

每个赠礼背后的节点都是 GiveMonsters(CommandGraph,Monsters 类别)。初始伙伴和“NPC 赠礼”是同一个节点,所以两者只有一套机制。

  1. 玩家与 NPC 交谈,图到达 GiveMonsters 节点。
  2. 在线时,该节点不会添加怪物。它通过 OnlineCommandBridge.RequestGiveMonsterAsync(grantId, ...) 向服务器请求,并用 GrantId 指明站点。
  3. 服务器在自己的数据(monster_grant_data)中查找该站点,铸造它记录在案的物种、等级和数量。客户端在请求中发送的任何物种都会被忽略并记入日志。
  4. 服务器记录该角色已领取过这个站点(monster_grant_claims,以角色和赠礼 ID 为键),因此赠礼每个角色只能领取一次:一个可以反复交谈的 NPC 不是怪物工厂。
  5. 客户端收到铸造出的怪物,并使用离线路径所用的同样对话框来显示它。

如果服务器不批准,该节点不会在本地授予任何东西 —— 那样会重新打开自我赠礼的漏洞 —— 并显示“grant failed”对话框。离线时则完全没有变化。

GrantId​

每个赠礼站点都需要自己的 GrantId:一个存储在 GiveMonsters 节点上的不透明字符串(它在 Inspector 中是隐藏的,你不需要输入)。服务器会点名拒绝空 ID(grantId is required),因此没有 ID 的站点在线上不会给出赠礼 —— 它是失败时关闭的。

这些 ID 具有以下特性:

  • 按站点,而非按节点类型。 两个互相复制的节点共享节点的创作 GUID,但给出不同的东西;盖章的 ID 是节点的 GUID 加上节点所在位置(资产的 GUID 和属性路径)的短哈希,因此每个站点都是独一无二的。
  • 稳定。 哈希使用资产的 GUID 而不是它的路径,所以移动或重命名文件不会改变它。
  • 不透明。 ID 不含 #、/ 或文件扩展名,因此节点在运行时总能处理它。
  • 绝不覆盖。 盖章只会填充空的 ID。已经存在的 ID,以及服务器针对它的种子数据,永远不会改变。

盖章与导出(编辑器侧)​

MonsterGrantSeedExporter(位于 MCE.Online.Editor 程序集)完成两项工作:

  1. 它扫描项目的预制体和场景中的 GiveMonsters 节点。场景会先按文本过滤(只有当场景的 YAML 包含节点的类标记时才会打开它),所以扫描不会打开每一个场景。
  2. 开启盖章后,它填充缺失的 GrantId,并写出种子:SeedData/monster-grant-seed.json(每个站点给出什么)和 SeedData/monster-grant-seed.report.txt(看到的站点和跳过的站点,并附原因)。

导出器的入口:

入口用途
MonsterGrantSeedExporter.Export(folder)为缺失的 ID 盖章,然后写出种子和报告
MonsterGrantSeedExporter.Scan(stampMissingIds, persist)扫描;可选择盖章,可选择保存到磁盘。单独的 Scan() 不读取也不写入任何内容
BatchExporters.ExportMonsterGrants批处理模式:-executeMethod OpenMon.MCE.Online.Editor.BatchExporters.ExportMonsterGrants

把种子发送到服务器是服务器对服务器的,与其他种子相同:mce_monster_grant_seed RPC 会拒绝任何携带用户会话的调用,并需要运行时 HTTP 密钥(关于该密钥为何绝不进入 Unity,参见物种播种)。

提供选择的赠礼

GiveMonsters 发放一个固定的赠礼(或一个随机的)。提供选择的节点 —— GiveMonstersBasedOnChosenItem,就像化石复活师那样 —— 会以 choice: true 导出:服务器根据玩家选择的索引推导出所选选项需要的道具,因此客户端无法通过声称花掉了便宜的那个来复活昂贵的化石。

导入的游戏​

从卡带或 Essentials 项目导入的游戏充满了赠礼节点:实验室的三只初始伙伴、NPC 给的宝可梦、化石。导入器会为你完成盖章。

NPC 导入器(HeartGold / SoulSilver、FireRed)完成之后,GrantsEnLoImportado.Estampar() 会在开启盖章和持久化的情况下运行导出器的扫描 —— 前提是在线层是项目的一部分;没有它就无章可盖。随后它用独立的计数来检查自己的工作:读取 Assets/ImportedGames 下的每个场景,并统计空的 GrantId 值,包括场景以预制体实例的覆盖形式存储的那些(实验室的初始伙伴正是如此)。如果还剩下任何一个,它就会抛出异常,因此导入绝不会在留下服务器会拒绝的赠礼时“成功”结束:

[Importador] GrantId de los regalos: estampados=3 yaEstaban=0 quedanSinId=0

(estampados:本次盖章的数量;yaEstaban:已有 ID 的数量;quedanSinId:仍为空的数量,必须为 0。)

之后,导出赠礼种子(见上文)并发送到服务器。与其他种子 RPC 一样,mce_monster_grant_seed 会拒绝任何携带用户会话的调用:只有带运行时 HTTP 密钥的服务器对服务器调用才能写入它。

参考​

类型位置作用
GiveMonstersOpenMon.MCE.Actors.CommandGraph.Monsters节点;携带 GrantId,在线时向服务器请求
OnlineCommandBridge.RequestGiveMonsterAsyncMCE.Online.Runtime请求(grantId,可选的选择索引)
MonsterGrantSeedExporterOpenMon.MCE.Online.Editor扫描、盖章并导出种子
GrantsEnLoImportadoOpenMon.MCE.EssentialsImporter.Editor导入后为 ID 盖章并验证
mce_monster_grant_seedNakama RPC服务器对服务器:存储站点