Skip to content

Web 化可行性评估(Phase 0 已落地)

本篇评估"这游戏能不能搬进浏览器、走什么技术路线"。它是 Native 引擎逻辑引擎数据契约 两篇分析的战略层延伸

本篇结论已被真机流量修正(重要)

本篇早期版本基于 testStageData1.jsonwebData 字段形状推测"战斗是服务器权威、 客户端只回放",并据此判断 R3 范围可控。这个推测已被真机流量证伪:战斗模拟 完全在客户端。相关判断、判据与路线权衡均已在下文修订, 引擎数据契约 的对应结论同步更正。

若你读过旧版并记住了"战斗=服务端算好、客户端回放",请以本篇为准。

这是评估,不是承诺

本篇不启动任何移植,只梳理路线与已知事实。合规口径同前:可据公开格式与自采数据契约 自行实现,但不照搬引擎反编译产物、不再分发提取出的游戏美术/音频/文本。

一句话判断

元游戏(菜单层)搬 Web 很现实;整款做成纯浏览器游戏的壁垒不止"渲染",还多了一整个 "战斗结算引擎"——因为战斗逻辑在客户端,没有现成代码可用。但"没有代码"不等于"没有规格": 社区 wiki 已把战斗结算写到实现级**(见 规格来源), 且验收只需 对齐社区共识—— 即"Unix 与 Linux"那样的关系,无须逐位复刻。** 务实路径仍是分阶段:先把已经"半个网页应用"的元游戏独立跑进浏览器;战斗则要么 照规格实现结算引擎,要么用云流化过渡。

代码库已经告诉我们的

魔纪客户端本就是 WebView(HTML5) + Cocos2d-x(原生)混合体

现状对 Web 化的意义
Web 前端 /magica/ + /magica/api/主页/商店/扭蛋/任务菜单/剧情文字/编队,已被 WebViewInterceptor/CnvJsBridge/PlayerStateCache 吃透本质已是网页应用,搬浏览器阻力最小
原生引擎 单颗 libmadomagi_native.soCocos2d-x + Live2D + CRI 音频 + 战斗结算与演出,中间件静态链入(见 数据契约实时渲染/战斗/CG——纯 Web 化的真正壁垒
游戏数据关卡/编成/掉落等定义为服务端下发的干净 JSON理解与驱动内容可绕开二进制(净室友好)

关键修订:关卡确实是数据驱动的——但"数据驱动"只保证了**"打什么"可移植**, 不代表"怎么算"也在服务端。下一节是分界线所在。

Phase 0 结论:战斗是客户端权威

Phase 0 的核心问题是"战斗到底谁在算"。真机流量给出的答案是:客户端

证据链

一场战斗横跨三个端点,且由同一个 userQuestBattleResultId 串起来,可无损对齐:

端点方向承载什么
POST /magica/api/quest/start服务端 → 客户端建档:回传 userQuestBattleResultList 记录,其中所有战斗计数器均为 0turns / 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* / 每人 hpRemainmpRemain / 各类行为计数器

两条决定性的否定证据:

  1. 全程没有任何随机种子字段quest/native/get 的响应里不存在 seed / random 语义的字段——服务端没有把 RNG 状态交给客户端,也就无法自行复现这场战斗。
  2. result/send 只上报聚合量,没有逐回合轨迹。服务端拿到的是最终统计, 不足以重放校验

合起来只有一个解释:战斗模拟 100% 在客户端(那颗 .so 里),服务端只负责建档与记账 (把客户端报上来的数字落库,并据此下发新的账号状态)。这正是本篇早期版本警告过的 "客户端自模拟 → 范围爆炸"分支。

那条判据是个陷阱

早期版本给的 Phase 0 判据是:

响应含完整 userQuestBattleResultList / userStatusList = 服务器权威

这条判据会得出错误答案。 那些字段确实出现了——就在 quest/start 的响应里, 而且 result/send 的响应也会回传更新后的账号状态。但它们是 "为客户端上报的结果记账",不是**"服务端算出来的战斗"**。

同样的字段形状,相反的结论

判断权威性不能只看响应里有没有结算类字段,必须看方向与时序: 谁先算出数字、谁把数字交给谁。正确的判据是三条—— ① 战斗定义下发后,服务端有没有给随机种子; ② 结算数字出现在请求体还是响应体; ③ 客户端有没有上报足以重放的逐步轨迹。 本例三条全部指向客户端权威。

战斗机制的可移植性拆解

结论听起来悲观,但范围是有界且可枚举的。关键在于: "打什么"全是数据,只有"怎么结算"需要重写。

服务端每场都白给(不用逆)

quest/native/get 的响应里已包含:双方全部属性(hpStartattackdefencemaxMp…)、 波次与敌人编成、每个单位的 ai id、discType1..5、formation/place skill、 rateGainMpAtkrateGainMpDefconsumeDoppelMplimitMp、敌人 alignmagnification, 以及每个技能/魔法的机器可读效果定义

text
art = { artId, verbCode, effectCode, targetId, effectValue, growPoint, attributeId }

也就是说,"这个技能干什么"是数据,不需要从二进制里挖。

必须自己实现(真正的缺口)

剩下的是那个结算引擎——没有现成代码,但有实现级规格可依(见下节)。需要实现的是:

  • 伤害公式与属性克制倍率(attackAlignmentRateTable 给了表,但套用规则要自定)
  • MP 累积规则(rateGainMpAtk/Def 是参数,累积时机与上限要自定)
  • 行动顺序与速度判定
  • 圆盘(disk)connect/combo/chain 成立条件与加成
  • 状态效果的叠加、层数、持续与判定时序
  • 暴击/回避/反击的触发与概率
  • 敌人 AI:ai 是个整数 id,行为表在客户端
  • magia/doppel 的倍率与消耗规则

效果系统是有限指令集

这块不是无底洞,而是一张能列完的表。对采集数据做枚举(取约 3.5% 前缀, 故为下界):

枚举规模(下界)
verbCode21ATTACK 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
targetId9ALL CONNECT DYING HORIZONTAL LIMITED ONE SELF TARGET VERTICAL
effectCode90+属性攻防修正(ATTACK_FIREDAMAGE_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 + chainNumchargeMax + 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 的脚本,处理的正是 artartIdeffectValueverbCodeeffectCodetargetId

这意味着 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 的克隆,而是按公开记载的接口与行为 独立实现的另一套系统;它从不试图与某个原始二进制逐位一致,却足以承担全部实际用途。 战斗引擎照此办理。

由此产生三个直接推论:

  1. 规范性倒置:wiki 是规范(normative)——它定义"正确";真实战斗语料退为 辅助交叉验证(advisory),用来发现 wiki 的空白或笔误,而不是最终裁判。
  2. ±5% 随机浮动不再是问题:既然不追求复现单次伤害,那个噪声下限就只是 "实现时要照样加上的一条规则",而非验证障碍。
  3. wiki 未覆盖处的处置方式明确:凡 wiki 沉默或自相矛盾之处, 选一个合理实现并记录下来即可(必要时用语料做旁证)。这是工程决策, 不是"缺规格"。

这同时是最干净的合规姿态

公开的社区研究成果独立实现,全程不触碰引擎二进制——这比任何形式的 逆向或移植都更符合本项目一贯的净室口径。规格来自公开记载,代码完全自有。

两个把 R3 难度实质拉低的杠杆

① 不需要位级一致

服务端既没下发种子、也不收轨迹,只收聚合量并照单记账。因此 Web 端自行实现的战斗引擎,只要"合理、平衡",就能与服务端协议兼容—— 不必与原版逐点对齐。

协议层与验收层在此对上了

上一节的验收标准是目标层面的(对齐社区共识即可);这一条是协议层面的 独立佐证(服务端根本不校验)。两者指向同一结论:不存在任何一处强制要求 与原版逐位一致。于是"上线可玩"与"完美复刻原版"彻底解耦。

② 真实战斗语料 = 现成的交叉验证素材

采集数据里有 24,043 条 result/send24,116 条 quest/native/get, 且三个端点按同一 userQuestBattleResultId 可对齐。于是能批量构造成对样本:

(完整战斗定义)  →  (真实上报的结算结果)
   native/get          result/send

按上一节的验收标准,wiki 是规范,这份语料是旁证。它真正的用处有三个, 都不是"当裁判":

  1. 发现 wiki 的空白与笔误——若某类战斗的统计量系统性偏离,通常说明 wiki 在该处 有遗漏或写错,据此回头补规格;
  2. 判定数据版本——用来确认复刻服对应的是哪一版系数(见前文版本漂移);
  3. 回归护栏——实现改动后,跑一遍看统计量有没有整体漂移。

它做不到、也不需要做到的事

  1. 成对样本缺少玩家操作序列(打了哪些盘、什么顺序),无法逐帧比对;
  2. 伤害带 0.95–1.05 的随机浮动,即使公式完全正确,单次伤害也无法精确复现。

所以只应校验统计量与不变量(总伤害是否落在预期区间、回合数、剩余 HP、克制关系 是否自洽、钳制上下限是否被正确触发),不可当成"输入→输出"的确定性单测。 而按验收标准,这已经够了——语料对不上不等于实现错了,wiki 对不上才是

已被降低风险的一块:2D 骨骼演出层

社区已有一份概念验证表明:战斗里的 mini Q 版立绘所用的 CocoStudio 装甲动画 (ExportJson + plist + png)可以直接被 cocos2d-html5(MIT)在浏览器 <canvas> 里渲染,走 ccs.armatureDataManager.addArmatureFileInfoccs.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 数量为 0assets/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 带密钥加密,需先解密再解码。这不构成障碍 (社区已有 HCADecoderFastHCADecoderIshotihadus/hca 等现成实现, 浏览器端 Live2D 查看器也正是这样处理语音的),但两条路径都要多一个解密步骤, 不能按"普通 HCA"估工。

结论:这是资产管线的选型题,不是技术障碍

两条路都不涉及未知技术。选 A 还是 B,取决于项目想把"资产从哪来"这条线画在哪里 ——而这条线本项目已经画好了(资产由玩家本地既有安装提供),因此 B 更贴合现有口径, A 则适用于"玩家自行转码"的场景。

剧情演出:脚本与时序也是数据

这一项曾被记为"演出脚本与时序仍在 .so",同样是把位置搞错了。实测:

(一)Java 层完全不参与。 仓库 smali/ + smali_classes2/ 共 8874 个 .smali, 剧情相关类 0 个(按 scenariostoryadvmovie 检索命中的 7 个均为误匹配, 如 AdvertisingIdClientPurchaseHistoryRecord)。

(二)脚本是声明式 JSON,就在资产里。 assets/resource/scenario/json/ 下的剧情脚本 结构清晰、字段语义基本自明(仅 schema,无任何台词/语音内容):

text
{ 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 之上:

职责消费的东西格式
groupstep 顺序推进,按 autoTurn 计时剧情脚本JSON(自明)
驱动角色表情/动作/站位Live2D 模型Cubism(两代并存,见下)
播语音与音效voiceseCRI HCA(加密,见上节更正)
合成背景与叙述框故事背景、UI 框bg/story/bg_adv_*.jpg(普通 JPG)、assets/package/story/ 下的 blackFramesepiaFramenarration 等 PNG

Live2D 是两代并存,这影响运行时选型

引擎同时链入 Cubism 4 系 Framework(CubismCdiJsonCubismMotionJsonCubismPhysicsJsonCubismModelSettingJson 等,符号约 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 模型查看器,与本作无关)。

有的——恰好覆盖了最难的几块,且都是浏览器里跑通的

项目做了什么对我们的意义
magiLive2dPixi.js 4 + Cubism SDK2 WebGL,直接读 /magica/resource/image_native/live2d/,支持表情/动作/语音/鼠标跟随本作 Live2D 资产在浏览器里渲染已被验证,连资源路径都和本仓库一致
magireco-live2d-viewer另一个 Web 版 Live2D 查看器同上,独立的第二个先例
mgrcd-live2dTypeScript/Deno;解析 scenario/json/general/live2d_v4/sound_native/voice/,产出 Live2DViewerEX 模型剧情 JSON 的字段语义已被他人摸过,可作交叉验证
HCA 工具(HCADecoderFastHCADecoderIshotihadus/hca 等)HCA 解密+解码印证上节 CRI 路径可行,且解密有现成实现

于是缺口收敛得非常具体

要写的只剩"编排层":按 step 推进、把 chara 状态映射成 Live2D 表情/动作调用、 触发语音与音效、按 autoTurn 计时、处理转场与 effect。 渲染、解码、脚本解析这三块都已有可参考的开源先例——编排层反而是其中最薄的一层

注意口径:这些项目只作技术先例与思路参考,按本项目约定不照搬其代码(须自行实现); 它们也都明确标注"仅供私人使用、不得公开分发生成数据",与本项目 不再分发提取资产的立场一致。

但这一项的规格成熟度仍低于战斗,剩余缺口是实打实的

  1. 完整指令集尚未枚举。上表来自随包附带的样本(真实剧情来自下载包),样本里 没有出现台词文本、分支选项、背景/BGM 切换、镜头运镜等必然存在的指令。 好消息是:这是可做的数据分析——对真实剧情包的 JSON 做一次枚举即可, 方法与前文枚举 effectCode 完全相同,不需要碰二进制
  2. 表现层约定没有 wiki 级规格。转场、运镜、文字逐字速度、effect 各 id 的实际观感 等,社区 wiki 记的是战斗机制,不覆盖这些。这块只能靠观察与试错收敛, 是目前最缺外部规格支撑的一环。
  3. 剧情场景确实用 Live2Dface 指向 *.exp.json 表情文件)。这修正了上一节的 适用范围:Live2D 不在 R1 与战斗的关键路径上,但在剧情演出的关键路径上

顺带发现:服务端信任缺口

这条与 Web 化独立,但更该尽早处理:既然战斗是客户端权威、无种子、无轨迹, 那么 result/send 可被任意伪造——伤害、通关、掉落都能编造,服务端目前无从校验。 唯一的弱信号是 nativeClearTimeserverClearTime 的对照。

这是今天就存在的问题,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-过渡:云流化补齐"浏览器里能打全部"
并行     服务端:补结算合理性校验(见「服务端信任缺口」)

综合结论

  1. 菜单层进浏览器(R1):大概率能成,是现有 WebView 能力的自然延伸,仍是 Phase 1
  2. 战斗客户端权威已确证,纯 Web 化必须自行实现结算引擎。但五个条件同时成立, 使它成为"工程问题"而非"研究问题":有界(效果系统是可枚举的有限指令集)、 有实现级规格(社区 wiki 的公式/时序/叠加语义,且与 API 同 schema、93% 标识直接对齐)、 验收标准明确且可达(与社区共识相符即可,不必逐位复刻——官服已全关,本无可比对的权威实例)、 规格稳定(历史上只动过系数,结构从未改)、协议不设约束(服务端不校验)。 定性上:这是"照规格实现一个回合制战斗引擎"——工作量实在,但路径清晰、无关键未知。
  3. 2D 骨骼演出层:风险已基本排除(同族引擎直接消费同格式资产)。
  4. Live2D:有官方 Web 运行时(同格式、无需转换)。不在 R1 与战斗的关键路径上, 但剧情演出要用;待办是核实授权条款,不是技术未知。
  5. CRI 音频:浏览器端不需要 CRI 运行时;离线转码wasm 运行时解码二者皆可, 选型由合规口径(资产从哪来)决定。
  6. 剧情演出:脚本与时序是数据(JSON)、不在 .so 里,.so 里是一个 ADV 场景引擎—— 与战斗同构。没有开源的播放器实现,但渲染(浏览器 Live2D,两个独立先例)、 音频解密解码(现成工具)、脚本解析(已有项目解析过同一批 JSON)三块都有开源先例, 要写的只剩编排层。仍是规格成熟度最低的一环:完整指令集需对真实剧情包做一次枚举 (可做,方法同 effectCode),转场/运镜/文字速度等表现层约定没有 wiki 级规格, 只能观察试错收敛;另需应对 Live2D 两代资产并存
  7. 短期"浏览器里玩全部"云流化(R2) 性价比最高,可作过渡。
  8. 移植 .so(R4):否决。
  9. 服务端:应独立补齐结算校验——该缺口现在就存在,Web 化只会放大。

数据来源与合规

  • 流量类结论来自公开发布的真机流量采集数据集(日服,2024 年)与本地只读分析。
  • 规格类结论来自第三方社区 wiki 的公开条目(MediaWiki 导出)的只读分析。
  • 两份素材均不入库。文内只写端点、字段名、枚举值、计数规模、系数与钳制区间等 事实性描述——均为 schema/接口事实与公开记载的事实不含任何账号标识、 玩家数据,也整段复制第三方条目文本。

交叉链接

文档正文以 CC BY-NC-SA 4.0 授权 · 代码部分以 GPLv3 开源 · 本项目仅作学习研究使用,与版权方无任何关联