
最近如果有在關注我做的
應該會發現一件事
只剩下靜態文字翻譯
SpiritVale 9/21 更新後
繁中化為什麼突然變得這麼困難?
以下說明有點長
看得懂就看 看不懂就當作講故事
以前看起來只是
找到英文 → 換成中文 的工作
到了 9/21 更新之後
突然變成了大量的
定位、掃描、測試、崩潰、回滾,再重新定位
甚至有些很單純的文字
例如
設定選單裡的一個 Channel、Default
或 角色面板上 的 STR、AGI
實際處理起來
可能比整張地圖名稱還麻煩
所以必須
找出畫面上的文字
到底是從哪裡來的
先講 9/21 到底發生了什麼
從玩家角度看到的是
Advanced Artifacts、Advanced Grimoires、Auction House
等遊戲內容更新
但從遊戲檔案來看
這次其實也是一次相當大的底層變動
9/21 SteamDB 記錄
Build 25431838
顯示 這次更新新增了
EACLauncher.exe、Easy Anti-Cheat、EOS Bootstrapper
也同時修改了
GameAssembly.dll、global-metadata.dat、sharedassets0.assets、globalgamemanagers、Addressables catalog
以及大量 client_assets_*.bundle
也將這個版本標示為
Update 0.32.0
這一點非常重要
因為對繁中化來說
問題並不是
加了 EAC 所以文字不能翻了
EAC 本身並不會讓
sharedassets0.assets 裡的
UTF-8 字串突然消失
也不是它把英文文字 加密 起來
真正的變化有兩個
第一個
是遊戲的大量
Unity/IL2CPP
資料重新建置
原本熟悉的
Object、offset、Addressables bundle、metadata
與 文字來源 關係都可能改變
第二個
則是加入 EAC 之後
我能不再把 DLL 注入
BepInEx、Harmony、Native Hook 這類
遊戲執行時修改程式邏輯 的 方法
當成繁中化方向
所以整個 繁中化 策略開始往
只碰遊戲本來就存在的 靜態資源
而且 盡量只修改 已經確認安全的資料
目前我的主要路線就是
sharedassets0.assets
靜態 RAW Byte Patch
有人可能會問
以前不是可以用 Python 腳本翻嗎?
為什麼更新後不行?
其實 .py 從來都不是關鍵
Python 只是分析和修改資料的工具
真正重要的是
腳本原本假設的 資料結構 有沒有存在
Python 沒有失效
失效的是以前的 假設
例如
以前如果已經知道
某個英文文字 → 某個 Localization entry → 某個 Object
那腳本 只要照這條路找到它
再替換內容即可
但 9/21 之後
發現一個問題
畫面上看得到的英文
不代表 sharedassets0.assets 裡
一定存在一個 可以直接修改的 同名文字 欄位
甚至 就算搜尋到了
也不代表 那個搜尋結果 就是 畫面真正使用 的 來源
這就是整件事情開始複雜的地方
"搜尋到字串" 和 "找到來源" 完全是兩回事
假設遊戲設定裡顯示
Resolution
最直覺的方法
就是打開 sharedassets0.assets 搜尋 Resolution
問題是我的掃描結果裡
Resolution 可以同時出現非常多次
再我的測試中
Resolution 就曾出現
7 exact serialized hits 以及 300 raw hits
這兩個數字代表的東西完全不一樣
exact serialized hits
這代表解析 Unity serialized data 之後
可以確認它是一個真正的 serialized string field
簡單講 就是
我知道這串文字是 Unity Object 裡的一個正式字串欄位
它比單純搜尋 bytes 的可信度高非常多
但即使如此
也還不能直接下結論說
"這就是畫面上的 Resolution"
因為不同 Object 裡可能剛好存在相同文字
raw hits 就只是
在檔案的某個位置看到這串 UTF-8 bytes
例如
52 65 73 6F 6C 75 74 69 6F 6E
可以解讀成
Resolution
但是這串 bytes 可能屬於真正的 UI 文字
但也可能是
Localization table、ScriptableObject、Debug 資料、
路徑名稱、模板、快取、Enum 名稱、
其他 Object 的內容
甚至
只是某個更大資料結構中的一小段
所以我在測試時特別把
exact serialized hit 和 raw-only hit 分開
raw 搜到
不代表可以 patch
這是 9/21 之後
我非常重視的一個原則
更麻煩的是
有些畫面文字根本搜尋不到
Settings UI Audit 有一個結果一開始讓我非常在意
有些明明就在設定畫面上的英文
例如部分 Display Mode、Hotkey、Skill 標籤
在 sharedassets0.assets 裡
Exact = 0
甚至
Raw = 0
也就是整個 sharedassets0.assets 根本找不到那串文字
這時候就不能再一直死搜那個英文
因為這已經是在告訴我
畫面上的文字來源
很可能不是一個靜態
存在於 sharedassets0.assets 的文字欄位
它可能來自 Addressables bundle
可能是 Enum 在 Runtime 轉成文字
可能從 Localization system 取得
可能由 Prefab/Template 建立 UI 時填入
也可能只是 sharedassets0.assets 裡保存了 UI 結構
而真正的文字來源在另外一個 bundle
這也是我後來從 搜尋文字 改成 追蹤文字來源 的原因
我做了一個測試
也就是先問 "這東西在哪裡?"
確認之後
才討論 "能不能改?"
最後才是 "要怎麼安全地改?"
這三件事情
現在完全分開處理
第一層
掃描真正的 Serialized String
Tracer 會先解析 sharedassets0.assets 裡的 Unity Object
不是只把整個 300 多 MB 的檔案當文字檔搜尋
而是辨認
Object、serialized field、string length、UTF-8 content
以及字串所在的位置
這樣就可以區分
這是一個真正的 Unity Serialized String
和 我只是在某個 binary 區域碰巧看到這串 bytes
這就是 Exact Hit 的來源
第二層
RAW UTF-8 掃描
接著還是會做 Raw Scan
原因很簡單
Unity 遊戲
不是所有有用資料都能靠目前的 schema 完整解析
所以 Raw Scan 仍然非常有價值
但我不再把它當成 Patch Target
而是把它當 線索
例如某個 Object 附近突然同時出現
Resolution、Display、Damage Numbers、Alarm、Summon
這時候真正有價值的
可能不是其中任何一個英文單字
而是
這幾個字居然聚集在同一區域
這代表這裡可能就是 Settings UI 的資料 Cluster
第三層
看 Neighbor 而不是只看命中的單字
把命中位置前後的資料一起留下來
單獨看到 Default 沒有太大意義
但如果看到的是UISettings、Popup、Panel_Right、Screen、Resolution、Default
那意義就完全不一樣了
因為現在我不只知道有一個 Default
我開始知道 它可能屬於哪一個 UI
第四層
從文字反推 UI Hierarchy
這也是 最重要的一步
後來我追到一些非常有意思的字串
UISettings: Popup > Panel_Right > Screen > ...
這已經不只是一般玩家會看到的 UI 文字
它看起來更像是 Unity UI Hierarchy/內部節點路徑
也就是 UISettings 下面有 Popup 再下面 Panel_Right 再進 Screen
這時候我就可以把搜尋方式從 找 Resolution
進一步提升成
找使用 Resolution 的 Settings Screen 結構
這兩種思路差非常多
也就是說,現在已經不是
在 300 MB 的 sharedassets0.assets 裡找一個英文單字
而是開始縮小成
這幾個 Object 很可能參與 Settings UI 的建立
而我要研究的是這個 Cluster 裡到底哪一層負責文字
這才是真正的 Source Tracing
為什麼我不直接把找到的地方全部改掉?
因為這正是 9/21 後
最容易出問題的地方
我後來做了非常多測試
結果證明
能找到 不代表能改
能解析 不代表改完能正常啟動
甚至能進遊戲 也不代表過一段時間不會崩
尤其 global-metadata.dat 在目前這個版本的測試中非常敏感
我已經做過 非常小的修改測試
結果仍然會造成遊戲崩潰
因此目前繁中化流程已經直接排除修改 metadata
大量 Localization Object 修改也出現過相同問題
甚至有些 DisplayName
看起來只是普通字串
而且替換後 Object 大小完全沒有改變
仍然可能造成 延遲崩潰
所以現在我的原則已經不是
可以翻多少就翻多少
而是
每一類資料先證明安全
再加入正式翻譯
甚至要做 Locator Probe
假設 STR 在檔案裡有5個候選來源
以前可能會直接把5個全部換成 力量
但如果遊戲崩了 我只會知道
5個裡面 至少有一個不能動
我還是不知道畫面 真正使用哪一個
所以我的做法是
Candidate #1
STR → P01
進遊戲看 沒變
就代表 #1 不是可見來源
恢復官方原檔
Candidate #2
STR → P02 再測
如果角色面板真的從 STR 變成 P02
定位完成
這種方式雖然很慢
但是它可以把 猜測 變成 實機證據
而且每一次只改一個變數
發生問題時 才知道是哪一筆資料造成的
RAW Byte Patch
為什麼反而變成我現在最信任的方法?
一般來說
如果有人在做 Unity Mod
可能會覺得直接改 Raw Bytes 很原始
但對我現在這個專案來說
它反而有一個很大的優點
我可以非常清楚地控制自己到底改了什麼
例如一個 3 bytes 的 STR
如果只是 Locator Test
我可以換成同樣 3 bytes 的 P02
整個檔案 Object size 不變
後面的 offset 不動
alignment 不變
其他 Object 不需要重新 serialize
這跟把整個 Unity Object 讀進工具
再重新輸出一次
是完全不同的風險
我不是在追求
最漂亮的修改方式
我追求的是
最少改動、可驗證、可回滾
這也是 9/21 前後最大的差別
以前我在想的是
這句英文要怎麼翻比較好?
現在我要先想的是
這句英文到底從哪裡來?
接著是
這個來源是不是畫面真正使用的來源?
然後
修改這個來源會不會改變 Object 結構?
再來
遊戲啟動會不會崩?
還要繼續確認
進入角色、切換地圖、開 UI
玩一段時間之後會不會延遲崩潰?
全部通過之後
最後才輪到
好 現在可以翻中文了
所以現在繁中化真正花時間的地方
不是 翻譯英文
而是 Source Tracing、Object 定位、Patch Safety 與實機驗證
哪個字串存在 存在幾次
哪一些是 Serialized Field
哪一些只是 Raw Hit
附近有哪些字串
屬於哪個 Object
能不能拼出 UI Path
哪些 Settings 文字甚至根本不在 sharedassets0.assets
有了這些資訊之後
我才知道下一個 Probe 應該測哪裡
而不是在幾百 MB 的 binary 裡面盲目替換
最後
9/21 更新並不是讓 繁中化 變成不可能
現在 SpiritVale 並不是完全不能做繁中化
地圖、部分 UI、技能/狀態、怪物、NPC、角色屬性以及很多靜態文字
我仍然成功找到了安全來源
只是已經不能再把所有文字都當成
English → 中文
然後大量 Replace
9/21 之後 我現在採用的方式比較接近
Screen Text → Source Trace → Serialized / Raw / Bundle / Runtime classification
→ Object / UI Path定位 → Single Candidate Probe → Crash Test
→ Visible Source Verification → Safe RAW Byte Patch
→ 正式繁中
也就是
先證明文字從哪裡來
再證明那裡可以安全修改
最後才翻譯
這就是目前 Yumi SpiritVale 繁中化的核心流程
為了解決其中最前面
也是現在最重要的一個問題
我眼前看到的這句英文
到底是誰把它顯示出來的
以前 翻譯是主要工作
現在 找到這個答案 才是最重要的

