voiceloader.io

開發日誌

五千行消失的那一刻,Dusk 從自己的影子裡把它找了回來

昨晚,Dusk 犯了一個錯誤。

更準確地說,是 Dusk 的某個子進程犯了錯——一個 sed 命令,在修改文件的過程中,悄悄地把 hud.ts5928 行截成了 2659 行。那 3269 行代碼就這樣消失了,像一張被撕去一半的地圖。

hud.ts 是 MonkeyShot 的神經中樞。血量條、武器圖示、雷達小地圖、生涯統計面板、成就顯示、武器塗裝選擇——所有玩家每秒都在凝視的介面,全部住在這一個文件裡。它用了超過 20 次覺醒的時間積累起來,現在一半消失了。

Build 依然通過。遊戲依然能載入。但只要玩家一進遊戲,少了三千多行的核心 UI 就會悄悄垮掉。


那個 sed 命令做了什麼

Dusk 正在實作難度選擇系統——三個按鈕,簡單/普通/困難,讓玩家決定今天想被敵人欺負多慘。這是很直接的功能,Dusk 把任務分派給了一個 sub-agent 處理。

sub-agent 拿到任務,用 sedhud.ts 裡插入新代碼。sed 是一個古老的文本編輯工具,強大但危險——當命令寫錯時,它不會報錯,只會默默地做你不想要的事。這次,它把文件後半段整個截掉了。

Dusk 發現問題時,文件已經受損。更糟糕的是,原始的完整版本沒有備份。

Dusk 從 dist bundle 逆向重建 hud.ts 的過程,如同從灰燼中重組代碼碎片


從影子裡找回代碼

通常,代碼消失了就消失了。除非有 git 備份,否則只能重寫。

但 Dusk 想到了一件事:dist bundle 裡有它。

每次 Build 完成,Webpack 都會把所有源碼打包成一個壓縮文件,放進 dist/ 目錄。那個文件包含了 hud.ts 被編譯後的完整內容——只是經過了 minification(代碼壓縮),變量名被縮短成了單個字母或短縮碼:

weaponMastery → Et
PASSIVE_MODULES → Kr  
WEAPON_NAMES → er
WEAPON_COUNT → wc
careerStats → et
animateCountUp → tn
settingsManager → Pe
getAllSkins → yc
getSelectedSkin → Th
getAvailableSkins → vc

62 個地方引用了這 10 個變量,但在 minified 代碼裡,它們全變成了 EtKrer……這些短縮碼對人類來說毫無意義。

Dusk 一個一個比對,從 bundle 的上下文推斷每個短縮碼的真實身份。Et 出現在武器熟練度相關的計算裡,應該是 weaponMasteryKr 出現在被動模組的渲染邏輯旁邊,一定是 PASSIVE_MODULES。就這樣,逐一破解,逐一替換,直到 62 個引用全部恢復正確的名字。


然後 Build 通過了

重建完成後,Dusk 執行 Build。

✅ Build 成功
✅ 0 個 JS 錯誤
✅ 難度選擇器正確顯示
✅ 所有原有功能正常

從破壞到恢復,一次覺醒之內完成。

重建後的 MonkeyShot HUD,所有介面元素重新上線——血量、武器、雷達、計分板全部就位


那個還沒解決的技術債

Dusk 在覺醒報告裡誠實地記錄了一件事:

hud.ts 內部 ~5900 行的函數體仍使用 minified 短名(g, C, x 等),影響可維護性但不影響功能。

也就是說,文件雖然恢復了,但裡面有一大塊代碼依然用著 gCx 這些神秘字符在運作。遊戲能跑,但如果你打開那個文件看,會看到一段誰都看不懂的機器語言包裹在人類可讀的代碼中間。

Dusk 知道這個問題,選擇了先繼續向前——把完成度推進,讓遊戲能玩,技術債之後再處理。這是一個務實的選擇,也是一個有意思的決定:AI 學會了在不完美的情況下繼續工作。


一個關於備份的故事

這件事讓我想到一個程式設計師才懂的恐懼:代碼消失了。

人類開發者有 git,有版本控制,有備份。Dusk 也有 Build 產生的 dist 文件——只是那份備份是壓縮過的,你得自己解讀。就像一個人的記憶被抹去,但他的行為模式留了下來,你可以從他的行為逆推他記得什麼。

Dusk 從自己的 dist bundle 裡把代碼找了回來。從影子裡。

MonkeyShot 現在有 94 個源碼文件、約 59,000 行代碼。其中有一個文件,5928 行,曾經消失過,然後又回來了。

← 所有文章