9.0 KiB
DEVLOG
Working log for the The I of the Dragon localization / HD project. Newest entries on top.
2026-09-20 — Accepted fixes and next-step plan
- User confirmed the tutorial prompt and option-title follow-up in game.
- Pushed fix commit
253cc47tocodex/fix-cjk-tooltip-layouton Gitea. - Added a prioritized implementation plan: tutorial display-text translation, an eight-texture 2x pilot, then validated 20–50 texture batches and chapter-by- chapter mission translation. The next-stage work is planned, not implemented.
- Plan:
docs/superpowers/plans/2026-09-20-high-impact-simple-first.md.
2026-09-20 — Center option titles and shorten tutorial exit prompt
- User confirmed the HUD tooltip fix in game.
- Original tutorial text was
\aOK - quit, Cancel - continue tutorial.; replaced the verbose literal Chinese translation with\a退出教程?. - Audio, game, video and controls titles all used fixed left x=620 before resolution scaling. Their panel/button center is reference x=640. At 1280px, the 24px Chinese controls title was consequently 20px left of the Bind button center. Title-only draw wrappers now measure actual text width and subtract half from the transformed x=640 anchor, after screen scaling.
test_cjk_titles.pyexecutes all four original title call sites with three text widths plus 1280/1920 screen-width cases. Both title tests and all 14 tooltip/layout tests pass. Game source patcher and translated Strings.dat are deployed locally; the user confirmed both fixes in game.
2026-09-20 — Fix Chinese HUD tooltip overlap
- Reproduced the reported world-map/minimap tooltip bug in the game's actual
x86 wrapped-text routine (
0x4ED380) using Unicorn. It builds a one-byte temporary string before measuring each character, so the existing DBCS metrics hook measured isolated GB2312 bytes as width/height zero. This miscentered Chinese lines and advanced the next line by only the 5px line distance, overlapping the 12px Chinese artwork. - Added pair-aware read, append, and fit caves to
tools/apply_cjk.py. GB2312 pairs now reach the measurer together, are appended/consumed together, and become complete-character wrap checkpoints. Initialized empty-line checkpoints correctly so mixed ASCII/CJK wraps retain the prior line height. A glyph wider than the available box is emitted intact rather than losing its lead byte; existing caller clipping remains responsible for box bounds. - Added
tools/test_cjk_layout.py: executes the real layout/measurement instructions and captures only the Direct3D draw boundary. Fourteen tests cover screenshot tooltip strings, shortcuts, centering, control codes, measure-only height, mixed text, whitespace, narrow boxes, and oversize glyphs. The original overlap case changes from(Chinese x=24,y=0; S x=20,y=5)to(Chinese x=12,y=0; S x=20,y=17)in a 48px box. - No atlas, translation, font-size, or mission-script changes are needed.
Original exe and patcher snapshots:
backup_game/font-layout-20260920/. Local deployed program:F:\steam\steamapps\common\The I of the Dragon\TheIOfTheDragon.exe.
Validation (requires unicorn):
python tools/test_cjk_layout.py --exe build/cjk-layout-fixed.exe -v
Progress audit: local HEAD matched Gitea ca57488 before this fix; 1884 texture
entries / 1882 preprocessed PNGs, 1397 geometry entries, and 479/496 translated
Strings.dat IDs. Mission scripts, description tables, baked text, and HD
upscaling remain separate unfinished work. Other-font CJK coverage is also
still limited as documented in patch-notes.md.
2026-09-20 — Full Strings.dat translation
- Translated the
Englishcolumn for 479 / 496 entries (the rest are pure-format strings, empty/whitespace values, the tutorial texture path, and a few odd key labels). tools/check_translations.pyverifies the printf specifier sequence (%s/%d/%i/%%) matches the English source exactly (0 mismatches) and that every value GB2312-encodes.tools/dump_all_strings.pydumps the source table tobuild/strings_en.json.
Known layout caveats (engine UI is tuned for the small Latin pixel font)
- Some engine UI positions tab/button labels against a box sized for English, so short Chinese labels can look left/right-aligned; a couple of centred dialogs jitter while a teletype reveal is running.
- In-game HUD button labels wrap and can overlap the shortcut hint because the boxes are small; to revisit via a smaller CJK cell/advance if needed.
2026-09-20 — Chinese in the main menu (first playable)
- Built
tools/build_cjk.py: renders the full GB2312 set (7445 double-byte codes) as 12x12 glyphs with simsun (crisp/binary, matching the game's pixel font) into a 2048x1024 TGA. The original 256x128 ASCII artwork is copied to (0,0), so all existingFonts.datrects keep working unchanged (verified byte-identical). Also emitscjk_glyph.bin/cjk_metric.bin. Advance/height = 12 (the UI font cap height is ~11-12px), drawn 1px up to fit the cell. tools/cn_strings.py+tools/make_cn_strings.py: translate theEnglishcolumn ofStrings.datto GB2312 (46 entries; escape-aware so\"%s\"formats survive).tools/install_cjk.py: one-shot deploy/restore (backs up exe/res/strings; rebuildsTextures.reswith the new atlas, drops the loose atlas, patches the exe and the strings).- Result: the main menu renders Chinese — 开始新游戏 / 载入游戏 / 选项 / 教程 / 制作人员 / 退出 / 载入上次存档:"…" — confirmed by the user on screen.
Fixed a byte-order bug in the metrics cave
The draw cave decoded the code as (first<<8)|second, but the metrics cave used
movzx eax,al; mov ah,[ebx+1] which produced (second<<8)|first. Every CJK width measured as 0,
so centred labels (the "Start New Game" button) were flushed right. Fixed to
movzx eax,al; shl eax,8; mov al,[ebx+1]. Centring is now correct.
Notes / next
- The menu button labels are dynamic (
Strings.dat) — the earlier suspicion of baked button images was wrong; the layer confusion came from the animated particle background. - Remaining UI text that is baked into textures (credits, tutorial pics) still needs redrawing.
- Next: translate the rest of
Strings.dat, scripts and*Description.dat; then HD textures.
2026-09-20 — Double-byte font patch proven
- Reverse-engineered the whole text pipeline (see
patch-notes.md). - Built
tools/add_section.py(PE section injection) and verified the patched exe still runs. - Built
tools/apply_cjk.py: assembles two code caves with keystone, adds a.cjksection, hooks the draw loop (0x4EACB0) and the metrics loop (0x4E8026). - Verified on screen: a GB2312-coded string
0xC1FA(龙) in a menu label rendered a 16x16 glyph at the mapped atlas position (green control test). Double-byte decode + render works. - Game files restored afterwards (exe SHA1
9EDB9B99...,Textures.resbyte-identical).
Next
- Big atlas (2048x2048): ASCII glyphs (copied) + CJK glyphs; re-point
Fonts.datTexture+ ASCII rects. - Generator for
cjk_glyph/cjk_metrictables from a chosen charset. - Convert
Strings.dat, scripts, and*Description.datdisplay text to GB2312. - Redraw baked-in text textures (menu buttons, credits, tutorial).
- Package: patched exe + atlas + data files.
2026-09-20 — HD texture preprocessing
- Cracked the
.resarchive format and builtres_unpack.py/res_repack.py(byte-identical round-trip once 16-byte alignment was found). - Extracted
Textures.res(1884) andGeometry.res(1397). - Built
preprocess.py(TGA/DDS→PNG, classification) andmake_plan.py. - Result: 63.6 Mpix, 1882 PNG, 0 failures. Plan: 1195 upscale / 499 tiling / 182 review / 8 skip (6 font atlases + 2 non-textures).
2026-09-20 — Cracking the .dat obfuscation
Fonts.dat/UnitDescription.dat/AIDescription.datdecoded:b"==" + XOR(plaintext, "GBDFYTNE"); key at0x620D18, decoder at0x4AE1D0.Fonts.datparsed: 4 font blocks, per-char atlas rects; parser keeps only the first byte ofCode(0x4EC168), so the stock engine is single-byte.
2026-09-20 — Initial findings
- Engine has a data-driven multi-language system: per-language folders for scripts/speech/video/UI
textures and language columns in
Strings.dat. - Text is externalized:
Strings.dat(499 entries, plain) and plain-text scripts. - First font test: replaced the
eglyph inShrift_gb_Germany.TGAand confirmed the atlas override works in game (rendered 龙 whereewas). - Investigated the "pirate build": PROPHET 2009 Topware release, languages EN/DE/PL/CZ/HU, no Chinese; its exe is identical to the Steam exe (no engine patch), so the Chinese build the user remembers was a different repack (not recoverable from it).
Decisions
- Do the localization ourselves (route B): patch the engine for double-byte text, build our own font atlas, translate only display text (never Ids / event names / unit types) to avoid trigger bugs.
- Keep the repository text-only; regenerate binaries from scripts (see
.gitignore).