From a9b31dec67020b985283ff4b794c43fa3ef6d7c5 Mon Sep 17 00:00:00 2001 From: shenlei Date: Wed, 23 Sep 2026 01:41:24 +0900 Subject: [PATCH] port 2D steps 3-4: strict 40250 asset gate with a provenance manifest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tools/asset_manifest.py records path/size/sha256 of pack/Index, every .eix/.epk and Eternexus/root/*.msm (audit/assets/40250-client.json). The gate script sets MT_ASSETS_STRICT=1, verifies the manifest, runs the native pack/proto tests and four Godot tests, and fails on a missing client, a mismatch or a skip. MT_40250_CLIENT now comes from the environment for the native tests too. remote_player_test accepts both weighted WAIT variants (wait/wait_1). PORT-PLAN §5 records the 2D status. Co-Authored-By: Claude Opus 5 --- audit/assets/40250-client.json | 1122 +++++++++++++++++++++++++++++ audit/history.jsonl | 1 + docs/PORT-PLAN.md | 30 + extension/src/port/CMakeLists.txt | 5 +- project/remote_player_test.gd | 4 +- script/run_40250_asset_gate.sh | 63 ++ tools/asset_manifest.py | 100 +++ 7 files changed, 1323 insertions(+), 2 deletions(-) create mode 100644 audit/assets/40250-client.json create mode 100755 script/run_40250_asset_gate.sh create mode 100755 tools/asset_manifest.py diff --git a/audit/assets/40250-client.json b/audit/assets/40250-client.json new file mode 100644 index 00000000..d5556d7d --- /dev/null +++ b/audit/assets/40250-client.json @@ -0,0 +1,1122 @@ +{ + "schema": 1, + "source": "40250 Server Client TMP4/Client", + "note": "path relative to the Client directory; regenerate with tools/asset_manifest.py generate", + "files": [ + { + "path": "pack/Index", + "size": 3414, + "sha256": "83ef51b625db77ea879da563490c308998faad8388c74114b39769e4420d245d" + }, + { + "path": "pack/BGM.eix", + "size": 268, + "sha256": "26a6ff3f0de276c5a26ac351fd1c5f0ec6924c0e65f210179b7580f4ad996ab4" + }, + { + "path": "pack/BGM.epk", + "size": 9334272, + "sha256": "495916dc7bae5371b21d8fbe2c77c8a1390a242eb79b0f988cd55a97d22b1a11" + }, + { + "path": "pack/ETC.eix", + "size": 36536, + "sha256": "970142375181e74c3df539a5674968caa328d378a3b62414a27a228ebc084ff5" + }, + { + "path": "pack/Effect.eix", + "size": 26476, + "sha256": "49b0ebdfa880631bd5aeb42f372e6b85545c34127f768ab250eb2a0eadbc6847" + }, + { + "path": "pack/Effect.epk", + "size": 3719424, + "sha256": "2819f81eb354eca2741b83ab9663dae8a689b24eef64c0e9033886c5c5de877e" + }, + { + "path": "pack/Etc.epk", + "size": 37156586, + "sha256": "e56b583e2630c25213fd19a76fd1db0713393a470eba6837d3f7660e885be561" + }, + { + "path": "pack/Monster.eix", + "size": 89196, + "sha256": "b7a53329dc1e342babe7cc5db3179e24f3bda9f70958eb02009e18bdd77b5e7f" + }, + { + "path": "pack/Monster.epk", + "size": 65224960, + "sha256": "07d28f3efecfc9d097efe70bf14ee35deabd243616206e5c8c9c63aed23152a5" + }, + { + "path": "pack/NPC.eix", + "size": 24708, + "sha256": "508c516150b1acada0d25dbfc43051d6394f611e75c403e73cc2a7a34cfac443" + }, + { + "path": "pack/NPC.epk", + "size": 21501440, + "sha256": "5fa1ccdf15297230573feb029c50c2cbb28311cd70ebfb8b0b6ad72f194541aa" + }, + { + "path": "pack/Outdoor.eix", + "size": 6452, + "sha256": "83ab1db8fb55a3b8477829a9bda6ef476fc77ac232f1810d4286e3aabe17e240" + }, + { + "path": "pack/Outdoor.epk", + "size": 2511360, + "sha256": "8ee6a0f94aca966424b0fe8d1105e3aa629b33517ab0c97f6b7848870377d382" + }, + { + "path": "pack/OutdoorA1.eix", + "size": 5368, + "sha256": "c47a5686aa810fa758f94919effe67d5154bd1e51d60464af108cf3886ba6751" + }, + { + "path": "pack/OutdoorA1.epk", + "size": 1652736, + "sha256": "b966af16ac20cfdf334ff4a44e484af18218ebc01ab4bb396dd4ae4762f55092" + }, + { + "path": "pack/OutdoorA2.eix", + "size": 10180, + "sha256": "ef9fee28a89f2ab3a18cce5bb6a324342f3815a385f818b72d3ed39235607803" + }, + { + "path": "pack/OutdoorA2.epk", + "size": 2888704, + "sha256": "10a92793e3bdeb4e7c5e88d032a1ccb2bf6354a650d3e04ca4335076475053a0" + }, + { + "path": "pack/OutdoorA3.eix", + "size": 4788, + "sha256": "a2dd1f2457ae151fd8914c2a001cdb4c2643f2e87677e20deb896d0c1763d06b" + }, + { + "path": "pack/OutdoorA3.epk", + "size": 1303296, + "sha256": "436869dbd0b9c4b45666d828e4bd061b64217f6caa06dbdb045ce5a5a3feca62" + }, + { + "path": "pack/OutdoorB1.eix", + "size": 6524, + "sha256": "2bbd9b547ab6719f4ae5605aa9f1606693fe6675a9efd7bb860422b0f3d70fd1" + }, + { + "path": "pack/OutdoorB1.epk", + "size": 1995264, + "sha256": "ceb9838020c0b829562365aef534ef9fe44553b650fba6c4cc4bd7dcd0fee013" + }, + { + "path": "pack/OutdoorB3.eix", + "size": 5468, + "sha256": "f2403679b143b1c2ece6183cbb72d5ab3de817406a9f7cf19910e67ec6126e7f" + }, + { + "path": "pack/OutdoorB3.epk", + "size": 1964288, + "sha256": "e9b1a280d1515e2065df2e636af310b1d7b3827351249a414a4c9b5daa3d4bd8" + }, + { + "path": "pack/OutdoorC1.eix", + "size": 5780, + "sha256": "399f5a9efbd944fc6c656bd58fef1b9dab4d2deaf9e0a1633087572d979154e0" + }, + { + "path": "pack/OutdoorC1.epk", + "size": 1331456, + "sha256": "1cedf1621866155d0920dc6f490a38ff15111e678407a523fb74c32e7e25e28b" + }, + { + "path": "pack/OutdoorC3.eix", + "size": 4796, + "sha256": "ecb91aaa0a9c3cdc10c0e4d12b606459f6bd399284fec2994062238343ac80e2" + }, + { + "path": "pack/OutdoorC3.epk", + "size": 1254144, + "sha256": "b0dbd42aae2759ec9160d1a64f9603662a589cea4210091bc8a10668d71721df" + }, + { + "path": "pack/OutdoorSnow1.eix", + "size": 9980, + "sha256": "e3075dae411537dc86606181142dd983bdbbc33ac7f2a6e9c47ac6871cf0d0b1" + }, + { + "path": "pack/OutdoorSnow1.epk", + "size": 2994176, + "sha256": "aa4bdfddd509ca0c7e3c533dd7fed36989022ef098a44452dda099e47287a263" + }, + { + "path": "pack/PC.eix", + "size": 79840, + "sha256": "0ff13aab4d9616b688683c7300a4522b476a7582783bae3c129a327d7ed5ce50" + }, + { + "path": "pack/PC.epk", + "size": 67204864, + "sha256": "ca418f722249f77f01c01364ca2c755970a0f64fb6342997a4fe963080013c8a" + }, + { + "path": "pack/Property.eix", + "size": 36816, + "sha256": "51b1bba303872af797d8aef55a3a4b05ed36355d886055313571f5af98e7fac3" + }, + { + "path": "pack/Property.epk", + "size": 340992, + "sha256": "f2d3cc495d5015d41e0aa8d663bea5cde008df204c141ffd591d9cd065df4915" + }, + { + "path": "pack/Psyco.eix", + "size": 116, + "sha256": "1f011bd49cc7ed667fce3b33989f713c6f00ebf1b8175bff9dfd0b195b9b45f7" + }, + { + "path": "pack/Psyco.epk", + "size": 0, + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "path": "pack/Sound.eix", + "size": 32100, + "sha256": "da4dcd285a3fa5d528d01fb54861c943030721353ba2a70f65ffb6ed62eb305a" + }, + { + "path": "pack/Sound.epk", + "size": 50380544, + "sha256": "8fbb8195ea53e293e49773f53c7c74def66b95035683c932ce68591b96519dde" + }, + { + "path": "pack/Terrain.eix", + "size": 9004, + "sha256": "9c2a8035a01fff26f519a2f8ec9308b68f063a9e0b8bacfed8b852d3959e0a24" + }, + { + "path": "pack/Terrain.epk", + "size": 10716416, + "sha256": "83f5e8a6d7a44806f438cfbe2963a3c1a3accdbfd79152cf8e33d99e3f01c3f4" + }, + { + "path": "pack/Tree.eix", + "size": 4588, + "sha256": "39067386bc3d15a1ced5058eceaff021dd6a5ee2a29ad99b1d4d48ab7e77ec4d" + }, + { + "path": "pack/Tree.epk", + "size": 3719424, + "sha256": "24aba26cf6e432a1febc8d3d4350c99152a24717ca8da99a765cb282ef6e9d49" + }, + { + "path": "pack/Zone.eix", + "size": 96244, + "sha256": "bf373237b5a20c3261912559b9eb234c30a8793bf49c58169a0995afecb75417" + }, + { + "path": "pack/Zone.epk", + "size": 93092608, + "sha256": "7def9a89205830bb50c03cad39e3caa1fcac3a7b8f381f1cb0e91036d8004270" + }, + { + "path": "pack/guild.eix", + "size": 6292, + "sha256": "aa01e0db4bc731fe2ed550b7e8f28860e5f380647645a9d29b5cb31f03795428" + }, + { + "path": "pack/guild.epk", + "size": 6400512, + "sha256": "431781fee47fac8a4ed376c979837880d2b6c10ffcedadc410ffe57ef2623227" + }, + { + "path": "pack/icon.eix", + "size": 53484, + "sha256": "6eec99582fba16e7eac2dcbad6288a4d871cfc0e7e0eb8f7a2141fe039bb7253" + }, + { + "path": "pack/icon.epk", + "size": 5232640, + "sha256": "37602eefca09d05659dd9826cbee7229067fc7af97bb80a4fa09d284b9f36813" + }, + { + "path": "pack/indoordeviltower1.eix", + "size": 2340, + "sha256": "a8cf23eb305b9e78fe16d05f6a15865943af0add01ee45ace2257041fb701e42" + }, + { + "path": "pack/indoordeviltower1.epk", + "size": 93184, + "sha256": "d5b17ab90311c70d9993c439a97788d7212f90ae7dfee1deb77535384311e5a0" + }, + { + "path": "pack/indoormonkeydungeon1.eix", + "size": 2516, + "sha256": "57d08f92cab141b8ef88cda56399746b87c8e8ff022dcbbb49ca781afc895796" + }, + { + "path": "pack/indoormonkeydungeon1.epk", + "size": 113152, + "sha256": "6c0ec032c9b2a265663a88440409adeebcf09e07b8f1f24f90ededb82808eed6" + }, + { + "path": "pack/indoormonkeydungeon2.eix", + "size": 2492, + "sha256": "bb7d3aaa747fb544ac5b3859b455685d9ca7d72dd88ebec1931401e9eb0034bf" + }, + { + "path": "pack/indoormonkeydungeon2.epk", + "size": 129024, + "sha256": "84ffcbbff791c7d17dc9eda8e688460f77cbe272534b4884ff0abce29cb9314e" + }, + { + "path": "pack/indoormonkeydungeon3.eix", + "size": 2532, + "sha256": "0e74137f9428040d8011c10ecf8388812da23a69df7e8a724ffdf8b7e800d093" + }, + { + "path": "pack/indoormonkeydungeon3.epk", + "size": 127488, + "sha256": "cf3da30348841d27b0b6a345538bfeb4446b59d9342c6adab97bb88e554335db" + }, + { + "path": "pack/indoorspiderdungeon1.eix", + "size": 2396, + "sha256": "2f2455dcccc1ded86cf78bbfb895d0fa49127550a58e3340e0f625b02e8651d8" + }, + { + "path": "pack/indoorspiderdungeon1.epk", + "size": 64768, + "sha256": "2eda281ce9ea2874f66934707a1acb7a3b28c9380f541eec70752a428b2f9456" + }, + { + "path": "pack/item.eix", + "size": 53404, + "sha256": "9f8bd1aa9e49771a8e413603f110761144745e8aff9fa7df6e4f871d154375d6" + }, + { + "path": "pack/item.epk", + "size": 5949440, + "sha256": "965671dcdaf6aa41e3f18862038591035a6d69bfe0ac67f4ce4d7f98c14cd8a7" + }, + { + "path": "pack/locale_cz.eix", + "size": 6888, + "sha256": "eec7862280c92e56f3038146068c20f593389845b8b80dc86f3897400c2d6861" + }, + { + "path": "pack/locale_cz.epk", + "size": 3728128, + "sha256": "1ec8f76be9000a5c413ee52b608565821c8d9a99ad208af75a1de2dde7896885" + }, + { + "path": "pack/locale_de.eix", + "size": 7040, + "sha256": "a8ead505eb52b75cdaafd2b8cd4b01c2d671dc214f6e09fc406ed5c19f6df24a" + }, + { + "path": "pack/locale_de.epk", + "size": 3886848, + "sha256": "3e367de75e75d10ff13d26886d2053fc24645f63070781c3d30e22bb385bc4e9" + }, + { + "path": "pack/locale_dk.eix", + "size": 6880, + "sha256": "46b7769c6954b87ea156bf3678a628d08b93c4e33dfd6e21fd7261a26e5e7220" + }, + { + "path": "pack/locale_dk.epk", + "size": 3699968, + "sha256": "3dd0ed4f902a6b905a5681d5130fcd26cc812699bea8858cc74b891c0ea05503" + }, + { + "path": "pack/locale_en.eix", + "size": 6856, + "sha256": "9882956d80d2ba8999a8c3a5a6df95f47e7c444ad32331d4839216061e885af2" + }, + { + "path": "pack/locale_en.epk", + "size": 3703296, + "sha256": "366b64f403d974c75763ac901e685033bc88b4ce102c5f3c9e7fc02499b98950" + }, + { + "path": "pack/locale_es.eix", + "size": 6872, + "sha256": "9a7e0568c187c89fb8fea46f3ca3c3f5372eb15fdfab4c3e9000d40c024e87d8" + }, + { + "path": "pack/locale_es.epk", + "size": 3715584, + "sha256": "b2147c6ab587269456b2dc88967b2a2fa8c0b309cdccbfb95fb84f325b91ebfa" + }, + { + "path": "pack/locale_fr.eix", + "size": 6960, + "sha256": "124b8573fa1dca0d94880e94b824ee749e6646496a837289bc7dc1b2c4870d98" + }, + { + "path": "pack/locale_fr.epk", + "size": 3753472, + "sha256": "17488500a4fce5bce298f49789850a98e8ce25c083f37f39ff4bdd911bbfd208" + }, + { + "path": "pack/locale_gr.eix", + "size": 6992, + "sha256": "c2c3c95e55760507a66701070922400e190d2ffa0b0342d96dc9041b5f360eaf" + }, + { + "path": "pack/locale_gr.epk", + "size": 3728128, + "sha256": "4f91907521776a493db62d414a230cfa3016b8a8784f794aa724c77f3c1c1eeb" + }, + { + "path": "pack/locale_hu.eix", + "size": 6856, + "sha256": "a519569266dc711ee291369a26207057bf9d97bb31cb93bb5fef2f2dec634764" + }, + { + "path": "pack/locale_hu.epk", + "size": 3702016, + "sha256": "393f379bde2ef8a6b60c13a3dcd7450139ae5a244f4283e02cc10536d2133b16" + }, + { + "path": "pack/locale_it.eix", + "size": 6856, + "sha256": "3a0455161e21e2b5ab4cfda142119626a2b156109a0ad6ef0ca63b27167dae19" + }, + { + "path": "pack/locale_it.epk", + "size": 3723520, + "sha256": "0c4ada6b48a73b0a9128e4deea5f743728e98c2df6c841183a27d782ba09e74b" + }, + { + "path": "pack/locale_nl.eix", + "size": 6888, + "sha256": "a13810d95d2437887875ee6a3e1c1eca8f23dea8695738d8675f291ee2315699" + }, + { + "path": "pack/locale_nl.epk", + "size": 3768320, + "sha256": "5425e84a0f56eae636f46ac449a21e6a9838cba07407cbcef0dbf6ea530232b3" + }, + { + "path": "pack/locale_pl.eix", + "size": 6856, + "sha256": "c18c9cfd4597cf0e4bf16bd263b45bf53034960e134ac47d80e034a97260540e" + }, + { + "path": "pack/locale_pl.epk", + "size": 3731200, + "sha256": "6b136fbfe144dff86b064e5c2983196ceabd90583fe73bf3aa017602f7f8efc9" + }, + { + "path": "pack/locale_pt.eix", + "size": 6864, + "sha256": "ecdc7be3301719036c9d6a1004c8d3ee9a9b7a224a556eec5e730af78f1bb8c9" + }, + { + "path": "pack/locale_pt.epk", + "size": 3719936, + "sha256": "b832d2c8686cf580ca45b2f24ee47832bec1dc705996548a458742e3c8590949" + }, + { + "path": "pack/locale_ro.eix", + "size": 6888, + "sha256": "ec80ce131093300ea899b7aef9f0cdc865cf097523701b5fd2b102f19152e455" + }, + { + "path": "pack/locale_ro.epk", + "size": 3724544, + "sha256": "ca3b02bfd4568d93438b72745c502876b59333ad434f9749dc57b4caeefd7d37" + }, + { + "path": "pack/locale_ru.eix", + "size": 6880, + "sha256": "c92691c2714aff1e6b027e8c92e676a77f3da0d5481dcfc563cde75bedfe120e" + }, + { + "path": "pack/locale_ru.epk", + "size": 3728384, + "sha256": "2e1ac1afff3ceb3e4ac73616557b14ea817252551f92efc6f0e2f7ccffd7be57" + }, + { + "path": "pack/locale_tr.eix", + "size": 6928, + "sha256": "d472ba322922e64a192aef8d825b74d11c3b1399e205dac7c5ae7ea4e6816458" + }, + { + "path": "pack/locale_tr.epk", + "size": 3705088, + "sha256": "cb62c431d7fa60e81d4010eb2a3bef1e5faf433a0155a479b36f8272383ad2d1" + }, + { + "path": "pack/metin2_patch_5th_armor.eix", + "size": 2568, + "sha256": "723268e62f9a7b6b36597b412bdbdd83faaf5a22afca4a04f7a521c9bf0eb7b4" + }, + { + "path": "pack/metin2_patch_5th_armor.epk", + "size": 7757795, + "sha256": "9bdb849a3ca99b28ae13005af696c132f83fe3c9ea08fb32bee65cd5d6cd3a19" + }, + { + "path": "pack/metin2_patch_costume_soccer.eix", + "size": 15120, + "sha256": "836dc3d6afe31d749e7df0f3924ffb3c0dfc2882800adea502087c6913bdb539" + }, + { + "path": "pack/metin2_patch_costume_soccer.epk", + "size": 91509599, + "sha256": "8ec1631d2b5f68b3e834a1e1bc8316579a03bfbde7176c80afdd5af1fb989ee7" + }, + { + "path": "pack/metin2_patch_dance.eix", + "size": 1000, + "sha256": "e5194f158f4b73c595f5c8881e4fd3cb1afdcd38aaa1763895b1c3ed85eaf638" + }, + { + "path": "pack/metin2_patch_dance.epk", + "size": 7745752, + "sha256": "50fedd6dcc16657a78eb119bb026c76d6cc41a19e1879e62299cb80cc92b1ef7" + }, + { + "path": "pack/metin2_patch_dragon_rock.eix", + "size": 43416, + "sha256": "9e89aad05a7afe01976ec328caf20371d4e5f3330157e73e3623af53b3b53ec9" + }, + { + "path": "pack/metin2_patch_dragon_rock.epk", + "size": 55554921, + "sha256": "50f7c69313ac3d5542a15cf379f7adc889599d82244bc3dcf626907daa00fd3b" + }, + { + "path": "pack/metin2_patch_dragon_rock_mobs.eix", + "size": 72456, + "sha256": "d708b4630d7e3ed39a7233e0787a4f4665fc168a8754447f2c8d62be7507cd84" + }, + { + "path": "pack/metin2_patch_dragon_rock_mobs.epk", + "size": 61838028, + "sha256": "3e23cb361100fdf249e2098ecdb232f2b7012fb833dc4fecae9a3c641bf76f0d" + }, + { + "path": "pack/metin2_patch_dragon_rock_mobs_texcache.eix", + "size": 4352, + "sha256": "71a4e2ff3ac7e095c44c169b519dafa73a2e7ca91ac8ebcb39f9ab8a2b779cc0" + }, + { + "path": "pack/metin2_patch_dragon_rock_mobs_texcache.epk", + "size": 17801408, + "sha256": "2ab134a1c1b2591e9f7e35cb9429f5f23f2886741afc71de21c9f2149062b891" + }, + { + "path": "pack/metin2_patch_dragon_rock_texcache.eix", + "size": 11840, + "sha256": "24f11e294c39e82d1e02b38d4edd819312aa3061ee511918f08a4c6d5dade716" + }, + { + "path": "pack/metin2_patch_dragon_rock_texcache.epk", + "size": 47697152, + "sha256": "0fa93a986bf4d5b853688a1610d78b390f6a5c7e3422fff8877dc8c6e3381bca" + }, + { + "path": "pack/metin2_patch_ds.eix", + "size": 5136, + "sha256": "868ac79ad2695b8e504d6550c8e030aaf578792a8827d4f55eb3ce777ea455ff" + }, + { + "path": "pack/metin2_patch_ds.epk", + "size": 1769171, + "sha256": "05a24cdf196b0cd4a2c07f0875da59be405134eacd2331b76784378352296c6e" + }, + { + "path": "pack/metin2_patch_dss_box.eix", + "size": 2720, + "sha256": "d722f67ba8bea1884594701ddfacae72cc54e931e7f75aa9a37e6bb43d60e7a9" + }, + { + "path": "pack/metin2_patch_dss_box.epk", + "size": 529060, + "sha256": "e7bf02ccca26213054510c8be8010d9cd621b538fe070fa92fa0bbe8e2182239" + }, + { + "path": "pack/metin2_patch_easter1.eix", + "size": 3184, + "sha256": "3882b9f4b1b4120ee50acc03893e115411b89fda27f8282d9902d63985fc3f71" + }, + { + "path": "pack/metin2_patch_easter1.epk", + "size": 7513344, + "sha256": "2c9edf12cda52e1503b13ea4b45327ce33f05ad13082b86d0a7b3db095eb87bb" + }, + { + "path": "pack/metin2_patch_etc.eix", + "size": 13408, + "sha256": "9416df91531cc012618fcd8bba0cb354ac638111763eca2802c0afaeb4fd4267" + }, + { + "path": "pack/metin2_patch_etc.epk", + "size": 5842764, + "sha256": "6bec41b9ff3e94cb99bf282912fa24b97991225726e67024b52bcd2af479e4f9" + }, + { + "path": "pack/metin2_patch_etc_costume1.eix", + "size": 7224, + "sha256": "51307dbdb89621e19a21677fa2dad528c6f70ca3b6b238d20bed0958d1e1e2e3" + }, + { + "path": "pack/metin2_patch_etc_costume1.epk", + "size": 16445038, + "sha256": "5624a04f20f5cf9b9d3b7974cca0072a1c2a6350b8e37589eeca272410be6b33" + }, + { + "path": "pack/metin2_patch_eu3.eix", + "size": 40440, + "sha256": "53cd6f949df392c5ca2e0615e0624026cbb827462a63f5d95ddc7e92d38bd4fb" + }, + { + "path": "pack/metin2_patch_eu3.epk", + "size": 32184576, + "sha256": "7d487c7cde676cd54d3251998514eba29e4df25f6ebb3d98d17f66e6911c558d" + }, + { + "path": "pack/metin2_patch_eu4.eix", + "size": 5112, + "sha256": "da873faa7fb65ac8e152b2137eecd44b080690b0a77ea853fc1d06fbb3cd60f7" + }, + { + "path": "pack/metin2_patch_eu4.epk", + "size": 10767104, + "sha256": "1e8f07ac9ffd03166ac92567ec937f452bb9834301f0c273531cdd61555c3694" + }, + { + "path": "pack/metin2_patch_flame.eix", + "size": 10120, + "sha256": "6f699ad2687720ffcf2aa9c133553cc159b75973afd89ef5fc565e339c0d5b0a" + }, + { + "path": "pack/metin2_patch_flame.epk", + "size": 16641770, + "sha256": "bed7cc686ff410e83f073e55970f6601c54d2614d452b1d690e1a84a8a8d1adf" + }, + { + "path": "pack/metin2_patch_flame_dungeon.eix", + "size": 5072, + "sha256": "71b57363c94e0ab344c1b3507a7b36f6e4d6e4e6e6542c48c03c8f3f81191128" + }, + { + "path": "pack/metin2_patch_flame_dungeon.epk", + "size": 10628610, + "sha256": "90fad557385c5cfd46ef0bab708ef3acc27f9b0e9efd2b8570186dc68f4cf66b" + }, + { + "path": "pack/metin2_patch_halloween.eix", + "size": 2448, + "sha256": "c64e45a611d23e92a975606123e0eb32bd312fdc7745e95a4771ff0980000c83" + }, + { + "path": "pack/metin2_patch_halloween.epk", + "size": 6723010, + "sha256": "b1b59c564699444e98de19740e4a3f9b72f61b82adbff73eaf826ba39455d8c5" + }, + { + "path": "pack/metin2_patch_mineral.eix", + "size": 696, + "sha256": "d4eed8e582749d456c340edf190ad002b2140a47142864dd7a8a3d4a5ad96a77" + }, + { + "path": "pack/metin2_patch_mineral.epk", + "size": 501767, + "sha256": "5747f41c6e01d7fade2144acb867859ad0d93f0ee11425c6829c33c194c9ae8c" + }, + { + "path": "pack/metin2_patch_mundi.eix", + "size": 15552, + "sha256": "31f32a17eb53ba1f926d590795a320e239fc51e640c1147d3bc2618854d8b30b" + }, + { + "path": "pack/metin2_patch_mundi.epk", + "size": 58156360, + "sha256": "34b72649ebf2d1c9c2902afe805862d9b35cdffed9ed9807ba1fb05aae636539" + }, + { + "path": "pack/metin2_patch_party.eix", + "size": 5248, + "sha256": "27ccfdb7264a21ae0ff7e7a7de5f93c9d89bc6c049ceb9ec8272dc9bafa4228f" + }, + { + "path": "pack/metin2_patch_party.epk", + "size": 13717291, + "sha256": "0e6c795dbce3e3a2c31cb5bb3609f339f615432fedee7d5b3bcb9308a7c3fff8" + }, + { + "path": "pack/metin2_patch_pet1.eix", + "size": 6512, + "sha256": "033aa0ca95b78f567562b28834a5a8e979a20c13a4ff51a55b2cfe59e98263c3" + }, + { + "path": "pack/metin2_patch_pet1.epk", + "size": 8774662, + "sha256": "d5c340bfdb772a210823d38d98bc96435dac97927bf7ff5d931edb5b86733c1e" + }, + { + "path": "pack/metin2_patch_pet2.eix", + "size": 3160, + "sha256": "e158833887cd1247f4b02ce83441f62eef9ff4ca530126043534af5deb9263c9" + }, + { + "path": "pack/metin2_patch_pet2.epk", + "size": 3626211, + "sha256": "1b593a9f000a6f86ca068b0744905ac42b1c2de7cda62846de6cbcf2ee4c6ca4" + }, + { + "path": "pack/metin2_patch_ramadan_costume.eix", + "size": 928, + "sha256": "eb9f07c188d0db8a84bd4292380786f281afb6d1ade9cdc887f9195d0a01edbb" + }, + { + "path": "pack/metin2_patch_ramadan_costume.epk", + "size": 2855300, + "sha256": "4ac34b1daec582b1cfe01864aab151e80411dfca072881325c167954cb4623d3" + }, + { + "path": "pack/metin2_patch_sd.eix", + "size": 7752, + "sha256": "30769cc66199577cc81be5aa802c252f48c131605ca0503301b26b827e48e5e7" + }, + { + "path": "pack/metin2_patch_sd.epk", + "size": 13939014, + "sha256": "c4f47c8153a903ed09666c63a7b12a98697d80c5d0b22fdb2fe89262c3f028b8" + }, + { + "path": "pack/metin2_patch_snow.eix", + "size": 9592, + "sha256": "b756693151bc8f7a34cfd4101ad22ac7fbeb1e6f609553560c6e9325f423cad7" + }, + { + "path": "pack/metin2_patch_snow.epk", + "size": 14268853, + "sha256": "d8e5a77f48949df5365dcbc310af523ae795b0cc3f2edceecc31a48eb138fbc7" + }, + { + "path": "pack/metin2_patch_snow_dungeon.eix", + "size": 7472, + "sha256": "ee441fb8a2fe7ca9fe4c0ad45e01b4465efe629fcac21b4cf623d6698e0c9d2a" + }, + { + "path": "pack/metin2_patch_snow_dungeon.epk", + "size": 16454147, + "sha256": "e04cd4c35f29a9136e18cbcc6ff9e9fc719cc46d8cd21b0e7ab47941bd8de913" + }, + { + "path": "pack/metin2_patch_w20_etc.eix", + "size": 744, + "sha256": "ede6d126af86786919734bdbd0202b137d9d8aa8eb0c5d739d230715f312fb0b" + }, + { + "path": "pack/metin2_patch_w20_etc.epk", + "size": 389376, + "sha256": "ff820fed85f17c4c8043e9f09726c3ac6f5830ca6b894fca76f776247e203afb" + }, + { + "path": "pack/metin2_patch_w20_sound.eix", + "size": 27904, + "sha256": "15ffffd5fc4fe187944a6206d62b15d01eb06421886d7a7a74ea0ea8b043529a" + }, + { + "path": "pack/metin2_patch_w20_sound.epk", + "size": 13982647, + "sha256": "fedc61929de0537bb3a52c9f5bdd9d9b6e2ce6b2edeec0b87f82ed22d75504b7" + }, + { + "path": "pack/metin2_patch_w21_etc.eix", + "size": 824, + "sha256": "c08249dddf3131c578be4e8c45b5507fc8b80428b55a34a2bc9e34fe451c4799" + }, + { + "path": "pack/metin2_patch_w21_etc.epk", + "size": 281488, + "sha256": "af1f38da731be0a773bed62ddd8115fc0a8ed1d557327cac995187501c576d02" + }, + { + "path": "pack/metin2_patch_w21_mobs.eix", + "size": 4712, + "sha256": "782ebf7a4fc25d77996f412b7321e18fcad92ef5950087a825556f8856fd95b1" + }, + { + "path": "pack/metin2_patch_w21_mobs.epk", + "size": 10472540, + "sha256": "5fbce39298df73ceeb4d5aaf1a1cece8ae4256e7adf89ec9a7b640cc09f7251e" + }, + { + "path": "pack/metin2_patch_w21_mobs_m.eix", + "size": 8592, + "sha256": "03cf1e48fa791fcaa2d19b5df6a73cf4e4f4bb73f19d58fb651c15a78a60c703" + }, + { + "path": "pack/metin2_patch_w21_mobs_m.epk", + "size": 280794, + "sha256": "8dddcc779469c4f45ac7a0f24ea22ce075df1bb25891ac949a6eda0bfcd9a00b" + }, + { + "path": "pack/metin2_patch_xmas.eix", + "size": 13056, + "sha256": "b87bdab29a625b3271807cc4c9349f6dd5be2f3b766d2648e8f00242c7681ac2" + }, + { + "path": "pack/metin2_patch_xmas.epk", + "size": 21194603, + "sha256": "8b2ee26667a652224345a93284e70541fab288d4f88379641437d341bccbcb02" + }, + { + "path": "pack/monster2.eix", + "size": 42668, + "sha256": "be5998d8b81e6e9e04a54a375ac1d5a1e7fbf724c15628cec2094ef1717da146" + }, + { + "path": "pack/monster2.epk", + "size": 31736832, + "sha256": "5d3d1aa75463a6257865eb07dcdc35c89cb4364454219ec152bf4eaa10d495f3" + }, + { + "path": "pack/npc2.eix", + "size": 524, + "sha256": "520a3bbb60fe4b19c12b0e510f582758b895cbaf24789a3b4a5dfd6953e3423e" + }, + { + "path": "pack/npc2.epk", + "size": 301568, + "sha256": "6718ddba10c105483e602a7b8b88decb2ac728b572287d2cc105971543248a2a" + }, + { + "path": "pack/outdoordesert1.eix", + "size": 10116, + "sha256": "19b728d856722604f1fabc7aad185aa6d92944d659a0e30cbdbfebd2e8b462e8" + }, + { + "path": "pack/outdoordesert1.epk", + "size": 2403328, + "sha256": "7ffb1cf1b9dd91b1f549b3e8ec9cc6e07a3717dc21ea6a932bbeaad0d5f19475" + }, + { + "path": "pack/outdoorduel.eix", + "size": 580, + "sha256": "e7472a272c42b2d81d076dd8b1041373fe04d4d218170f3c5fc3353094a731a8" + }, + { + "path": "pack/outdoorduel.epk", + "size": 72192, + "sha256": "4ab4ca9faea44daa46b9deaaafd1e9f938f99d48a6abb13b37b70d3e6608db61" + }, + { + "path": "pack/outdoorempirebattle1.eix", + "size": 2732, + "sha256": "0853b2e3378083bc93529f280ac44314ee8974be3f423dec99befe7490c9c770" + }, + { + "path": "pack/outdoorempirebattle1.epk", + "size": 761600, + "sha256": "ec06bd6dd9a4f34512dc10ce3b8e250b257a7447c7d387cf16e79b7421e803af" + }, + { + "path": "pack/outdoorfielddungeon1.eix", + "size": 1204, + "sha256": "1dc807a2cd6047bb8ae4cfa12a63d654ce05fa7bc80abc6ff037504694ca8617" + }, + { + "path": "pack/outdoorfielddungeon1.epk", + "size": 297728, + "sha256": "d32d577abd49aee76eff0b944e002e155aeb9d851c188a3fbf231566deaae100" + }, + { + "path": "pack/outdoorflame1.eix", + "size": 9612, + "sha256": "36d95f41eacf9bcf688745b7b8b135c1357228b0e7bf016f758f9e620876fd7e" + }, + { + "path": "pack/outdoorflame1.epk", + "size": 3019776, + "sha256": "1e30915737814d9a8cbece8e724781abf406d34c1d98f8fbe8913872c547070b" + }, + { + "path": "pack/outdoorgmguildbuild.eix", + "size": 612, + "sha256": "c83cae298bda5f835c7eddcaf405782a81bcc5e2346c1ff46d5f22aabb66c6dd" + }, + { + "path": "pack/outdoorgmguildbuild.epk", + "size": 105216, + "sha256": "ddefc2bbb4167d58a5188588a42c202d8f1ecad647fb7cfa4cc988f03ce436c0" + }, + { + "path": "pack/outdoorguild1.eix", + "size": 1388, + "sha256": "2365d9efce29252fcf612ccb1d730b9ed8c1155633990ba206f812d5e687b2ff" + }, + { + "path": "pack/outdoorguild1.epk", + "size": 317184, + "sha256": "1de02f8638021db4eef99b67aa58068d8a263b178c1efd36b8db5c6d7512c386" + }, + { + "path": "pack/outdoorguild2.eix", + "size": 1412, + "sha256": "3153e4e24b07edd8657c7a19b9a43c618ac58c148d30daafaa60f4b3ddfdd030" + }, + { + "path": "pack/outdoorguild2.epk", + "size": 412160, + "sha256": "3c861461824ee0b4c1031d8c05b2fd866ab811694c585413ab2e05b7a3a57c95" + }, + { + "path": "pack/outdoorguild3.eix", + "size": 1356, + "sha256": "25ccc66e20c13953c3e8cadf3726bb2d0d309d08b4a3f6aa752241bf1bf3f630" + }, + { + "path": "pack/outdoorguild3.epk", + "size": 334080, + "sha256": "bcc028355ce2d04353712b2ddb4bde0fa9765d416a5fa4c6852a31b6c0349474" + }, + { + "path": "pack/outdoormilgyo1.eix", + "size": 4692, + "sha256": "af2489537ef8dab1aaaf513e702c431455fc6a93cd2bcc1714cec0b54eb32d12" + }, + { + "path": "pack/outdoormilgyo1.epk", + "size": 1072640, + "sha256": "f118bdf570f9ee9c38126f1f2a313591d25fc96c303cf47eb67e4f1c19aad34b" + }, + { + "path": "pack/outdoort1.eix", + "size": 2764, + "sha256": "cddb11306d3a6b1f48e443430062a969d06d6b7a1d440c7a92bd36622f1da7eb" + }, + { + "path": "pack/outdoort1.epk", + "size": 1157888, + "sha256": "371d5e251267e3ed82108dd531c84279567af7b789ca3f4919feb7fbd0e42972" + }, + { + "path": "pack/outdoort2.eix", + "size": 628, + "sha256": "993d04e4366cd109e5daba7bb5df27ed3695e42a31f4ad8786ef5c262336a608" + }, + { + "path": "pack/outdoort2.epk", + "size": 161792, + "sha256": "5c078cef781c95493d4a44ef826eb538db82fe9e425aa50fd3e217873c74d88f" + }, + { + "path": "pack/outdoort3.eix", + "size": 548, + "sha256": "576daed0783c46782477e8447e813880d16268ec811f83ae1d56ca7600204d30" + }, + { + "path": "pack/outdoort3.epk", + "size": 86272, + "sha256": "e7b6d2050fcca816f3d41473db950ee15050e6405b89a5c65ff83e6e6b3a9768" + }, + { + "path": "pack/outdoort4.eix", + "size": 564, + "sha256": "738591223445178403a82cf5f6f1aa11c4cfd9556307a1f1d9e1ce35c3f8132b" + }, + { + "path": "pack/outdoort4.epk", + "size": 84224, + "sha256": "b42a164e68ef53796bc414e9aa26b8d7f1bfc09d45b339000e3c5d867374247c" + }, + { + "path": "pack/outdoortrent.eix", + "size": 1596, + "sha256": "e7f36bc3b8d97b1e4c0816f74f3d81fd2d5f31227c2368f5d80e041c9be14560" + }, + { + "path": "pack/outdoortrent.epk", + "size": 754176, + "sha256": "22f98ed1afadee57d3ad6bf1d7539ff7c096e81ce46f4c740d2e8e8e58740622" + }, + { + "path": "pack/outdoortrent02.eix", + "size": 4324, + "sha256": "44d16f55b77ad14cbb3a6064ab7ccef660c201b2ead8e7e2d25dc667680e16e6" + }, + { + "path": "pack/outdoortrent02.epk", + "size": 863488, + "sha256": "261b1e7694b135bce4f133e499c7ab16c1090fa2ce4d5184cdcf3fcace2743c1" + }, + { + "path": "pack/outdoorwedding.eix", + "size": 524, + "sha256": "ab013b72b08f68f23323fabc37b57f0da1b642c7ed647c17c56fbd1c1f7782ae" + }, + { + "path": "pack/outdoorwedding.epk", + "size": 89344, + "sha256": "5a5ca6ea1668235c199038cc68cf194b2ce1912c3f72f1ec111672b5ff549256" + }, + { + "path": "pack/patch1.eix", + "size": 16012, + "sha256": "a13dfdf30302c5eac83d36f8db3c02a7e11eb91e07e65dde47bc821892a7cde5" + }, + { + "path": "pack/patch1.epk", + "size": 92664320, + "sha256": "30d781107d9d801dc8ec563da83c9cbee12fd7344945f73c20617e697726d143" + }, + { + "path": "pack/patch2.eix", + "size": 35736, + "sha256": "4640892f14a623699cb17562188c8cd5d027a8b030c6a94a7ad968c22b589537" + }, + { + "path": "pack/patch2.epk", + "size": 26139762, + "sha256": "dd280abd35f4895a4b2554d4f3688ab151820bec0b92596418cadb11386b715b" + }, + { + "path": "pack/pc2.eix", + "size": 55644, + "sha256": "2e1ea3de3a1f3460ce771e6a98b18c90144cd54ba782e50023903bf665e27498" + }, + { + "path": "pack/pc2.epk", + "size": 62856192, + "sha256": "c07b8efc433692623c8a8dc1f173ec003398c2ad3eab3821ecdda84510f88947" + }, + { + "path": "pack/root.eix", + "size": 2968, + "sha256": "7b90b6f11cd468770af6de4a74a55ea45610d9681acfcf5f08afe82d51fbfb6d" + }, + { + "path": "pack/root.epk", + "size": 520704, + "sha256": "51670cbbcda40db17c89cbce3e6e1f1029ae0355c37a8f6a97038f08254b73ab" + }, + { + "path": "pack/season1.eix", + "size": 109008, + "sha256": "be76c3f596ebdad42a6a0b6193b6e0e35a688d70b85d6212f4e79f52e4f42a36" + }, + { + "path": "pack/season1.epk", + "size": 54050048, + "sha256": "ebbb1147eb11ed3acc5f3929cc1e25aef4efe349db9d1ed66d65665338aa1c96" + }, + { + "path": "pack/season2.eix", + "size": 78564, + "sha256": "696c3f8dabfeed38c7a0373b8c33cfc3f90044afcd2b7234672a8a72b6ba502b" + }, + { + "path": "pack/season2.epk", + "size": 20960768, + "sha256": "35eb33c0222976963f0a7fd3d96afc6f6223853360ca95781b1300883e32d4f0" + }, + { + "path": "pack/season3_eu.eix", + "size": 36188, + "sha256": "9fd3db6feb6cd3853d682b7e217093eead8d45d4de2f38febd160c5cd56f6f31" + }, + { + "path": "pack/season3_eu.epk", + "size": 29648896, + "sha256": "30fe0bce77449d722549e94a5a0c6f55ac1d93cd4611eecb9ba2ffa7f8921e08" + }, + { + "path": "pack/sound2.eix", + "size": 36732, + "sha256": "762fb3313f0d93bbdce702d078e5464c53badc19bb098fb2227e633faa76b017" + }, + { + "path": "pack/sound2.epk", + "size": 31777280, + "sha256": "967e2e1d69bf5c91d5ae68172897ad210b15f635d47e6a5942fe4c642a271b78" + }, + { + "path": "pack/sound_m.eix", + "size": 36660, + "sha256": "8c655788d6ce43e1a71d4423dcb954ad0be326dad52de9e5c1455b347d85480c" + }, + { + "path": "pack/sound_m.epk", + "size": 378368, + "sha256": "63c1ad5ac6faec606f065575cd58a89044283d9711cd41e9f2083b699cdc1d6e" + }, + { + "path": "pack/textureset.eix", + "size": 1340, + "sha256": "f9740106ff13884dee69fea235472011f633e2a084971adec439a75835a7c1a9" + }, + { + "path": "pack/textureset.epk", + "size": 21248, + "sha256": "01db10d220747c4651787ee08ada116b24aa6d435687abe39000b88fc3b8621b" + }, + { + "path": "pack/uiloading.eix", + "size": 1552, + "sha256": "c60a9d1803fab3f021905b346e6f1d95f0f3390036961fbcb7a929ef41798570" + }, + { + "path": "pack/uiloading.epk", + "size": 10192384, + "sha256": "1736374ea65414832cd306ff799086789da78fc43ebdb85b20f8ac28d861ecc9" + }, + { + "path": "pack/uiscript.eix", + "size": 4136, + "sha256": "b053f0349f4748956620fc4c4b6120dde284e6d7226bde0eebc3b02bdbd95b37" + }, + { + "path": "pack/uiscript.epk", + "size": 85592, + "sha256": "cfc778a92541fff7b83210f747c29f300472f7062d0c754006904f2a5116e14b" + }, + { + "path": "Eternexus/root/assassin_m.msm", + "size": 36070, + "sha256": "ad344dbfd9015f02611e09cda4e231189194eaf3b39f58131608df015b55b173" + }, + { + "path": "Eternexus/root/assassin_w.msm", + "size": 38386, + "sha256": "706a6aa78e3d9f99c71aa6e0ccd94ddebcd0fd0247b70d423b1113f719ba8f98" + }, + { + "path": "Eternexus/root/shaman_m.msm", + "size": 36790, + "sha256": "95f76cb12bf1e9cd6d42f759e2a84eefbb02ae9bf39d9fc73e97aefe29495a43" + }, + { + "path": "Eternexus/root/shaman_w.msm", + "size": 37592, + "sha256": "b14b61a0956a527121c5588b12acd7adf0a2fbe72ab640eef8c1f021011bee26" + }, + { + "path": "Eternexus/root/sura_m.msm", + "size": 35427, + "sha256": "65f34ae92467b9b92bcff8588d8727d20b9850d6b7713c21e9e732d1e031cbbc" + }, + { + "path": "Eternexus/root/sura_w.msm", + "size": 37621, + "sha256": "d825393ae5aefba606d6994cbfbda25a9ef6af263ee93c1fdd721514cf016546" + }, + { + "path": "Eternexus/root/warrior_m.msm", + "size": 37628, + "sha256": "5a519531607feaf016da2486ca097fd6ecc8d0826779cc0fa07aa34d0812f644" + }, + { + "path": "Eternexus/root/warrior_w.msm", + "size": 39386, + "sha256": "dd1519611556715212283c7513455fd7db5e853cbc7df6252a3d9d8c4ad20e03" + } + ] +} diff --git a/audit/history.jsonl b/audit/history.jsonl index 2189daff..1198f0ea 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -491,3 +491,4 @@ {"time":"2026-09-23T10:00:00Z","event":"port_round","unit":"EterPack/*, EterBase/{tea,lzo,Timer,Stl,Random}.cpp + platform EterBase/{CRC32,FileBase,MappedFile,Debug,Utils}","ported":["EterPack/EterPack.cpp","EterPack/EterPackManager.cpp","EterPack/EterPackCursor.cpp","EterPack/EterPackPolicy_CSHybridCrypt.cpp","EterBase/tea.cpp","EterBase/lzo.cpp","EterBase/Timer.cpp","EterBase/Stl.cpp","EterBase/Random.cpp"],"status_note":"mirror copies + platform FileBase/MappedFile/CRC32/Debug/Utils; not runtime-reachable until the asset_io pack backend (PORT-PLAN §5 step 5), so port-map statuses stay TODO","divergent":[],"needs_live":[],"corrections":["2R registered_packs 136 was wrong: 124 Index pairs -> 119 RegisterPack successes, 103 distinct packs + root (PORT-PLAN, memory)"],"findings":["libc++ unordered_multimap also keeps first-registered-wins: 0 wrong winners over 2282 overrides","exactly the 4 short-layout SECURITY files fail CEterPackManager::Get","pack/Index spells Etc for ETC.eix: CEterPack::CreateIndexFile fopens directly, so the bootstrap must resolve the on-disk dbname"],"keys":"EterPack TEA keys generated at configure time into the build tree (EterPackKeys.generated.h), never committed","tests":["extension/tests/port_eterpack_test.cpp PASS (macOS, 52605 files / 2023459178 bytes)","script/port_gate.sh macos/android/ios/windows PASS"]} {"time":"2026-09-23T12:00:00Z","event":"port_round","unit":"platform UserInterface PackInitialize + EterBase/FileLoader.cpp + pack:// asset_io backend (PORT-PLAN §5 step 5b)","ported":["EterBase/FileLoader.cpp"],"deleted":[],"divergent":[],"needs_live":[],"status_note":"PackInitialize (platform, on-disk dbname resolution, no LogBoxf) + mtpack40250 backend + Metin2Pack node; no runtime reader uses pack:// until the proto/GDScript switch, so port-map statuses stay TODO","tests":["extension/tests/port_eterpack_test.cpp via PackSingletons+PackInitialize(\"pack\"): 103 packs, oracle order, PASS"],"commit":"5b"} {"time":"2026-09-23T12:30:00Z","event":"port_round","unit":"proto reader -> 40250 item_proto/mob_proto via CLZO + pack://locale// (PORT-PLAN §5 step 2 + step 5 runtime switch)","ported":["EterPack/EterPack.cpp (16 fns)","EterPack/EterPackManager.cpp (14)","EterPack/EterPackPolicy_CSHybridCrypt.cpp (1)","EterBase/lzo.cpp (11)","EterBase/tea.cpp (2)","EterBase/Stl.cpp (2)"],"adapted":["UserInterface/UserInterface.cpp PackInitialize","EterBase/FileLoader.cpp (5)","EterBase/MappedFile.cpp (9)","EterBase/FileBase.cpp (5)","EterBase/CRC32.cpp GetCRC32"],"deleted":["extension/src/proto/proto.cpp m2dev reader: XChaCha20 + MCOZ, 236-byte item / 335-byte mob strides"],"divergent":[],"needs_live":[],"status_note":"statuses set only for the functions a clang coverage run of proto_test + port_eterpack_test hit; the rest stay TODO. SMobTable is a local #pragma pack(1) mirror in proto.cpp (static_assert 255) until batch 2P ports GameLib/PythonNonPlayer. name = cp1252(szLocaleName) as CItemData::GetName / CPythonNonPlayer::GetMonsterName","tests":["extension/tests/proto_test.cpp: 5743 items / 1334 mobs from pack://locale/en PASS","extension/tests/proto_item_layout_test.cpp 156/255 strides, 236/335 rejected PASS","godot netbridge/equip_model/remote_player/mob_view PASS"],"commit":"2D-proto"} +{"time":"2026-09-23T13:30:00Z","event":"asset_gate","unit":"PORT-PLAN §5 steps 3-4: MT_ASSETS_STRICT + provenance manifest + script/run_40250_asset_gate.sh","manifest":"audit/assets/40250-client.json (pack/Index + 214 .eix/.epk + 8 Eternexus/root/*.msm = 223 files, 1407474045 bytes, sha256)","env":{"MT_40250_CLIENT":"40250 Client dir (native tests, AssetRoot.client_path, gate)","MT_ASSETS":"m2dev loose dev override only","M2_ASSETS":"no longer used by tests"},"fixes":["remote_player_test accepted only twohand_sword/wait.msa; WAIT picks wait/wait_1 by weight, so it failed ~1/3 of runs"],"tests":["script/run_40250_asset_gate.sh macOS PASS (manifest, ctest port.eterpack|proto.*, godot netbridge/equip_model/remote_player/mob_view)","gate with MT_40250_CLIENT=/nonexistent exits 1"],"commit":"2D-gate"} diff --git a/docs/PORT-PLAN.md b/docs/PORT-PLAN.md index 00a5e08c..dab6950c 100644 --- a/docs/PORT-PLAN.md +++ b/docs/PORT-PLAN.md @@ -349,6 +349,32 @@ extension/third_party/cpython-2.7.18/ # 静态库(2P 批次 5. 资源根切换按 2R 第 6 条执行:移植 `EterPack`(`CLZObject`/TEA 已经在第 2 步)和 `EterPackManager`,接上 `asset_io` 的 pack 后端,读取方逐个改用 40250 路径,跑严格门禁,更新本节状态。 +状态(2026-09-23): + +| 步骤 | 状态 | 提交 | +| --- | --- | --- | +| 1. msm 路径 | 完成:`equip_model.gd` 先查 `root/_.msm`,m2dev 的 `root/msm/` 作后备;8 个种族都能从 `Eternexus/root` 找到 | 240d2827 | +| 2. proto | 完成:`proto.cpp` 用移植的 `CLZO`/TEA 读 MIPX/MMPT(156 / 255 字节),m2dev 的 XChaCha20 / 236 / 335 读取已删除;名字按 `GetName`/`GetMonsterName` 取 `szLocaleName`(cp1252)。`SMobTable` 暂时在 `proto.cpp` 里放一份 `#pragma pack(1)` 镜像(`static_assert == 255`),2P 移植 `GameLib/PythonNonPlayer` 后改用正式镜像 | 232d0461 | +| 3. 严格模式 | 完成(见下) | 本批最后一个提交 | +| 4. 门禁脚本 | 完成:`script/run_40250_asset_gate.sh` 在 macOS 上 PASS | 同上 | +| 5. 资源根 | 部分完成:pack 后端(`PackInitialize` + `asset_io` 的 `pack://` + `Metin2Pack` 节点)已接入,proto 经 `pack://locale//` 读取(5a 1f1004da、5b 5a26e93f)。模型、贴图、地图和 root/locale 文本仍读 m2dev `assets/`,由 2V 切片逐个切换 | | + +环境变量(取代步骤 3 里“两者都透传”的过渡方案): + +- `MT_40250_CLIENT`:40250 的 `Client` 目录(`pack/`、`Eternexus/`)。native 测试(CMake 缓存变量默认读同名环境变量, + 再退回 `${MT_40250_SOURCE}/../../Client`)、`AssetRoot.client_path()` 和门禁脚本都用它; +- `MT_ASSETS`:只表示 m2dev 散文件目录(开发期覆盖); +- `M2_ASSETS`:测试不再使用; +- `MT_ASSETS_STRICT=1`:native 测试在资源缺失时返回 1(不是 ctest 的跳过码 77),门禁脚本把 Godot 测试输出里的 + `(skip` 也算失败。 + +来源清单:`tools/asset_manifest.py generate|verify ` 记录 `pack/Index`、全部 `.eix/.epk` 和 +`Eternexus/root/*.msm` 的路径、大小、sha256,结果在 `audit/assets/40250-client.json`(223 个文件,1,407,474,045 +字节)。文件缺失、内容变化或清单外多出的文件都会让 verify 失败。 + +已知问题(不是本批引入的):完整 Android 链接在 API 24 上失败,原因是 `extension/src/net/text_codec.cpp` 用了 iconv; +本批的 mtproto、`pack40250_node`、`asset_io`、`proto_node` 都能在 Android 上编译。 + ## 6. 进度与 port-map 基线 实时数字用 `port_map.py status` 查看。 @@ -370,6 +396,10 @@ extension/third_party/cpython-2.7.18/ # 静态库(2P 批次 | platform | 2091 | 0 | | | 合计 | 10609 | 0 | | +2D 之后(2026-09-23):logic 46 个 `PORTED`(EterPack、EterPackManager、lzo、tea、Stl),platform 21 个 `ADAPTED` +(PackInitialize、FileLoader、MappedFile、FileBase、CRC32)。只标了 proto_test + port_eterpack_test 覆盖率运行实际执行到 +的函数。 + 与基线前的数字(logic 3285、python 4890、platform 2229,共 10404)相比的变化: - 函数清单(`port_map.cpp_functions`)用 platform 骨架的 clang 声明逐个对照后修正: diff --git a/extension/src/port/CMakeLists.txt b/extension/src/port/CMakeLists.txt index c84aebc1..a83f753e 100644 --- a/extension/src/port/CMakeLists.txt +++ b/extension/src/port/CMakeLists.txt @@ -140,7 +140,10 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME) # Against the real 40250 Client/pack next to the reference source; skipped (77) when it is missing, # failed instead under MT_ASSETS_STRICT=1. - set(MT_40250_CLIENT "${MT_40250_SOURCE}/../../Client" CACHE PATH "40250 Client directory (pack/, Eternexus/)") + set(MT_40250_CLIENT "$ENV{MT_40250_CLIENT}" CACHE PATH "40250 Client directory (pack/, Eternexus/)") + if(NOT MT_40250_CLIENT) + set(MT_40250_CLIENT "${MT_40250_SOURCE}/../../Client") + endif() add_executable(port_eterpack_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_eterpack_test.cpp) target_link_libraries(port_eterpack_test PRIVATE port_platform) add_test(NAME port.eterpack COMMAND $ ${MT_40250_CLIENT}) diff --git a/project/remote_player_test.gd b/project/remote_player_test.gd index 1c3fbf64..a40caa3d 100644 --- a/project/remote_player_test.gd +++ b/project/remote_player_test.gd @@ -63,7 +63,9 @@ func _run() -> void: await process_frame if proto: _ck(pv.get_motion_mode() == 3, "remote weapon 3159 -> TWOHAND_SWORD mode") - _ck(String(pv.anim.get("anim_path")).contains("/twohand_sword/wait.msa"), + # WAIT 按权重随机选 wait.msa / wait_1.msa(见 motion_registry_test、player_motion_test),两者都是双手握姿。 + var wait_re := RegEx.create_from_string("/twohand_sword/wait(_\\d+)?\\.msa$") + _ck(wait_re.search(String(pv.anim.get("anim_path"))) != null, "remote heavy-weapon wait uses two-hand grip pose") _ck(pv.remote_equip._weapon_refine_fx.size() == 1, "remote +9 heavy weapon creates one persistent refine effect") diff --git a/script/run_40250_asset_gate.sh b/script/run_40250_asset_gate.sh new file mode 100755 index 00000000..d8991746 --- /dev/null +++ b/script/run_40250_asset_gate.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# 40250 asset gate (docs/PORT-PLAN.md 2D steps 3-4): with MT_ASSETS_STRICT=1, verify the provenance manifest +# (audit/assets/40250-client.json), then run the native pack/proto tests and the Godot tests that read the +# 40250 client. Missing assets, a manifest mismatch, a skipped test or a failed one all fail the gate; nothing is +# reported as PASS without having run. +# +# MT_40250_CLIENT=<.../Server Client TMP4/Client> script/run_40250_asset_gate.sh +# +# Uses the build tree $MT_BUILD_DIR (default build/, configured with BUILD_TESTING=ON) and $GODOT (default godot). +set -uo pipefail +cd "$(dirname "$0")/.." +REPO="$PWD" + +export MT_ASSETS_STRICT=1 +CLIENT="${MT_40250_CLIENT:-$REPO/../40250/Server Client TMP4/Client}" +BUILD="${MT_BUILD_DIR:-build}" +GODOT="${GODOT:-godot}" +LOG="${MT_ASSET_GATE_LOG:-$BUILD/40250-asset-gate.log}" +fail=0 +: >"$LOG" 2>/dev/null || LOG=/dev/null + +step() { # name, command... + local name="$1"; shift + if "$@" >>"$LOG" 2>&1; then + echo "PASS $name" + else + echo "FAIL $name (see $LOG)" + fail=1 + fi +} + +if [ ! -f "$CLIENT/pack/Index" ]; then + echo "FAIL no 40250 client at '$CLIENT' (set MT_40250_CLIENT)" + exit 1 +fi +CLIENT="$(cd "$CLIENT" && pwd)" +export MT_40250_CLIENT="$CLIENT" + +step "manifest audit/assets/40250-client.json" python3 tools/asset_manifest.py verify "$CLIENT" + +native() { + cmake -S . -B "$BUILD" -DBUILD_TESTING=ON "-DMT_40250_CLIENT=$CLIENT" \ + && cmake --build "$BUILD" --target port_eterpack_test proto_test proto_item_layout_test mtgodot -j 8 \ + && ctest --test-dir "$BUILD" -R '^(port\.eterpack|proto\.)' --output-on-failure --no-tests=error +} # under MT_ASSETS_STRICT=1 the tests exit 1, not the ctest skip code 77, when the client is missing +step "native pack/proto tests" native + +godot_test() { # script: runs headless; a "(skip" line is a failure under the gate + local out + out="$(cd project && "$GODOT" --headless --path . -s "$1" 2>&1)" + local rc=$? + printf '%s\n' "$out" + [ $rc -eq 0 ] && ! grep -q "(skip" <<<"$out" && grep -q "^PASS" <<<"$out" +} +for t in netbridge_test.gd equip_model_test.gd remote_player_test.gd mob_view_test.gd; do + step "godot $t" godot_test "$t" +done + +if [ $fail -ne 0 ]; then + echo "40250 asset gate: FAIL" + exit 1 +fi +echo "40250 asset gate: PASS" diff --git a/tools/asset_manifest.py b/tools/asset_manifest.py new file mode 100755 index 00000000..f8d713c9 --- /dev/null +++ b/tools/asset_manifest.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +"""Provenance manifest of the 40250 client assets the tests and the runtime read (docs/PORT-PLAN.md 2D step 3). + +Records path (relative to the Client directory) + size + sha256 for pack/Index, every .eix/.epk in pack/ and the +loose Eternexus/root/*.msm race specs. `verify` fails on a missing, changed or untracked file, so a strict +run proves it read exactly the bytes the manifest names. + + tools/asset_manifest.py generate [-o audit/assets/40250-client.json] + tools/asset_manifest.py verify [-m audit/assets/40250-client.json] +""" +import argparse +import hashlib +import json +import os +import sys + +DEFAULT = os.path.join(os.path.dirname(__file__), "..", "audit", "assets", "40250-client.json") + + +def sha256(path): + h = hashlib.sha256() + with open(path, "rb") as f: + for block in iter(lambda: f.read(1 << 20), b""): + h.update(block) + return h.hexdigest() + + +def tracked(client): + files = ["pack/Index"] + pack = os.path.join(client, "pack") + files += sorted("pack/" + n for n in os.listdir(pack) if n.lower().endswith((".eix", ".epk"))) + root = os.path.join(client, "Eternexus", "root") + if os.path.isdir(root): + files += sorted("Eternexus/root/" + n for n in os.listdir(root) if n.lower().endswith(".msm")) + return files + + +def entry(client, rel): + p = os.path.join(client, rel) + return {"path": rel, "size": os.path.getsize(p), "sha256": sha256(p)} + + +def generate(args): + files = [entry(args.client, rel) for rel in tracked(args.client)] + out = { + "schema": 1, + "source": "40250 Server Client TMP4/Client", + "note": "path relative to the Client directory; regenerate with tools/asset_manifest.py generate", + "files": files, + } + os.makedirs(os.path.dirname(os.path.abspath(args.output)), exist_ok=True) + with open(args.output, "w") as f: + json.dump(out, f, indent=1) + f.write("\n") + print("%d files, %d bytes -> %s" % (len(files), sum(e["size"] for e in files), args.output)) + return 0 + + +def verify(args): + try: + with open(args.manifest) as f: + want = json.load(f)["files"] + except (OSError, ValueError, KeyError) as e: + print("asset_manifest: cannot read manifest %s: %s" % (args.manifest, e), file=sys.stderr) + return 1 + if not os.path.isfile(os.path.join(args.client, "pack", "Index")): + print("asset_manifest: no pack/Index under %s" % args.client, file=sys.stderr) + return 1 + bad = 0 + for e in want: + p = os.path.join(args.client, e["path"]) + if not os.path.isfile(p): + print("missing %s" % e["path"], file=sys.stderr) + bad += 1 + elif os.path.getsize(p) != e["size"] or sha256(p) != e["sha256"]: + print("changed %s" % e["path"], file=sys.stderr) + bad += 1 + extra = sorted(set(tracked(args.client)) - {e["path"] for e in want}) + for rel in extra: + print("untracked %s" % rel, file=sys.stderr) + bad += len(extra) + print("%d files checked, %d mismatch(es)" % (len(want), bad)) + return 1 if bad else 0 + + +def main(): + ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + sub = ap.add_subparsers(dest="cmd", required=True) + g = sub.add_parser("generate") + g.add_argument("client") + g.add_argument("-o", "--output", default=DEFAULT) + v = sub.add_parser("verify") + v.add_argument("client") + v.add_argument("-m", "--manifest", default=DEFAULT) + args = ap.parse_args() + return generate(args) if args.cmd == "generate" else verify(args) + + +if __name__ == "__main__": + sys.exit(main())