# Migration from legacy packs This project is meant to replace legacy `.pck` or EterPack-style content delivery gradually, not through a single risky cutover. ## Target state - Linux builds produce `.m2p` - the client loads `.m2p` first - runtime master key delivery is required - silent fallback to legacy packs is disabled in production ## Suggested migration phases ### Phase 1: parallel loader - keep the legacy loader in the client - add `.m2p` support beside it - verify the new loader against real content sets - keep fallback only in development if needed ### Phase 2: pipeline validation - build `.m2p` from the same source tree as legacy packs - run `verify` for every archive - run `diff` between the source tree and `.m2p` - compare in-game behavior between legacy and `.m2p` ### Phase 3: runtime delivery - stop embedding a real content key in the client - deliver the runtime key through launcher, environment, or mapping - verify startup failure behavior when the runtime key is missing ### Phase 4: production cutover - package only `.m2p` for release clients - disable silent fallback to legacy packs - remove stale pack generation from release CI - keep extract/debug tools only for internal use ## Recommended checks - duplicate normalized paths - invalid relative paths - case-collision problems on Windows - decompression failures - manifest signature failures - key mismatch by `key_id` ## Practical migration loop 1. Pick one legacy pack group. 2. Rebuild it as `.m2p`. 3. Verify it. 4. Diff it against the source tree. 5. Boot the client with runtime keys. 6. Validate asset loads in logs and in-game. 7. Move to the next pack group. ## Confirmed startup-safe pack group The following startup pack set has already been validated against the real client runtime on the Linux VPS: - `root` - `patch1` - `patch2` - `season3_eu` - `metin2_patch_snow` - `metin2_patch_snow_dungeon` - `metin2_patch_etc_costume1` - `metin2_patch_pet1` - `metin2_patch_pet2` - `metin2_patch_ramadan_costume` - `metin2_patch_flame` - `metin2_patch_flame_dungeon` - `locale` - `uiscript` - `uiloading` - `ETC` - `item` - `effect` - `icon` - `property` - `terrain` - `tree` - `zone` - `outdoora1` - `outdoora2` - `outdoorb1` - `outdoorc1` - `outdoorsnow1` - `pc` - `pc2` - `guild` - `npc` - `monster2` - `sound` - `sound_m` - `sound2` - `monster` - `npc2` - `textureset` - `outdoora3` - `outdoorb3` - `outdoorc3` - `outdoordesert1` - `outdoorflame1` - `outdoorfielddungeon1` Validation method: 1. build each pack as `.m2p` 2. remove the matching legacy `.pck` 3. provide the runtime master key through: - `M2PACK_MASTER_KEY_HEX` - `M2PACK_KEY_ID=1` 4. start the Linux-built Windows client with `xvfb-run + wine` Observed result: - `PackInitialize` succeeded - Python startup succeeded - `app.Create(...)` succeeded - client reached `MainStream.SetLoginPhase()` For the world, audio, actor, and gameplay-adjacent packs in this list, the current validation level is startup regression smoke only. Full confidence for those packs still requires map-load or in-game coverage. The repository now also includes a scenario validator for common world packs: - `scripts/validate_runtime_scenarios.py` It verifies that selected `Outdoor*` maps reference valid `textureset` and environment assets across pack boundaries. It also now includes an actor/content validator: - `scripts/validate_actor_scenarios.py` On the current real client runtime, the full actor validator reports five data issues that look like pre-existing content inconsistencies rather than `.m2p` loader regressions: - `Monster/misterious_diseased_host` missing `25.gr2` - `Monster/skeleton_king` missing `24.gr2` - `Monster/thief2` missing `03_1.gr2` - `NPC/christmas_tree` missing `wait.gr2` - `NPC/guild_war_flag` missing `wait.gr2` Recommended next pack groups: 1. remaining startup-adjacent patch packs 2. remaining late-load gameplay content not covered yet 3. broader scenario-based validation for actor, effect, and sound content ## Risk notes - Do not mix silent fallback with production security claims. - Do not ship a client that accepts `.m2p` without runtime key enforcement. - Do not keep real secret keys inside the repository.