Web 化可行性评估(Phase 0 已落地)
本篇评估"这游戏能不能搬进浏览器、走什么技术路线"。它是 Native 引擎逻辑 与 引擎数据契约 两篇分析的战略层延伸。
本篇结论已被真机流量修正(重要)
本篇早期版本基于 testStageData1.json 的 webData 字段形状推测"战斗是服务器权威、 客户端只回放",并据此判断 R3 范围可控。这个推测已被真机流量证伪:战斗模拟 完全在客户端。相关判断、判据与路线权衡均已在下文修订, 引擎数据契约 的对应结论同步更正。
若你读过旧版并记住了"战斗=服务端算好、客户端回放",请以本篇为准。
这是评估,不是承诺
本篇不启动任何移植,只梳理路线与已知事实。合规口径同前:可据公开格式与自采数据契约 自行实现,但不照搬引擎反编译产物、不再分发提取出的游戏美术/音频/文本。
一句话判断
元游戏(菜单层)搬 Web 很现实;整款做成纯浏览器游戏的壁垒不止"渲染",还多了一整个 "战斗结算引擎"——因为战斗逻辑在客户端,没有现成代码可用。但"没有代码"不等于"没有规格": 社区 wiki 已把战斗结算写到实现级**(见 规格来源), 且验收只需 对齐社区共识—— 即"Unix 与 Linux"那样的关系,无须逐位复刻。** 务实路径仍是分阶段:先把已经"半个网页应用"的元游戏独立跑进浏览器;战斗则要么 照规格实现结算引擎,要么用云流化过渡。
代码库已经告诉我们的
魔纪客户端本就是 WebView(HTML5) + Cocos2d-x(原生) 的混合体:
| 层 | 现状 | 对 Web 化的意义 |
|---|---|---|
Web 前端 /magica/ + /magica/api/ | 主页/商店/扭蛋/任务菜单/剧情文字/编队,已被 WebViewInterceptor/CnvJsBridge/PlayerStateCache 吃透 | 本质已是网页应用,搬浏览器阻力最小 |
原生引擎 单颗 libmadomagi_native.so | Cocos2d-x + Live2D + CRI 音频 + 战斗结算与演出,中间件静态链入(见 数据契约) | 实时渲染/战斗/CG——纯 Web 化的真正壁垒 |
| 游戏数据 | 关卡/编成/掉落等定义为服务端下发的干净 JSON | 理解与驱动内容可绕开二进制(净室友好) |
关键修订:关卡确实是数据驱动的——但"数据驱动"只保证了**"打什么"可移植**, 不代表"怎么算"也在服务端。下一节是分界线所在。
Phase 0 结论:战斗是客户端权威
Phase 0 的核心问题是"战斗到底谁在算"。真机流量给出的答案是:客户端。
证据链
一场战斗横跨三个端点,且由同一个 userQuestBattleResultId 串起来,可无损对齐:
| 端点 | 方向 | 承载什么 |
|---|---|---|
POST /magica/api/quest/start | 服务端 → 客户端 | 建档:回传 userQuestBattleResultList 记录,其中所有战斗计数器均为 0(turns / diskAcceleNum / nativeClearTime / serverClearTime / enemyNum …),状态 CREATED |
POST /magica/api/quest/native/get | 服务端 → 客户端 | 完整战斗定义:双方全属性、波次敌人、ai id、discType1..5、place skill、art 效果定义、MP 获取率、doppel MP 消耗 |
POST /magica/api/quest/native/result/send | 客户端 → 服务端 | 客户端算好的结果:result / totalTurn / totalWave / clearTime / 各属性 totalDamage* / 每人 hpRemain・mpRemain / 各类行为计数器 |
两条决定性的否定证据:
- 全程没有任何随机种子字段。
quest/native/get的响应里不存在seed/random语义的字段——服务端没有把 RNG 状态交给客户端,也就无法自行复现这场战斗。 result/send只上报聚合量,没有逐回合轨迹。服务端拿到的是最终统计, 不足以重放校验。
合起来只有一个解释:战斗模拟 100% 在客户端(那颗 .so 里),服务端只负责建档与记账 (把客户端报上来的数字落库,并据此下发新的账号状态)。这正是本篇早期版本警告过的 "客户端自模拟 → 范围爆炸"分支。
那条判据是个陷阱
早期版本给的 Phase 0 判据是:
响应含完整
userQuestBattleResultList/userStatusList= 服务器权威
这条判据会得出错误答案。 那些字段确实出现了——就在 quest/start 的响应里, 而且 result/send 的响应也会回传更新后的账号状态。但它们是 "为客户端上报的结果记账",不是**"服务端算出来的战斗"**。
同样的字段形状,相反的结论
判断权威性不能只看响应里有没有结算类字段,必须看方向与时序: 谁先算出数字、谁把数字交给谁。正确的判据是三条—— ① 战斗定义下发后,服务端有没有给随机种子; ② 结算数字出现在请求体还是响应体; ③ 客户端有没有上报足以重放的逐步轨迹。 本例三条全部指向客户端权威。
战斗机制的可移植性拆解
结论听起来悲观,但范围是有界且可枚举的。关键在于: "打什么"全是数据,只有"怎么结算"需要重写。
服务端每场都白给(不用逆)
quest/native/get 的响应里已包含:双方全部属性(hpStart・attack・defence・maxMp…)、 波次与敌人编成、每个单位的 ai id、discType1..5、formation/place skill、 rateGainMpAtk/rateGainMpDef、consumeDoppelMp/limitMp、敌人 align 与 magnification, 以及每个技能/魔法的机器可读效果定义:
art = { artId, verbCode, effectCode, targetId, effectValue, growPoint, attributeId }也就是说,"这个技能干什么"是数据,不需要从二进制里挖。
必须自己实现(真正的缺口)
剩下的是那个结算引擎——没有现成代码,但有实现级规格可依(见下节)。需要实现的是:
- 伤害公式与属性克制倍率(
attackAlignmentRateTable给了表,但套用规则要自定) - MP 累积规则(
rateGainMpAtk/Def是参数,累积时机与上限要自定) - 行动顺序与速度判定
- 圆盘(disk)connect/combo/chain 成立条件与加成
- 状态效果的叠加、层数、持续与判定时序
- 暴击/回避/反击的触发与概率
- 敌人 AI:
ai是个整数 id,行为表在客户端 - magia/doppel 的倍率与消耗规则
效果系统是有限指令集
这块不是无底洞,而是一张能列完的表。对采集数据做枚举(取约 3.5% 前缀, 故为下界):
| 枚举 | 规模(下界) | 值 |
|---|---|---|
verbCode | 21 | ATTACK BUFF BUFF_DIE BUFF_DYING BUFF_HPMAX BUFF_PARTY_DIE CONDITION_BAD CONDITION_GOOD DAMAGE DEBUFF DRAW ENCHANT HEAL IGNORE INITIAL LIMITED_ENEMY_TYPE OTHER RESURRECT REVOKE TURN_ALLY TURN_ENEMY |
targetId | 9 | ALL CONNECT DYING HORIZONTAL LIMITED ONE SELF TARGET VERTICAL |
effectCode | 90+ | 属性攻防修正(ATTACK_FIRE…DAMAGE_DOWN_DARK)、状态(BURN CHARM CURSE FOG DARKNESS BLINDNESS BAN_SKILL BAN_MAGIA…)、机制(ACCEL BLAST CHARGE COUNTER CRITICAL AVOID BARRIER GUTS AGAIN C_COMBO_PLUS DEFENSE_IGNORED DAMAGE_UP_BAD_NUM…) |
而 result/send 的计数器字段集本身就把系统边界枚举出来了:7 种属性伤害 + 14 类异常状态(badCharmNum / badStunNum / badPoisonNum …) + accele/blast/charge 三种圆盘及其 combo + chainNum + chargeMax + skill/connect/magia/doppel + abnormal/avoid/counter。
换言之:规格的"外延"可以从数据完整推导;而"内涵"(公式本身)也并非空白——见下节。
规格来源:社区 wiki 是实现级规格
「魔法纪录中文Wiki」(MediaWiki 导出,主命名空间 2814 页)对战斗结算的记载不是定性描述, 而是可直接照着写代码的规格。三篇核心条目:
| 条目 | 提供了什么 |
|---|---|
| 伤害公式 | 完整乘法链(普攻/Magia/Doppel/追击/反击各一条);每个系数的确切数值(盘型基础系数、叠 C 原始倍率 1–20 层全表、B 盘位置系数、克制表 1.5/0.5/1.0 及属性强化 3.0);全部钳制区间(基础伤害下限 500、理论伤害下限 250、通用加伤 0.3–3.0、盘型弱体 0.3–5.0、属性弱体 0.3–2.0、Buff 同类叠加 −95%~+100%);取整(DEF/3);随机浮动 0.95–1.05;暴击规则(系数 ≤1 则 ×2,否则 +1);心魔战/歼灭战/镜界的系数变体 |
| MP计算公式 | floor/round 的嵌套顺序与 0.1 精度(并直接建议"乘 10 用整型运算");A/B/C 盘基础 MP(7/0/2)、格位加成(1/1.5/2)、首 A 奖励 +3;10 种角色类型的攻击/受击 MP 率表;叠 C MP 倍率全表;各类 MP 技能的结算先后顺序及"当前 MP 是否过 100 会中途改变系数"这类有状态细节 |
| 技能触发机制 | 14 步有序的攻击结算流程(挑衅→目标列表→回避无效→雾系→回避→保护→伤害→赋异常→生死→攻击 MP→受击 MP→被攻击 MPUP→反击→追击);四种叠加语义(线性叠加/独立判定/最大概率/概率求和)各自适用哪些技能;Magia・Doppel・追击・反击各自跳过哪些步骤的明确清单 |
配套还有 状态异常(114 KB)、技能和状态效果列表、技能等级数值表、魔法阵形、 行动盘 等条目。
决定性的一点:wiki 与 API 用的是同一套 schema
把上文枚举出的 effectCode 逐个在 wiki 全文里检索,93% 的英文标识直接命中 (未命中的 6 个主要是 FORMATION_* 系,但其效果在「伤害公式」里以中文"阵形加成 [Ⅰ]=1.10/[Ⅱ]=1.15/[Ⅲ]=1.20"完整给出)。verbCode / effectCode / targetId 这些字段名本身也在 wiki 被引用上百次——其技能速查页是一段消费 master data JSON 的脚本,处理的正是 art/artId/effectValue/verbCode/effectCode/targetId。
这意味着 wiki 是基于数据挖掘、与游戏内部标识对齐写成的,因此 wiki 的公式与 API 下发的效果定义可以近乎 1:1 对接,不需要靠猜去做语义映射。
这把战斗那块的性质改变了:不是"靠模糊记载反推公式",而是"照规格实现 + 用真实语料验收"。
版本漂移风险很低:结构稳定,只动过系数
核心公式三篇里有日期标注的机制变更总共只有 3–4 处,且全是数值/常量微调—— Charge 盘基础系数(2020-11-02,旧值 0.8/1.2/0.8/1.2)、Doppel 发动 MP 与 MP 上限 (2020-12-15,200→150)、心魔战克制表(每次心魔战本就会变)、虚弱状态对多格 Boss 的生效范围(2023-11-18)。
从未改动过的是结构:14 步结算流程、四种叠加语义、乘法链的组成方式。 而且 wiki 正文给的就是最新值,旧值只作历史标注。因此这不是一个开放未知, 而是一组已枚举、已注明日期的数值差异——落地时只需确认复刻服的数据版本, 必要时用真实语料反查即可。
授权边界
wiki 是第三方社区作品。可以据其记载的事实(公式、系数、时序)自行实现, 但不得把其条目文本整段复制入库;引用需遵守该站授权条款。同理,其技能速查脚本 所依赖的 master-data JSON 镜像属外部仓库,按本项目的净室与外部仓库边界口径: 只作只读参考、不照搬、不再分发。
验收标准:对齐社区共识即可
这是整个 R3 里最该先立住的一条原则,因为它直接决定要花多少力气、以及"做完了" 怎么判定。
官方服务器已全部关闭,不存在一个可供逐位比对的权威运行实例。因此目标不是 "克隆那颗 .so 的行为",而是:
验收标准
实现的效果与社区 wiki 的记载没有差异 —— 因为那份 wiki 就是 社区对这套战斗系统的研究结论与共识。做到这一点,就意味着 复原出的游戏与社群共识完全相符,这已经够了。
这正是 Unix → Linux 的关系:Linux 不是 Unix 的克隆,而是按公开记载的接口与行为 独立实现的另一套系统;它从不试图与某个原始二进制逐位一致,却足以承担全部实际用途。 战斗引擎照此办理。
由此产生三个直接推论:
- 规范性倒置:wiki 是规范(normative)——它定义"正确";真实战斗语料退为 辅助交叉验证(advisory),用来发现 wiki 的空白或笔误,而不是最终裁判。
- ±5% 随机浮动不再是问题:既然不追求复现单次伤害,那个噪声下限就只是 "实现时要照样加上的一条规则",而非验证障碍。
- wiki 未覆盖处的处置方式明确:凡 wiki 沉默或自相矛盾之处, 选一个合理实现并记录下来即可(必要时用语料做旁证)。这是工程决策, 不是"缺规格"。
这同时是最干净的合规姿态
按公开的社区研究成果独立实现,全程不触碰引擎二进制——这比任何形式的 逆向或移植都更符合本项目一贯的净室口径。规格来自公开记载,代码完全自有。
两个把 R3 难度实质拉低的杠杆
① 不需要位级一致
服务端既没下发种子、也不收轨迹,只收聚合量并照单记账。因此 Web 端自行实现的战斗引擎,只要"合理、平衡",就能与服务端协议兼容—— 不必与原版逐点对齐。
协议层与验收层在此对上了
上一节的验收标准是目标层面的(对齐社区共识即可);这一条是协议层面的 独立佐证(服务端根本不校验)。两者指向同一结论:不存在任何一处强制要求 与原版逐位一致。于是"上线可玩"与"完美复刻原版"彻底解耦。
② 真实战斗语料 = 现成的交叉验证素材
采集数据里有 24,043 条 result/send 与 24,116 条 quest/native/get, 且三个端点按同一 userQuestBattleResultId 可对齐。于是能批量构造成对样本:
(完整战斗定义) → (真实上报的结算结果)
native/get result/send按上一节的验收标准,wiki 是规范,这份语料是旁证。它真正的用处有三个, 都不是"当裁判":
- 发现 wiki 的空白与笔误——若某类战斗的统计量系统性偏离,通常说明 wiki 在该处 有遗漏或写错,据此回头补规格;
- 判定数据版本——用来确认复刻服对应的是哪一版系数(见前文版本漂移);
- 回归护栏——实现改动后,跑一遍看统计量有没有整体漂移。
它做不到、也不需要做到的事
- 成对样本缺少玩家操作序列(打了哪些盘、什么顺序),无法逐帧比对;
- 伤害带 0.95–1.05 的随机浮动,即使公式完全正确,单次伤害也无法精确复现。
所以只应校验统计量与不变量(总伤害是否落在预期区间、回合数、剩余 HP、克制关系 是否自洽、钳制上下限是否被正确触发),不可当成"输入→输出"的确定性单测。 而按验收标准,这已经够了——语料对不上不等于实现错了,wiki 对不上才是。
已被降低风险的一块:2D 骨骼演出层
社区已有一份概念验证表明:战斗里的 mini Q 版立绘所用的 CocoStudio 装甲动画 (ExportJson + plist + png)可以直接被 cocos2d-html5(MIT)在浏览器 <canvas> 里渲染,走 ccs.armatureDataManager.addArmatureFileInfo → ccs.Armature 路径, 零格式转换——因为它与原生那颗 .so 里的 Cocos2d-x 是同族引擎。
这实质回答了"资产转换管线工作量"这个变量:对 2D 骨骼这一层,答案接近于零。
合规边界
上述只采纳技术结论(同族引擎可直接消费同格式资产)。该 PoC 附带分发了提取出的 游戏美术,这与本项目净室口径相冲突——不得照搬其资产、不得将任何提取出的 美术/音频/文本入库或再分发。本项目可做的是:自行实现渲染代码,资产由玩家本地 既有安装提供。
各子系统状态
| 子系统 | 状态 |
|---|---|
| 2D 骨骼演出(mini 立绘) | 基本证明可行:同族引擎直接消费同格式资产(见上节) |
| 战斗结算引擎 | 需自行实现,但规格/验收/稳定性均已落实(见上文) |
Live2D(moc3) | 有官方 Web 路径,且不在关键路径上——见下 |
CRI 音频(hca/acb) | 有两条明确解法,选哪条取决于合规口径而非技术——见下 |
| 剧情 CG/演出 | 脚本与时序是数据(JSON),.so 里只是播放器;缺口收敛为"完整指令集 + 表现层约定"——见下 |
Live2D 不需要"替代方案"
moc3 有官方第一方的 Web 运行时(Cubism SDK for Web),吃的就是同一份 moc3, 不需要格式转换、也不需要另找替代渲染器。它与"2D 骨骼层用 cocos2d-html5"是同一类情形: 官方同族实现已经存在。
而且从本仓库的资产清单看,它不在关键路径上:
- 仓库内
moc3/model3.json数量为 0(assets/resource/image_native/live2d/下只有 一个占位 PNG,另有assets/package/live2dViewer/的几个 UI JSON)——Live2D 素材来自 下载包,不随包附带; - 元游戏(R1)是 WebView 页面,不用 Live2D;
- 战斗演出用的是 CocoStudio mini 立绘,也不用 Live2D。
所以它既不阻塞 R1,也不阻塞战斗。
但剧情演出用得上
剧情脚本的 chara.face 指向 *.exp.json(Live2D 表情文件),说明剧情场景走 Live2D。 所以"不在关键路径"只对 R1 与战斗成立;做到剧情时,Cubism Web 运行时是要用上的 (见 剧情演出)。
需要落实的是授权:Cubism SDK 有其自身的 许可条款(含面向个人/小规模的免费档),必须按当期条款核实本项目是否适用—— 这是一个合规待办,不是技术未知。
CRI 音频不需要在浏览器里跑 CRI
浏览器端永远不需要 CRI 的运行时。有两条都成立的路径,区别只在合规口径:
| 路径 | 做法 | 代价 / 约束 |
|---|---|---|
| A 离线转码 | 把 hca/acb 一次性转成 opus/aac/ogg,浏览器用原生 WebAudio 播放 | 技术上最省事、运行时零解码器。但转码产物是派生音频——若由项目分发即越过"不再分发提取音频"的红线;若由玩家在本地对自己的资产转码则无此问题 |
| B wasm 运行时解码 | 把 HCA 解码器编译成 wasm,在浏览器里即时解码玩家提供的资产 | 保持"资产由玩家本地提供"的模型。HCA 是已被充分研究、有多个开源解码实现的格式,编译到 wasm 是常规工程,不是研究课题 |
一处更正:本作的 HCA 是加密的
不只是压缩——游戏内的 .hca 带密钥加密,需先解密再解码。这不构成障碍 (社区已有 HCADecoder/FastHCADecoder/Ishotihadus/hca 等现成实现, 浏览器端 Live2D 查看器也正是这样处理语音的),但两条路径都要多一个解密步骤, 不能按"普通 HCA"估工。
结论:这是资产管线的选型题,不是技术障碍
两条路都不涉及未知技术。选 A 还是 B,取决于项目想把"资产从哪来"这条线画在哪里 ——而这条线本项目已经画好了(资产由玩家本地既有安装提供),因此 B 更贴合现有口径, A 则适用于"玩家自行转码"的场景。
剧情演出:脚本与时序也是数据
这一项曾被记为"演出脚本与时序仍在 .so",同样是把位置搞错了。实测:
(一)Java 层完全不参与。 仓库 smali/ + smali_classes2/ 共 8874 个 .smali, 剧情相关类 0 个(按 scenario/story/adv/movie 检索命中的 7 个均为误匹配, 如 AdvertisingIdClient、PurchaseHistoryRecord)。
(二)脚本是声明式 JSON,就在资产里。 assets/resource/scenario/json/ 下的剧情脚本 结构清晰、字段语义基本自明(仅 schema,无任何台词/语音内容):
{ story: { group_N: [ step, … ] }, version: 2 }
step ├─ chara[] # 本步各角色的状态
├─ autoTurn # ★ 自动推进时长(秒)——时序就在这里
├─ autoTurnLast # ★ 末步停留时长
└─ se # 音效 id
chara ├─ id # 角色 id
├─ face # 表情文件(`*.exp.json`)
├─ motion # 动作序号
├─ pos # 站位
├─ voice # 语音 id
├─ cheek # 脸红档位
└─ effect # 特效 id一份 14 KB 的样本即含 75 个 group/149 步。
(三).so 里是播放器。 其只读串中 Story 相关约 2826 处、Scenario 约 373 处、 Movie 约 300 处——即"渲染角色、切表情/动作、播语音与音效、按 autoTurn 推进"的 解释器,而非剧情本身。
与战斗完全同构
"播什么"是数据(JSON),"怎么播"是播放器。 因此 Web 化要写的是一个 声明式脚本播放器,而剧情内容天然可移植——和战斗那条"服务端下发定义、客户端跑引擎" 的结构一模一样。
那个"播放器"具体是什么
把上面几项拼起来,.so 里那个剧情播放器的职责是可以列清的——它是一个 ADV(视觉小说)场景引擎,跑在 Cocos2d-x 之上:
| 职责 | 消费的东西 | 格式 |
|---|---|---|
按 group/step 顺序推进,按 autoTurn 计时 | 剧情脚本 | JSON(自明) |
| 驱动角色表情/动作/站位 | Live2D 模型 | Cubism(两代并存,见下) |
| 播语音与音效 | voice/se | CRI HCA(加密,见上节更正) |
| 合成背景与叙述框 | 故事背景、UI 框 | bg/story/bg_adv_*.jpg(普通 JPG)、assets/package/story/ 下的 blackFrame/sepiaFrame/narration 等 PNG |
Live2D 是两代并存,这影响运行时选型
引擎同时链入 Cubism 4 系 Framework(CubismCdiJson/CubismMotionJson/ CubismPhysicsJson/CubismModelSettingJson 等,符号约 1336 处)并支持 .moc3/.exp3.json/.motion3.json;同时也支持旧的 .exp.json(Cubism 2 系)。 资产相应分布在 image_native/live2d/(旧)与 image_native/live2d_v4/(新)。
而前文那份剧情样本里 face 取的正是 *.exp.json(旧格式)。因此 Web 端 可能需要同时具备两代 Cubism Web 运行时,或对旧资产做一次转换——这是上一节 "Live2D 有官方 Web 路径"需要补充的一个实际约束。
开源现状:播放器没人做,但部件都有先例
对社区项目做了一轮只读调研,结论分两半:
没有的:未发现任何开源的剧情/ADV 播放器实现。相关 GitHub 话题下也没有 (magireco / magia-record 话题里只有私服 capricieux、安装脚本、字幕时间轴工具等; Magi3Dviewer 是新作 Magia Exedra 的 3D 模型查看器,与本作无关)。
有的——恰好覆盖了最难的几块,且都是浏览器里跑通的:
| 项目 | 做了什么 | 对我们的意义 |
|---|---|---|
| magiLive2d | Pixi.js 4 + Cubism SDK2 WebGL,直接读 /magica/resource/image_native/live2d/,支持表情/动作/语音/鼠标跟随 | 本作 Live2D 资产在浏览器里渲染已被验证,连资源路径都和本仓库一致 |
| magireco-live2d-viewer | 另一个 Web 版 Live2D 查看器 | 同上,独立的第二个先例 |
| mgrcd-live2d | TypeScript/Deno;解析 scenario/json/general/ + live2d_v4/ + sound_native/voice/,产出 Live2DViewerEX 模型 | 剧情 JSON 的字段语义已被他人摸过,可作交叉验证 |
HCA 工具(HCADecoder/FastHCADecoder/Ishotihadus/hca 等) | HCA 解密+解码 | 印证上节 CRI 路径可行,且解密有现成实现 |
于是缺口收敛得非常具体
要写的只剩"编排层":按 step 推进、把 chara 状态映射成 Live2D 表情/动作调用、 触发语音与音效、按 autoTurn 计时、处理转场与 effect。 渲染、解码、脚本解析这三块都已有可参考的开源先例——编排层反而是其中最薄的一层。
注意口径:这些项目只作技术先例与思路参考,按本项目约定不照搬其代码(须自行实现); 它们也都明确标注"仅供私人使用、不得公开分发生成数据",与本项目 不再分发提取资产的立场一致。
但这一项的规格成熟度仍低于战斗,剩余缺口是实打实的
- 完整指令集尚未枚举。上表来自随包附带的样本(真实剧情来自下载包),样本里 没有出现台词文本、分支选项、背景/BGM 切换、镜头运镜等必然存在的指令。 好消息是:这是可做的数据分析——对真实剧情包的 JSON 做一次枚举即可, 方法与前文枚举
effectCode完全相同,不需要碰二进制。 - 表现层约定没有 wiki 级规格。转场、运镜、文字逐字速度、
effect各 id 的实际观感 等,社区 wiki 记的是战斗机制,不覆盖这些。这块只能靠观察与试错收敛, 是目前最缺外部规格支撑的一环。 - 剧情场景确实用 Live2D(
face指向*.exp.json表情文件)。这修正了上一节的 适用范围:Live2D 不在 R1 与战斗的关键路径上,但在剧情演出的关键路径上。
顺带发现:服务端信任缺口
这条与 Web 化独立,但更该尽早处理:既然战斗是客户端权威、无种子、无轨迹, 那么 result/send 可被任意伪造——伤害、通关、掉落都能编造,服务端目前无从校验。 唯一的弱信号是 nativeClearTime 与 serverClearTime 的对照。
这是今天就存在的问题,Web 化会放大它
它不是Web 化引入的:现有原生客户端同样如此。但 Web 端的 JS 可被直接审查与改写, 会把利用门槛降低一个量级。若复刻服在意这一点,应在服务端补:结算合理性上界校验 (伤害/回合/耗时与关卡定义的一致性)、掉落由服务端裁定而非采信客户端上报,等等。 相关客户端侧机制见 安全机制与防篡改。
候选路线(修订)
| 路线 | 覆盖 | 可行性 | 代价 / 风险 |
|---|---|---|---|
| R1 元游戏纯 Web | 菜单/商店/扭蛋/剧情文字/编队 | 高 | 把 NativeBridge/CnvBridge 换成纯 JS shim,直连复刻后端;战斗先占位或走"结算结果页"。最吃现有 WebView 积累,ROI 最高。不受本次修订影响 |
| R2 云流化整机 | 全游戏 | 高 | redroid/Genymotion + WebRTC,把真安卓客户端跑在服务器、推流到浏览器。本质是"远程真机"非移植;按并发付 GPU。魔纪战斗偏回合、对延迟宽容,适合过渡 |
| R3 净室重写战斗/CG | 全游戏(真 Web 版) | 中,工程量大但路径清晰 | 除表现层外还需实现整个战斗结算引擎——但规格是实现级的(社区 wiki,与 API 同 schema)、验收标准是"与社区共识相符"而非逐位复刻、另有两万余场真实战斗可作旁证。剩余风险集中在工作量本身与剧情演出的表现层约定(该处最缺外部规格);Live2D 有官方 Web 运行时、CRI 音频有两条明确解法、剧情脚本本身是数据,版本漂移风险亦低(结构未变、只动过系数) |
| R4 WASM 移植那颗 .so | 全游戏 | 很低 | 无源码、中间件无 Web 构建、性能不足。基本否决 |
修订后的推荐路径
Phase 0 侦察 ——【已完成】
└─ 结论:战斗客户端权威;2D 骨骼层可直接渲染;效果系统为有限指令集;
且社区 wiki 已提供实现级规格(公式/时序/叠加语义,与 API 同 schema)
Phase 1 R1:元游戏独立跑进浏览器,直连复刻服(风险低、见效快、最擅长)
Phase 2 两条并行可选:
R3-战斗:照 wiki 规格实现结算引擎(验收=与社区共识相符,非逐位复刻),
真实战斗语料作旁证:补 wiki 空白、定数据版本、当回归护栏
R2-过渡:云流化补齐"浏览器里能打全部"
并行 服务端:补结算合理性校验(见「服务端信任缺口」)综合结论
- 菜单层进浏览器(R1):大概率能成,是现有 WebView 能力的自然延伸,仍是 Phase 1。
- 战斗:客户端权威已确证,纯 Web 化必须自行实现结算引擎。但五个条件同时成立, 使它成为"工程问题"而非"研究问题":有界(效果系统是可枚举的有限指令集)、 有实现级规格(社区 wiki 的公式/时序/叠加语义,且与 API 同 schema、93% 标识直接对齐)、 验收标准明确且可达(与社区共识相符即可,不必逐位复刻——官服已全关,本无可比对的权威实例)、 规格稳定(历史上只动过系数,结构从未改)、协议不设约束(服务端不校验)。 定性上:这是"照规格实现一个回合制战斗引擎"——工作量实在,但路径清晰、无关键未知。
- 2D 骨骼演出层:风险已基本排除(同族引擎直接消费同格式资产)。
- Live2D:有官方 Web 运行时(同格式、无需转换)。不在 R1 与战斗的关键路径上, 但剧情演出要用;待办是核实授权条款,不是技术未知。
- CRI 音频:浏览器端不需要 CRI 运行时;离线转码或 wasm 运行时解码二者皆可, 选型由合规口径(资产从哪来)决定。
- 剧情演出:脚本与时序是数据(JSON)、不在
.so里,.so里是一个 ADV 场景引擎—— 与战斗同构。没有开源的播放器实现,但渲染(浏览器 Live2D,两个独立先例)、 音频解密解码(现成工具)、脚本解析(已有项目解析过同一批 JSON)三块都有开源先例, 要写的只剩编排层。仍是规格成熟度最低的一环:完整指令集需对真实剧情包做一次枚举 (可做,方法同effectCode),转场/运镜/文字速度等表现层约定没有 wiki 级规格, 只能观察试错收敛;另需应对 Live2D 两代资产并存。 - 短期"浏览器里玩全部":云流化(R2) 性价比最高,可作过渡。
- 移植 .so(R4):否决。
- 服务端:应独立补齐结算校验——该缺口现在就存在,Web 化只会放大。
数据来源与合规
- 流量类结论来自公开发布的真机流量采集数据集(日服,2024 年)与本地只读分析。
- 规格类结论来自第三方社区 wiki 的公开条目(MediaWiki 导出)的只读分析。
- 两份素材均不入库。文内只写端点、字段名、枚举值、计数规模、系数与钳制区间等 事实性描述——均为 schema/接口事实与公开记载的事实,不含任何账号标识、 玩家数据,也未整段复制第三方条目文本。
交叉链接
- 引擎子系统与"播放器 vs 数据"边界 → Native 引擎逻辑
- .so 不是数据库 / 战斗关卡 schema / 权威性判断更正 → 引擎数据契约
- WebView 前端、JS 桥、状态重放(R1 的基础) → WebView 拦截与状态重放
- 握手/API 与后端可控性 → 握手协议与云端接口
- 客户端侧防篡改机制 → 安全机制与防篡改
