Compare commits
16
Commits
b19d5b5dd3
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1db9e9a129 | ||
|
|
400e3e8ea5 | ||
|
|
85ce75e707 | ||
|
|
474a709f69 | ||
|
|
1933a5ceda | ||
|
|
96c29d2bb7 | ||
|
|
cc5573ddc1 | ||
|
|
f39a55fdd5 | ||
|
|
374d4165d8 | ||
|
|
1ab68bd06e | ||
|
|
e0c1853909 | ||
|
|
fb4d2d222b | ||
|
|
cea79fe17c | ||
|
|
c3a6fb973e | ||
|
|
8092ff44e2 | ||
|
|
61272b75e9 |
+13
@@ -5,6 +5,8 @@
|
||||
|
||||
# build
|
||||
/build/
|
||||
# 渲染测试的落图输出(test/rendering 用例自建)
|
||||
/project/build/
|
||||
/build-ios/
|
||||
/build-android/
|
||||
/build-classic/
|
||||
@@ -33,6 +35,17 @@ compile_commands.json
|
||||
*.tmp
|
||||
*.o
|
||||
*.a
|
||||
.env.live-smoke.local
|
||||
|
||||
# playable network tests: local scenario/fixture configs, credential files and
|
||||
# run outputs never enter git. Only scenario.example.json and the static gate
|
||||
# fixtures in test/playable are committed. Run outputs live under /build/playable.
|
||||
/test/playable/*.local.json
|
||||
/test/playable/*.local.txt
|
||||
/test/playable/runs/
|
||||
*.credentials
|
||||
*.credentials.json
|
||||
.env.*.local
|
||||
|
||||
# clangd
|
||||
/.cache/
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
[`docs/SHINSOO-WORLD-RENDERING.md`](docs/SHINSOO-WORLD-RENDERING.md)(正式移植,Phase 2 bring-up 之后);
|
||||
距参考图「目视等价」还差哪些保真化工作见 [`docs/PARITY-GAP.md`](docs/PARITY-GAP.md)。
|
||||
|
||||
当前进入游戏、模型/发型、贴地与技能栏问题的分阶段修复步骤,以及结合两个 Godot 项目的
|
||||
对照验证和 macOS 包验收要求,见 [`docs/RENDERING-REPAIR-PLAN.md`](docs/RENDERING-REPAIR-PLAN.md)
|
||||
(2026-09-08,实施计划;不表示其中工作已完成)。
|
||||
|
||||
---
|
||||
|
||||
## 现状
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,27 @@
|
||||
# Native tree geometry
|
||||
|
||||
These 87 GLBs are offline SpeedTreeRT extractions of this workspace's existing
|
||||
SPT assets, not procedural replacements. Their embedded bark/composite textures
|
||||
and meshes are game artwork: the same internal-use/licensing restrictions as
|
||||
`assets/Tree` apply. Do not treat them as freely redistributable open-source art.
|
||||
|
||||
`manifest.json` maps original SPT SHA-256 to the GLB filename and SHA-256.
|
||||
Both hashes are checked by `script/stage_tree_geometry.mjs`; the runtime also
|
||||
verifies both before loading. The source conversion index lives in the sibling
|
||||
`metin2-godot-main/generated/content-v1/40250-full-unpacked-final` workspace.
|
||||
No proprietary Windows DLL is shipped or loaded by the Mac client.
|
||||
|
||||
Coordinates are already Godot Y-up metres. Keep original height, origin, UVs,
|
||||
branches, fronds and leaf cards; do not apply the former proxy's 12m scale.
|
||||
Leaf materials use double-sided alpha scissor with cutoff 0.3.
|
||||
|
||||
This is real **static** geometry: full SpeedTree wind, camera-facing leaf
|
||||
clusters and native LOD transitions are not reconstructed by these GLBs.
|
||||
|
||||
Validation: all 87 species import; all 81 species referenced by current static
|
||||
AreaData have a conversion; six principal maps render 2,092 native trees with
|
||||
zero proxies. The 31 legacy SPTs under `Zone/ymir work/zone/b/tree` have different
|
||||
source hashes and are not converted or aliased to these meshes. They are not
|
||||
referenced by current tree property records. One unused historical property
|
||||
references missing `christmastree.spt`; the actual `christmastree1/2/3.spt`
|
||||
variants are converted. Seasonal event spawning is separate from static maps.
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,963 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"coordinates": "godot_y_up_meters",
|
||||
"trees": {
|
||||
"1d20b68d50ce007b4814da28936b1992ccb399f1c264df3a5dcaa8b92de5be5e": {
|
||||
"source": "Tree/ymir work/tree/b1_baobab_rt.spt",
|
||||
"source_sha256": "1d20b68d50ce007b4814da28936b1992ccb399f1c264df3a5dcaa8b92de5be5e",
|
||||
"glb": "1d20b68d50ce007b4814da28936b1992ccb399f1c264df3a5dcaa8b92de5be5e.glb",
|
||||
"glb_sha256": "642c31b558023112fc6c5fba9955c235d39d97a7c05eb56613bd76a4cf33e83e",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"9e5b696ab020cd18232e18c866454c5d52deb1076998db0a1fbf8703d1599741": {
|
||||
"source": "Tree/ymir work/tree/b1_baobab_rt2.spt",
|
||||
"source_sha256": "9e5b696ab020cd18232e18c866454c5d52deb1076998db0a1fbf8703d1599741",
|
||||
"glb": "9e5b696ab020cd18232e18c866454c5d52deb1076998db0a1fbf8703d1599741.glb",
|
||||
"glb_sha256": "4a4d6013668a084dc3b00d44e9cc7474457ddd1f06e64229a348ff8f0a445326",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"de17c0c13f956cf75d92997063a12c5dbca1a26234ad14a5f868a03362a11b48": {
|
||||
"source": "Tree/ymir work/tree/b1_beech_rt.spt",
|
||||
"source_sha256": "de17c0c13f956cf75d92997063a12c5dbca1a26234ad14a5f868a03362a11b48",
|
||||
"glb": "de17c0c13f956cf75d92997063a12c5dbca1a26234ad14a5f868a03362a11b48.glb",
|
||||
"glb_sha256": "18f49b44e9b435f91da8b75958aab7aef4b0d368301da7b3789f51e0570481ac",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"cdb81537efcda4c26781463a6018d59c42edcb12ca3d5b724c029810bf434de9": {
|
||||
"source": "Tree/ymir work/tree/b1_beech_rt2.spt",
|
||||
"source_sha256": "cdb81537efcda4c26781463a6018d59c42edcb12ca3d5b724c029810bf434de9",
|
||||
"glb": "cdb81537efcda4c26781463a6018d59c42edcb12ca3d5b724c029810bf434de9.glb",
|
||||
"glb_sha256": "9da1a6ab558c70dda232c36a2bd85bb710d24031149dac0198af3532b0bd4145",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"9d7ee35f949b4764090b1a916ade1005b622b31fea49b2d4b8586076711c8fc7": {
|
||||
"source": "Tree/ymir work/tree/b1_beech_rt3.spt",
|
||||
"source_sha256": "9d7ee35f949b4764090b1a916ade1005b622b31fea49b2d4b8586076711c8fc7",
|
||||
"glb": "9d7ee35f949b4764090b1a916ade1005b622b31fea49b2d4b8586076711c8fc7.glb",
|
||||
"glb_sha256": "edf0fbac525cfc48f87527aa25d3f49df6f010ee51f56ae78e0ac69d00aa4ba5",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"25d677d269f8cfc38ca1cd3f692810cb293ab13db46b576b278cc695f7cf3f16": {
|
||||
"source": "Tree/ymir work/tree/b1_beech_rt4.spt",
|
||||
"source_sha256": "25d677d269f8cfc38ca1cd3f692810cb293ab13db46b576b278cc695f7cf3f16",
|
||||
"glb": "25d677d269f8cfc38ca1cd3f692810cb293ab13db46b576b278cc695f7cf3f16.glb",
|
||||
"glb_sha256": "edc5c99aab45da766baa28ee402086b2b107326ec52d81b3324c06ad38def6ee",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"66392538f04a55d484f9c92cdc9d19d21341f499f30162d288e75812669f1f04": {
|
||||
"source": "Tree/ymir work/tree/b1_montereycypress_rt.spt",
|
||||
"source_sha256": "66392538f04a55d484f9c92cdc9d19d21341f499f30162d288e75812669f1f04",
|
||||
"glb": "66392538f04a55d484f9c92cdc9d19d21341f499f30162d288e75812669f1f04.glb",
|
||||
"glb_sha256": "9abdfc7f413b5aa4117f36106720dc979ebfa4c647c28a833904aa4d9e713466",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"0b90a99d6480452b12b5f78a9b61e453180ec4a83f4246bdf1b91c02b949f4e8": {
|
||||
"source": "Tree/ymir work/tree/b1_montereycypress_rt2.spt",
|
||||
"source_sha256": "0b90a99d6480452b12b5f78a9b61e453180ec4a83f4246bdf1b91c02b949f4e8",
|
||||
"glb": "0b90a99d6480452b12b5f78a9b61e453180ec4a83f4246bdf1b91c02b949f4e8.glb",
|
||||
"glb_sha256": "acd4675f30e805d5543c17f0a7a52fe37f31f6e67874b196b7395997e1ea8e83",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"f6691c8b816eea9bc8c49189d7f780f531ed9ec82d432fbba3a847d0776c27db": {
|
||||
"source": "Tree/ymir work/tree/b1_montereycypress_rt3.spt",
|
||||
"source_sha256": "f6691c8b816eea9bc8c49189d7f780f531ed9ec82d432fbba3a847d0776c27db",
|
||||
"glb": "f6691c8b816eea9bc8c49189d7f780f531ed9ec82d432fbba3a847d0776c27db.glb",
|
||||
"glb_sha256": "56effe5240c0cf44f74c033412fa2bf25a8329be74c66a62da3d2288ae24ab10",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"d7ca320772595a77c28856c45a36674e18918b9e7bc5101cd5cb8cdf12de27e1": {
|
||||
"source": "Tree/ymir work/tree/b1_montereycypress_rt4.spt",
|
||||
"source_sha256": "d7ca320772595a77c28856c45a36674e18918b9e7bc5101cd5cb8cdf12de27e1",
|
||||
"glb": "d7ca320772595a77c28856c45a36674e18918b9e7bc5101cd5cb8cdf12de27e1.glb",
|
||||
"glb_sha256": "d371eba315defbfb6956cc8cfbd26dde7ff9240d21f832c37a6fc63559bfcca2",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"cb9102770aca71a6e269e806c6e6e74e5d4cb8096abbf078180ab27c8e1367c3": {
|
||||
"source": "Tree/ymir work/tree/b1_montereycypress_rt5.spt",
|
||||
"source_sha256": "cb9102770aca71a6e269e806c6e6e74e5d4cb8096abbf078180ab27c8e1367c3",
|
||||
"glb": "cb9102770aca71a6e269e806c6e6e74e5d4cb8096abbf078180ab27c8e1367c3.glb",
|
||||
"glb_sha256": "28c7a3e30c21d3874247e10a0bf6107de1775d29b0effa664edeb743c036f953",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"2851666e8f3556aa6606642bcd529672ab45b0f8db1304d6fbb4466900a2ca5a": {
|
||||
"source": "Tree/ymir work/tree/b1_pagodatree_rt.spt",
|
||||
"source_sha256": "2851666e8f3556aa6606642bcd529672ab45b0f8db1304d6fbb4466900a2ca5a",
|
||||
"glb": "2851666e8f3556aa6606642bcd529672ab45b0f8db1304d6fbb4466900a2ca5a.glb",
|
||||
"glb_sha256": "0af3909bf5fe30ae77f918e7641e12791b8c2d3f40ec576aa375b3005bb8f528",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"d35194db82fe4ca4a7668f95d5d95f116ab6b08c326b7baf0c0ab074276db953": {
|
||||
"source": "Tree/ymir work/tree/b1_pagodatree_rt2.spt",
|
||||
"source_sha256": "d35194db82fe4ca4a7668f95d5d95f116ab6b08c326b7baf0c0ab074276db953",
|
||||
"glb": "d35194db82fe4ca4a7668f95d5d95f116ab6b08c326b7baf0c0ab074276db953.glb",
|
||||
"glb_sha256": "a6546ab05a6722bf2eaefc0b23ae399d97050a280631488bb82d651ed131ea52",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"a566eff0304a67971167e4e7d3bf254ab0c7a33478fcd657cec613c16058e900": {
|
||||
"source": "Tree/ymir work/tree/b1_pagodatree_rt3.spt",
|
||||
"source_sha256": "a566eff0304a67971167e4e7d3bf254ab0c7a33478fcd657cec613c16058e900",
|
||||
"glb": "a566eff0304a67971167e4e7d3bf254ab0c7a33478fcd657cec613c16058e900.glb",
|
||||
"glb_sha256": "fd60281f1384d80b51f838ee512e5d7506fef17d8ad9c28c962a4970e5e02be6",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"1bc5e65c0e4efcb60f7ea930f683b80001b8dd97762b6d25281946a295685149": {
|
||||
"source": "Tree/ymir work/tree/b1_sassafras_rt_fall.spt",
|
||||
"source_sha256": "1bc5e65c0e4efcb60f7ea930f683b80001b8dd97762b6d25281946a295685149",
|
||||
"glb": "1bc5e65c0e4efcb60f7ea930f683b80001b8dd97762b6d25281946a295685149.glb",
|
||||
"glb_sha256": "69ba5cd343cb193e12d5fa9203356e08e5536e6a0083650ca4be88f87472fcf8",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"5c6dabb419b86756136240a32b532746d6f86759c8e744f1701c24bcb840262a": {
|
||||
"source": "Tree/ymir work/tree/b1_sassafras_rt_fall2.spt",
|
||||
"source_sha256": "5c6dabb419b86756136240a32b532746d6f86759c8e744f1701c24bcb840262a",
|
||||
"glb": "5c6dabb419b86756136240a32b532746d6f86759c8e744f1701c24bcb840262a.glb",
|
||||
"glb_sha256": "14cb7ad036580d3387112e2098d52ee6815d158c533ed52f3db0604a00c33b09",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"d76530cfba5e75a94a9634fd76f86a02126c22bd51cccfc3d995eff8974742f2": {
|
||||
"source": "Tree/ymir work/tree/b2_cedaroflebanon_rt.spt",
|
||||
"source_sha256": "d76530cfba5e75a94a9634fd76f86a02126c22bd51cccfc3d995eff8974742f2",
|
||||
"glb": "d76530cfba5e75a94a9634fd76f86a02126c22bd51cccfc3d995eff8974742f2.glb",
|
||||
"glb_sha256": "d8df7faf73265c6a5b2a725cfacab421b609cd9a4bd2bad41997e349e9ee4fa7",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"73d757a146ca27a9459ccc3027cd9464ce415f1a6731771cbff37827a3ee1caa": {
|
||||
"source": "Tree/ymir work/tree/b2_cedaroflebanon_rt2.spt",
|
||||
"source_sha256": "73d757a146ca27a9459ccc3027cd9464ce415f1a6731771cbff37827a3ee1caa",
|
||||
"glb": "73d757a146ca27a9459ccc3027cd9464ce415f1a6731771cbff37827a3ee1caa.glb",
|
||||
"glb_sha256": "c6c15c69d0b60f232293e74f8da191b3ae62f4a69fba61d0e7fe94008c51176e",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"fd2e5bb94c5223e1eaca97544e757e135252edb05f0ddfa991e3abad3fb78b3f": {
|
||||
"source": "Tree/ymir work/tree/b2_cedaroflebanon_rt3.spt",
|
||||
"source_sha256": "fd2e5bb94c5223e1eaca97544e757e135252edb05f0ddfa991e3abad3fb78b3f",
|
||||
"glb": "fd2e5bb94c5223e1eaca97544e757e135252edb05f0ddfa991e3abad3fb78b3f.glb",
|
||||
"glb_sha256": "81e2b1c1cd753ba17e8d875bc5ad0104c0f2a8cc1831d4decbc64d7a82fb1202",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"50557c6da89615d82f9d81799315549bed25e9ae09dd128a6f161f83a17f04f5": {
|
||||
"source": "Tree/ymir work/tree/b2_ivyspy_rt.spt",
|
||||
"source_sha256": "50557c6da89615d82f9d81799315549bed25e9ae09dd128a6f161f83a17f04f5",
|
||||
"glb": "50557c6da89615d82f9d81799315549bed25e9ae09dd128a6f161f83a17f04f5.glb",
|
||||
"glb_sha256": "d632d027f5e228e6d85a986068ada05996461692623dc082569b9078965af7dd",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"d012fcd397e8dac1d1778b3ad700ee36f08d282bd53ca6466a7232824e453f5a": {
|
||||
"source": "Tree/ymir work/tree/b2_ivyspy_rt2.spt",
|
||||
"source_sha256": "d012fcd397e8dac1d1778b3ad700ee36f08d282bd53ca6466a7232824e453f5a",
|
||||
"glb": "d012fcd397e8dac1d1778b3ad700ee36f08d282bd53ca6466a7232824e453f5a.glb",
|
||||
"glb_sha256": "ce88fcfb1f04048912665592e0ad4da69679163c23b8b2f541641bad7e319f2d",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"065babe8c785f54d23b99e91e9d505b91eadaae1dff492bcfe236b657acf9272": {
|
||||
"source": "Tree/ymir work/tree/b2_ivyspy_rt3.spt",
|
||||
"source_sha256": "065babe8c785f54d23b99e91e9d505b91eadaae1dff492bcfe236b657acf9272",
|
||||
"glb": "065babe8c785f54d23b99e91e9d505b91eadaae1dff492bcfe236b657acf9272.glb",
|
||||
"glb_sha256": "aea108dfb8fcaf7021b54df8c27a194ac5486fac08fb32dbc15c00b7834d2596",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"61f67291ff5d7c49014991dddb3d03550ae18e157f1acf62daf249ca40206bf3": {
|
||||
"source": "Tree/ymir work/tree/b2_ivyspy_rt4.spt",
|
||||
"source_sha256": "61f67291ff5d7c49014991dddb3d03550ae18e157f1acf62daf249ca40206bf3",
|
||||
"glb": "61f67291ff5d7c49014991dddb3d03550ae18e157f1acf62daf249ca40206bf3.glb",
|
||||
"glb_sha256": "fcd95e7569a5a6d8af5e987f3764d520d941fa518827ae247514b003c2de5a87",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"f40054b4e07fdc6071f8b5bd6ad85782d5207c51fa116bfb8e0aca4d8675badd": {
|
||||
"source": "Tree/ymir work/tree/b2_ivyspy_rt5.spt",
|
||||
"source_sha256": "f40054b4e07fdc6071f8b5bd6ad85782d5207c51fa116bfb8e0aca4d8675badd",
|
||||
"glb": "f40054b4e07fdc6071f8b5bd6ad85782d5207c51fa116bfb8e0aca4d8675badd.glb",
|
||||
"glb_sha256": "0824f3fc789c420d6eb543cf932f617eabb8f01437e5bf6ef9aacf116e0eca83",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"80422882e2d1ec63f6c5080c9c308634b8e8acc1342ebe1ebc74039fe2384631": {
|
||||
"source": "Tree/ymir work/tree/b2_ivyspy_rt_winter.spt",
|
||||
"source_sha256": "80422882e2d1ec63f6c5080c9c308634b8e8acc1342ebe1ebc74039fe2384631",
|
||||
"glb": "80422882e2d1ec63f6c5080c9c308634b8e8acc1342ebe1ebc74039fe2384631.glb",
|
||||
"glb_sha256": "f2a4fa095e0d7ca96a49afc371b9f9189a5b370ca4543827fc3098971b779a31",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"8c9d519de4a1652c2b923e11927be3818942235052cc67e6825d9705a09feaeb": {
|
||||
"source": "Tree/ymir work/tree/b2_ivyspy_rt_winter2.spt",
|
||||
"source_sha256": "8c9d519de4a1652c2b923e11927be3818942235052cc67e6825d9705a09feaeb",
|
||||
"glb": "8c9d519de4a1652c2b923e11927be3818942235052cc67e6825d9705a09feaeb.glb",
|
||||
"glb_sha256": "97a8e81c46cf1f5dbe8084535e17286c7df07e7b71d61ae7c591adff1dd62fda",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"fa2b9ac46f0f3be36f386fb8630f034393bde37d9cc5b2ec8b38470bdbb14c59": {
|
||||
"source": "Tree/ymir work/tree/b2_japanesemaple_rt_fall.spt",
|
||||
"source_sha256": "fa2b9ac46f0f3be36f386fb8630f034393bde37d9cc5b2ec8b38470bdbb14c59",
|
||||
"glb": "fa2b9ac46f0f3be36f386fb8630f034393bde37d9cc5b2ec8b38470bdbb14c59.glb",
|
||||
"glb_sha256": "34831b921865e35889704938333c80d69daaba09762e4fe8351c673811053dea",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"86b5d9065583eabca29ad89b7ccb67ac640bada57af8504c6448027fa05bd655": {
|
||||
"source": "Tree/ymir work/tree/b2_japanesemaple_rt_fall2.spt",
|
||||
"source_sha256": "86b5d9065583eabca29ad89b7ccb67ac640bada57af8504c6448027fa05bd655",
|
||||
"glb": "86b5d9065583eabca29ad89b7ccb67ac640bada57af8504c6448027fa05bd655.glb",
|
||||
"glb_sha256": "f38ffdbebb6f60e4e92d3b8993cc3001c502a8223c72bfb3688812d9217a67b2",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"13292b7af3472178d07e40005acd73b09d61f1d9f9570606cc74f115a42a1637": {
|
||||
"source": "Tree/ymir work/tree/b2_redoak_rt.spt",
|
||||
"source_sha256": "13292b7af3472178d07e40005acd73b09d61f1d9f9570606cc74f115a42a1637",
|
||||
"glb": "13292b7af3472178d07e40005acd73b09d61f1d9f9570606cc74f115a42a1637.glb",
|
||||
"glb_sha256": "6fc61c59dc838a768f10b749a9b7ce1ea659e4a9d6f9fc6ee6c887c0532adc6c",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"55ee1c716113b30ebc1e4166698765f041f1c094bf28d4ec86f8ca61202e5116": {
|
||||
"source": "Tree/ymir work/tree/b2_redoak_rt2.spt",
|
||||
"source_sha256": "55ee1c716113b30ebc1e4166698765f041f1c094bf28d4ec86f8ca61202e5116",
|
||||
"glb": "55ee1c716113b30ebc1e4166698765f041f1c094bf28d4ec86f8ca61202e5116.glb",
|
||||
"glb_sha256": "3200e730f4551792a504f20e4046e7bcf466e1e51d90229c9328b3ea63bc47cb",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"c50b043a6ceed03fbdac17cd0a861b1de1d06f4c5933a9078d073f42867e1a22": {
|
||||
"source": "Tree/ymir work/tree/b2_redoak_rt3.spt",
|
||||
"source_sha256": "c50b043a6ceed03fbdac17cd0a861b1de1d06f4c5933a9078d073f42867e1a22",
|
||||
"glb": "c50b043a6ceed03fbdac17cd0a861b1de1d06f4c5933a9078d073f42867e1a22.glb",
|
||||
"glb_sha256": "6781839f9fcdcdbae7b156b5708436e2580781a11bb784ff11f5f088a841471a",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"0d62629ce2423bdfce51595038cab213dec628acb4cf063b0b271279a28e8832": {
|
||||
"source": "Tree/ymir work/tree/b2_redoak_rt4.spt",
|
||||
"source_sha256": "0d62629ce2423bdfce51595038cab213dec628acb4cf063b0b271279a28e8832",
|
||||
"glb": "0d62629ce2423bdfce51595038cab213dec628acb4cf063b0b271279a28e8832.glb",
|
||||
"glb_sha256": "febe8dcbe1880cec8f91dc5844a55749c8d183e86c1b581d07440f6bf38ab794",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"eace2fb1af759da813559a33d38690596a066397983994cfea75232441ca3086": {
|
||||
"source": "Tree/ymir work/tree/b3_beech_rt.spt",
|
||||
"source_sha256": "eace2fb1af759da813559a33d38690596a066397983994cfea75232441ca3086",
|
||||
"glb": "eace2fb1af759da813559a33d38690596a066397983994cfea75232441ca3086.glb",
|
||||
"glb_sha256": "1d29e58f3e04b4dbfe4cbfb91403bddcfed2af0f282636f506d358b5f15cccb1",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"65846f0ea0ac8ace155a11cc6a41631d3330e6db25ba9a9c8b8171b96fdfde67": {
|
||||
"source": "Tree/ymir work/tree/b3_beech_rt2.spt",
|
||||
"source_sha256": "65846f0ea0ac8ace155a11cc6a41631d3330e6db25ba9a9c8b8171b96fdfde67",
|
||||
"glb": "65846f0ea0ac8ace155a11cc6a41631d3330e6db25ba9a9c8b8171b96fdfde67.glb",
|
||||
"glb_sha256": "2bdbe584e694ec4516803ac0966f741cf39920f20c4692b6f5f4496e5fff0b06",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"09c12d2bf8ef2c5ada7d54323b7b11816bebc56cc3fddd7373aba4eed7d3527e": {
|
||||
"source": "Tree/ymir work/tree/b3_beech_rt3.spt",
|
||||
"source_sha256": "09c12d2bf8ef2c5ada7d54323b7b11816bebc56cc3fddd7373aba4eed7d3527e",
|
||||
"glb": "09c12d2bf8ef2c5ada7d54323b7b11816bebc56cc3fddd7373aba4eed7d3527e.glb",
|
||||
"glb_sha256": "cae93d33e0849b769cb9070bb094239a2d68c33e22942df24836190757c3cd98",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"e622c7689d6525c09b22244a9a112ce9448c1c189cbe7f0468da9de82b8d9c36": {
|
||||
"source": "Tree/ymir work/tree/b3_beech_rt_fall.spt",
|
||||
"source_sha256": "e622c7689d6525c09b22244a9a112ce9448c1c189cbe7f0468da9de82b8d9c36",
|
||||
"glb": "e622c7689d6525c09b22244a9a112ce9448c1c189cbe7f0468da9de82b8d9c36.glb",
|
||||
"glb_sha256": "59e6e7c3378af28c44a3293b1bd026023cbcc9c5447be1684e63a88d9b3691f8",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"8aaf7a77ff61d8dd3828057df396ae27a6471faa7db94a6f2c93c0522ce22aa0": {
|
||||
"source": "Tree/ymir work/tree/b3_beech_rt_fall2.spt",
|
||||
"source_sha256": "8aaf7a77ff61d8dd3828057df396ae27a6471faa7db94a6f2c93c0522ce22aa0",
|
||||
"glb": "8aaf7a77ff61d8dd3828057df396ae27a6471faa7db94a6f2c93c0522ce22aa0.glb",
|
||||
"glb_sha256": "3e684dc00afd7451b28ed3f89a00baa7ea6c9d45c442caad332b9596ed0b872c",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"6600b5cae4c4f473b5cea7e9d90614ffeb3559807d4605d6d729ab7b3182eb77": {
|
||||
"source": "Tree/ymir work/tree/b3_pagodatree_rt_winter.spt",
|
||||
"source_sha256": "6600b5cae4c4f473b5cea7e9d90614ffeb3559807d4605d6d729ab7b3182eb77",
|
||||
"glb": "6600b5cae4c4f473b5cea7e9d90614ffeb3559807d4605d6d729ab7b3182eb77.glb",
|
||||
"glb_sha256": "bec163b2c1fa99b26d97bad86155a401ab19c067b2acb160a747fceb5b168226",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"ea34cd93e320c38e79837ab348022ea6cab4a62b295fd20a54c7a4a9688129f5": {
|
||||
"source": "Tree/ymir work/tree/b3_pagodatree_rt_winter2.spt",
|
||||
"source_sha256": "ea34cd93e320c38e79837ab348022ea6cab4a62b295fd20a54c7a4a9688129f5",
|
||||
"glb": "ea34cd93e320c38e79837ab348022ea6cab4a62b295fd20a54c7a4a9688129f5.glb",
|
||||
"glb_sha256": "63aa6ef7fe8181bc1877e86a6b3f1f3bd617a2af303208006289c8e68a76b859",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"e03e7c40dd56befae1804550d90f114a1496f7a5c0fa18ae111de5a19372639b": {
|
||||
"source": "Tree/ymir work/tree/b3_shingleoak_rt.spt",
|
||||
"source_sha256": "e03e7c40dd56befae1804550d90f114a1496f7a5c0fa18ae111de5a19372639b",
|
||||
"glb": "e03e7c40dd56befae1804550d90f114a1496f7a5c0fa18ae111de5a19372639b.glb",
|
||||
"glb_sha256": "54bb8cf813b9c6f05f14ea7dbb39689a3a26f9737e7526969c2bea070b8bf78f",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"d59d8a429a63272bcd21b403cd581556b57a140f5cdc65c7af329d30b6770d26": {
|
||||
"source": "Tree/ymir work/tree/b3_shingleoak_rt2.spt",
|
||||
"source_sha256": "d59d8a429a63272bcd21b403cd581556b57a140f5cdc65c7af329d30b6770d26",
|
||||
"glb": "d59d8a429a63272bcd21b403cd581556b57a140f5cdc65c7af329d30b6770d26.glb",
|
||||
"glb_sha256": "6b85b0a649472c7268791a0adce367099b4fbb783d07ad3a508e0aa88d77c331",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"2bec6d9317e3947386c56c4183db454fe629af9fa87de759324928e681eb5742": {
|
||||
"source": "Tree/ymir work/tree/b3_shingleoak_rt3.spt",
|
||||
"source_sha256": "2bec6d9317e3947386c56c4183db454fe629af9fa87de759324928e681eb5742",
|
||||
"glb": "2bec6d9317e3947386c56c4183db454fe629af9fa87de759324928e681eb5742.glb",
|
||||
"glb_sha256": "3a3fc8e8afa93b2a65806fd5d6eb625a05426c6f8a99c50a77ac1c197bf9a6f5",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"0a15ca2a0809cc74e6d72ed48b137906f02f0e44994228fa9f840d76a6ca52cc": {
|
||||
"source": "Tree/ymir work/tree/b3_shingleoak_rt4.spt",
|
||||
"source_sha256": "0a15ca2a0809cc74e6d72ed48b137906f02f0e44994228fa9f840d76a6ca52cc",
|
||||
"glb": "0a15ca2a0809cc74e6d72ed48b137906f02f0e44994228fa9f840d76a6ca52cc.glb",
|
||||
"glb_sha256": "39dc26f0713574b98e8bba0a26ff448bd6fabd97c5b66880f155516f536d35a4",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"dbc300acb7356f4f51e897a2e248a2883241ea570d5d8cded218b31401206534": {
|
||||
"source": "Tree/ymir work/tree/b3_shingleoak_rt5.spt",
|
||||
"source_sha256": "dbc300acb7356f4f51e897a2e248a2883241ea570d5d8cded218b31401206534",
|
||||
"glb": "dbc300acb7356f4f51e897a2e248a2883241ea570d5d8cded218b31401206534.glb",
|
||||
"glb_sha256": "08dc609a9aa5b16ce943dfd6bc63d2db45daf3bc7252fd6d1ee58a7ce6449685",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"0e8ab0197ee0db8e3a40e4b8d6c5c8f0b291284d2ccb7e13cee41d0f0792cc6f": {
|
||||
"source": "Tree/ymir work/tree/b3_umbrellathorn_rt_flowers.spt",
|
||||
"source_sha256": "0e8ab0197ee0db8e3a40e4b8d6c5c8f0b291284d2ccb7e13cee41d0f0792cc6f",
|
||||
"glb": "0e8ab0197ee0db8e3a40e4b8d6c5c8f0b291284d2ccb7e13cee41d0f0792cc6f.glb",
|
||||
"glb_sha256": "580a3ff0582a7723250650e8b0828912000faf494afb25ace42578e0d1397bb8",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"3c5c75535819e405b61cd21c89d514a8d2b0e6afdd75428cc0687745a3314cfe": {
|
||||
"source": "Tree/ymir work/tree/b3_umbrellathorn_rt_flowers2.spt",
|
||||
"source_sha256": "3c5c75535819e405b61cd21c89d514a8d2b0e6afdd75428cc0687745a3314cfe",
|
||||
"glb": "3c5c75535819e405b61cd21c89d514a8d2b0e6afdd75428cc0687745a3314cfe.glb",
|
||||
"glb_sha256": "2483acf297ce1f35e3ef297ff14e84c33b16bfae885fb04f373a601ad41cfab6",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"a6592779c9460b004be7956123a13f439bef0669dbfdad4bd330b78c44b100d2": {
|
||||
"source": "Tree/ymir work/tree/b3_umbrellathorn_rt_flowers3.spt",
|
||||
"source_sha256": "a6592779c9460b004be7956123a13f439bef0669dbfdad4bd330b78c44b100d2",
|
||||
"glb": "a6592779c9460b004be7956123a13f439bef0669dbfdad4bd330b78c44b100d2.glb",
|
||||
"glb_sha256": "0d5fe2e83f4621f6cefbbf8e645306af026c540364d05d91e2757d8d4775ceff",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"44ec99e53b3158a6619ec7a5cb4110bfb67ff9943224b068a8bc99fa1d92c0d0": {
|
||||
"source": "Tree/ymir work/tree/b3_umbrellathorn_rt_flowers4.spt",
|
||||
"source_sha256": "44ec99e53b3158a6619ec7a5cb4110bfb67ff9943224b068a8bc99fa1d92c0d0",
|
||||
"glb": "44ec99e53b3158a6619ec7a5cb4110bfb67ff9943224b068a8bc99fa1d92c0d0.glb",
|
||||
"glb_sha256": "1efd17b58f6dd39b3df3e7de84d20a1d4740e8d53c05a08080a3e335619e6ac8",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"d85676762825b8324ebeba85bc9a0e2242da8d225c5699c042f469abd17d01d7": {
|
||||
"source": "Tree/ymir work/tree/christmastree1.spt",
|
||||
"source_sha256": "d85676762825b8324ebeba85bc9a0e2242da8d225c5699c042f469abd17d01d7",
|
||||
"glb": "d85676762825b8324ebeba85bc9a0e2242da8d225c5699c042f469abd17d01d7.glb",
|
||||
"glb_sha256": "6836fef2133fbc14a4ac17f3762cfe64b596e2cc1dbae818c80fe4eb421a510f",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"6277b6d6dd747b0a6aa067fc2a27e8e7dad3bd8c9c755d6b124bc474b4107a1d": {
|
||||
"source": "Tree/ymir work/tree/christmastree2.spt",
|
||||
"source_sha256": "6277b6d6dd747b0a6aa067fc2a27e8e7dad3bd8c9c755d6b124bc474b4107a1d",
|
||||
"glb": "6277b6d6dd747b0a6aa067fc2a27e8e7dad3bd8c9c755d6b124bc474b4107a1d.glb",
|
||||
"glb_sha256": "451bd2edca71c9aa5c658ce8bc1353b7315530220f1d1458c037d5ea007b2794",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"074755f44edc3d836c20b8e254c61af805c3e7f3cbe1e65f76bb35bd3d66ca8f": {
|
||||
"source": "Tree/ymir work/tree/christmastree3.spt",
|
||||
"source_sha256": "074755f44edc3d836c20b8e254c61af805c3e7f3cbe1e65f76bb35bd3d66ca8f",
|
||||
"glb": "074755f44edc3d836c20b8e254c61af805c3e7f3cbe1e65f76bb35bd3d66ca8f.glb",
|
||||
"glb_sha256": "6445e98dd9760e3371dbcd13673b539b2c6be6450dc883605c50b3d5fac3f825",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"0ce9fe068b0a227cb4ce1c36dbeff5792ae6488f012c028b54ab89d7ef2b2f3b": {
|
||||
"source": "Tree/ymir work/tree/n1_baobab_rt_winter.spt",
|
||||
"source_sha256": "0ce9fe068b0a227cb4ce1c36dbeff5792ae6488f012c028b54ab89d7ef2b2f3b",
|
||||
"glb": "0ce9fe068b0a227cb4ce1c36dbeff5792ae6488f012c028b54ab89d7ef2b2f3b.glb",
|
||||
"glb_sha256": "d49a2346357486cab5368ecb1a32a8e728bd45318b301b86755c41d481f3712f",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"0d766295707ebd0e6af56bfc49ed1bca8bc11f7b15f79be44e221bbe9e18d53e": {
|
||||
"source": "Tree/ymir work/tree/n1_beech_rt_winter.spt",
|
||||
"source_sha256": "0d766295707ebd0e6af56bfc49ed1bca8bc11f7b15f79be44e221bbe9e18d53e",
|
||||
"glb": "0d766295707ebd0e6af56bfc49ed1bca8bc11f7b15f79be44e221bbe9e18d53e.glb",
|
||||
"glb_sha256": "031cde20e4c46d5f75cda94fd783834614d31584f7af36e9be2218dabc6a0cbb",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"e5497e163459d6ad06745e4b8a5ab95422fb59143e7aa76cf40ac65d242872b3": {
|
||||
"source": "Tree/ymir work/tree/n1_beech_rt_winter02.spt",
|
||||
"source_sha256": "e5497e163459d6ad06745e4b8a5ab95422fb59143e7aa76cf40ac65d242872b3",
|
||||
"glb": "e5497e163459d6ad06745e4b8a5ab95422fb59143e7aa76cf40ac65d242872b3.glb",
|
||||
"glb_sha256": "f542b8c33350569b80f2a3c88fc1db22be93ed51fbcfe46654d2b29fccaa413a",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"41997e16e6110e21096ffa2d85f0d2135e7b8a4ec82a869f899a6325776a2225": {
|
||||
"source": "Tree/ymir work/tree/n1_beech_rt_winter03.spt",
|
||||
"source_sha256": "41997e16e6110e21096ffa2d85f0d2135e7b8a4ec82a869f899a6325776a2225",
|
||||
"glb": "41997e16e6110e21096ffa2d85f0d2135e7b8a4ec82a869f899a6325776a2225.glb",
|
||||
"glb_sha256": "fd2fd865a012ba6f53b0bdd0eea8971c7858826cc4cbb08d3a6db1becf027fc0",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"b60fa3d6329d76d4b85da226e88c36241bf8fb4e3a3fc5e1316f0a64d7e2c6ad": {
|
||||
"source": "Tree/ymir work/tree/n1_coloradobluespruce_rt_01.spt",
|
||||
"source_sha256": "b60fa3d6329d76d4b85da226e88c36241bf8fb4e3a3fc5e1316f0a64d7e2c6ad",
|
||||
"glb": "b60fa3d6329d76d4b85da226e88c36241bf8fb4e3a3fc5e1316f0a64d7e2c6ad.glb",
|
||||
"glb_sha256": "82d906bb624b0041c3d687e3af51cff8ed524ba75e6432a5f293554d5d4ff137",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"265aef90b037111a8d08bd4f258501872be9fc0b4bacf6ad17820241c5f959a1": {
|
||||
"source": "Tree/ymir work/tree/n1_coloradobluespruce_rt_02.spt",
|
||||
"source_sha256": "265aef90b037111a8d08bd4f258501872be9fc0b4bacf6ad17820241c5f959a1",
|
||||
"glb": "265aef90b037111a8d08bd4f258501872be9fc0b4bacf6ad17820241c5f959a1.glb",
|
||||
"glb_sha256": "6265bd35d1da9f9daa34a15b34dd9cadc5af9d6346c0b9104b2c3d582c510225",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"2e3fe98b0ca1aae0ad512741f9465e42653b4c4df7345bc915e6b6b3bf80d27d": {
|
||||
"source": "Tree/ymir work/tree/n1_coloradobluespruce_rt_03.spt",
|
||||
"source_sha256": "2e3fe98b0ca1aae0ad512741f9465e42653b4c4df7345bc915e6b6b3bf80d27d",
|
||||
"glb": "2e3fe98b0ca1aae0ad512741f9465e42653b4c4df7345bc915e6b6b3bf80d27d.glb",
|
||||
"glb_sha256": "cbeb5930c57e2dbefbe9c50987275e7abc2b1ac9aa9cf190f60de71dae75f52b",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"4c3b7f1bc32ca54a581a22eb99a5229c066a2e3db84d73c4a260b41ecb4151d6": {
|
||||
"source": "Tree/ymir work/tree/n1_commonolive_rt_winter.spt",
|
||||
"source_sha256": "4c3b7f1bc32ca54a581a22eb99a5229c066a2e3db84d73c4a260b41ecb4151d6",
|
||||
"glb": "4c3b7f1bc32ca54a581a22eb99a5229c066a2e3db84d73c4a260b41ecb4151d6.glb",
|
||||
"glb_sha256": "a2fb958788a84301f9008e4efe1ea9994314d28b4b3954649c64b3033bf912c0",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"e63e6fd8aec38f5a4dea10edce507870f834cf1da5fbd8b5e789dc75f773957c": {
|
||||
"source": "Tree/ymir work/tree/n1_montereycypress_rt_winter_01.spt",
|
||||
"source_sha256": "e63e6fd8aec38f5a4dea10edce507870f834cf1da5fbd8b5e789dc75f773957c",
|
||||
"glb": "e63e6fd8aec38f5a4dea10edce507870f834cf1da5fbd8b5e789dc75f773957c.glb",
|
||||
"glb_sha256": "9dc165cb8f6417f9e27486db714809722b5e85ff4ed827b21a0fe1d52feee89f",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"bd813274fcc6fc3c8bf26a9bc85eb6b3c18d0a4a68dd0a51e13183f4634680da": {
|
||||
"source": "Tree/ymir work/tree/n1_montereycypress_rt_winter_02.spt",
|
||||
"source_sha256": "bd813274fcc6fc3c8bf26a9bc85eb6b3c18d0a4a68dd0a51e13183f4634680da",
|
||||
"glb": "bd813274fcc6fc3c8bf26a9bc85eb6b3c18d0a4a68dd0a51e13183f4634680da.glb",
|
||||
"glb_sha256": "f64d701e3ec752f566eef179ed62d613fd20d7dcc0bd86dcb95c1e3a0ef56c86",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"1af978f7efd1be5ba7af90056c4b933f74154c60a47a20fe88f4872aaf7bc862": {
|
||||
"source": "Tree/ymir work/tree/n1_montereycypress_rt_winter_03.spt",
|
||||
"source_sha256": "1af978f7efd1be5ba7af90056c4b933f74154c60a47a20fe88f4872aaf7bc862",
|
||||
"glb": "1af978f7efd1be5ba7af90056c4b933f74154c60a47a20fe88f4872aaf7bc862.glb",
|
||||
"glb_sha256": "f80e080f78042b751116ef056edf98501922de0bb46c6e0efb950e17115afbbe",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"36389501b6156b934f960d826ac2e3ecae86430cf53dc88dd6c30f5a8415aba9": {
|
||||
"source": "Tree/ymir work/tree/n1_tulip_rt_winter_01.spt",
|
||||
"source_sha256": "36389501b6156b934f960d826ac2e3ecae86430cf53dc88dd6c30f5a8415aba9",
|
||||
"glb": "36389501b6156b934f960d826ac2e3ecae86430cf53dc88dd6c30f5a8415aba9.glb",
|
||||
"glb_sha256": "ce0f23b6d5931ebeea06862a4ffef37b2274dc0b8643ec2f5768f1b0df3ae858",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 1,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"0df26ab085d443bccc61d8ec878b61117f64db3b3ffa31e70fa0fce6d5f59361": {
|
||||
"source": "Tree/ymir work/tree/n1_whitepine_rt_low_01.spt",
|
||||
"source_sha256": "0df26ab085d443bccc61d8ec878b61117f64db3b3ffa31e70fa0fce6d5f59361",
|
||||
"glb": "0df26ab085d443bccc61d8ec878b61117f64db3b3ffa31e70fa0fce6d5f59361.glb",
|
||||
"glb_sha256": "48bd12ddffdc0aee165a29bfc6fd0dcbfe1366aec5542bcee102bf8d5d82c3e2",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"ac5bb9b19999fe6d20793898edc7b709b1ba792e6cac2cc7ed5fcd64abdfb03f": {
|
||||
"source": "Tree/ymir work/tree/n1_whitepine_rt_low_02.spt",
|
||||
"source_sha256": "ac5bb9b19999fe6d20793898edc7b709b1ba792e6cac2cc7ed5fcd64abdfb03f",
|
||||
"glb": "ac5bb9b19999fe6d20793898edc7b709b1ba792e6cac2cc7ed5fcd64abdfb03f.glb",
|
||||
"glb_sha256": "fa1fe6e118c91b6d1276b17ed05297eed6349e4c29726e11a51de48252dbf787",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"34314fd26754a94e9215723fd970a09b360eef0f8fa7e93c55c44b6dadd4b4c8": {
|
||||
"source": "Tree/ymir work/tree/n2_aloevera_rt_flowers_01.spt",
|
||||
"source_sha256": "34314fd26754a94e9215723fd970a09b360eef0f8fa7e93c55c44b6dadd4b4c8",
|
||||
"glb": "34314fd26754a94e9215723fd970a09b360eef0f8fa7e93c55c44b6dadd4b4c8.glb",
|
||||
"glb_sha256": "96d7b310fa8d13e910b11e5524a1a30886e21c9e715290c64d1df2e9b4298d17",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"e0c3f6cfe9200acf3fe66fcc33fa52e2bbab55a48a35815178e74ee80e717c36": {
|
||||
"source": "Tree/ymir work/tree/n2_aloevera_rt_flowers_02.spt",
|
||||
"source_sha256": "e0c3f6cfe9200acf3fe66fcc33fa52e2bbab55a48a35815178e74ee80e717c36",
|
||||
"glb": "e0c3f6cfe9200acf3fe66fcc33fa52e2bbab55a48a35815178e74ee80e717c36.glb",
|
||||
"glb_sha256": "968300bd31c235557926343e46d7335ae75644aff6d0ca58f3a3e4a1963c5e51",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"f7c94a390c712edae5557d03849373c713d4ce28fba6080d87fc761216c4a26d": {
|
||||
"source": "Tree/ymir work/tree/n2_bananatree_rt_01.spt",
|
||||
"source_sha256": "f7c94a390c712edae5557d03849373c713d4ce28fba6080d87fc761216c4a26d",
|
||||
"glb": "f7c94a390c712edae5557d03849373c713d4ce28fba6080d87fc761216c4a26d.glb",
|
||||
"glb_sha256": "0b43c6087d26a19e6863a1d488eb6e3e524240793d850b27f844e4c194818afa",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"23b662d2b6d87d268460e4ae100b618ecfac6dd5262f59a2912e6dfe74530436": {
|
||||
"source": "Tree/ymir work/tree/n2_bananatree_rt_02.spt",
|
||||
"source_sha256": "23b662d2b6d87d268460e4ae100b618ecfac6dd5262f59a2912e6dfe74530436",
|
||||
"glb": "23b662d2b6d87d268460e4ae100b618ecfac6dd5262f59a2912e6dfe74530436.glb",
|
||||
"glb_sha256": "c5bd49676be213f69141b644b109a890f682fcc31ae8bf4fb0d078b72b28d8b8",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"93ded82028c0f2e97d0403ec045b89bbc1ac859ad8b84a2e1930e0503907b354": {
|
||||
"source": "Tree/ymir work/tree/n2_cinnamonfern_rt_01.spt",
|
||||
"source_sha256": "93ded82028c0f2e97d0403ec045b89bbc1ac859ad8b84a2e1930e0503907b354",
|
||||
"glb": "93ded82028c0f2e97d0403ec045b89bbc1ac859ad8b84a2e1930e0503907b354.glb",
|
||||
"glb_sha256": "027fe6300b18a9608ffe465d1e1c77783a8c05c17e99c2999e058095ed62de05",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 1,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"dc389cbfc25b6e3226e961e7e392ed96c7a789c0dfc1d392b0a1950e81f59f9e": {
|
||||
"source": "Tree/ymir work/tree/n2_cinnamonfern_rt_02.spt",
|
||||
"source_sha256": "dc389cbfc25b6e3226e961e7e392ed96c7a789c0dfc1d392b0a1950e81f59f9e",
|
||||
"glb": "dc389cbfc25b6e3226e961e7e392ed96c7a789c0dfc1d392b0a1950e81f59f9e.glb",
|
||||
"glb_sha256": "0c537775ba7e98e11b6d5b74a6665dfd5eb74c94f70ad39c80c4f0979b5246ac",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 1,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"82566982c7decbccbbb9e50f0b1d399a86bed94a968e0a78e2ce8b25989d2462": {
|
||||
"source": "Tree/ymir work/tree/n2_cinnamonfern_rt_03.spt",
|
||||
"source_sha256": "82566982c7decbccbbb9e50f0b1d399a86bed94a968e0a78e2ce8b25989d2462",
|
||||
"glb": "82566982c7decbccbbb9e50f0b1d399a86bed94a968e0a78e2ce8b25989d2462.glb",
|
||||
"glb_sha256": "1d38479f01b5dac599ff8dbc80dab1657671950047da6bae43e7a201562da106",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 1,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"af5abcd685bf92c9597740c9c85168f6104e62c12e30117ca5759bf555f2c6ff": {
|
||||
"source": "Tree/ymir work/tree/n2_coconutpalm_rt_01.spt",
|
||||
"source_sha256": "af5abcd685bf92c9597740c9c85168f6104e62c12e30117ca5759bf555f2c6ff",
|
||||
"glb": "af5abcd685bf92c9597740c9c85168f6104e62c12e30117ca5759bf555f2c6ff.glb",
|
||||
"glb_sha256": "3344943038999faf012f8d1520b2feaaab367c06a6b24748685a233b89f7ec70",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"e45bdc521daaeb53191a995485513b046b0602b60d55185e465ded20a8242828": {
|
||||
"source": "Tree/ymir work/tree/n2_coconutpalm_rt_02.spt",
|
||||
"source_sha256": "e45bdc521daaeb53191a995485513b046b0602b60d55185e465ded20a8242828",
|
||||
"glb": "e45bdc521daaeb53191a995485513b046b0602b60d55185e465ded20a8242828.glb",
|
||||
"glb_sha256": "3f46282c3c8d094206d516475cf1e086e87af584c4537c3d48da1e2ee544a248",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"75b89b54281bedd408be91863cfbf1131a7c9fce5c0e153e601db3c7195c8dd6": {
|
||||
"source": "Tree/ymir work/tree/n2_coconutpalm_rt_03.spt",
|
||||
"source_sha256": "75b89b54281bedd408be91863cfbf1131a7c9fce5c0e153e601db3c7195c8dd6",
|
||||
"glb": "75b89b54281bedd408be91863cfbf1131a7c9fce5c0e153e601db3c7195c8dd6.glb",
|
||||
"glb_sha256": "1e19c9fe65ef02d0277206f4737eeafec5541ba6bc2619dcb015e31bf8d76800",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"8a6d6468b7f97040b08ba70718650abbd0d0c4684fa6e092b0a603717ed0ec28": {
|
||||
"source": "Tree/ymir work/tree/n2_curlypalm_rt_01.spt",
|
||||
"source_sha256": "8a6d6468b7f97040b08ba70718650abbd0d0c4684fa6e092b0a603717ed0ec28",
|
||||
"glb": "8a6d6468b7f97040b08ba70718650abbd0d0c4684fa6e092b0a603717ed0ec28.glb",
|
||||
"glb_sha256": "a0859095e4b20c71d33e3cde76696584880df357d3642c07d79355cb0d732809",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"de5e22bb1610c61bcb00e3835698b6a9b50b67263a438b9ba7400157dce42b5e": {
|
||||
"source": "Tree/ymir work/tree/n2_curlypalm_rt_02.spt",
|
||||
"source_sha256": "de5e22bb1610c61bcb00e3835698b6a9b50b67263a438b9ba7400157dce42b5e",
|
||||
"glb": "de5e22bb1610c61bcb00e3835698b6a9b50b67263a438b9ba7400157dce42b5e.glb",
|
||||
"glb_sha256": "c8b1d7ad7faf78e14b0c50f7c33dd9712a2c79dbec54a574945e2b20f7e22d4a",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"97ce0c94956eeafad580424081ae4ab767f01e948ab9461a9b48e5cf8bd824af": {
|
||||
"source": "Tree/ymir work/tree/n2_curlypalm_rt_03.spt",
|
||||
"source_sha256": "97ce0c94956eeafad580424081ae4ab767f01e948ab9461a9b48e5cf8bd824af",
|
||||
"glb": "97ce0c94956eeafad580424081ae4ab767f01e948ab9461a9b48e5cf8bd824af.glb",
|
||||
"glb_sha256": "700aa9caba46ed1b7141d58a653d77ea9eb96911172d1a4dacb414328c8f18ee",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"6e24a4896134057a1bc495f0f8af32ca74a7b51e0d54baa612f6dcd36a99b54e": {
|
||||
"source": "Tree/ymir work/tree/n2_datepalm_rt_01.spt",
|
||||
"source_sha256": "6e24a4896134057a1bc495f0f8af32ca74a7b51e0d54baa612f6dcd36a99b54e",
|
||||
"glb": "6e24a4896134057a1bc495f0f8af32ca74a7b51e0d54baa612f6dcd36a99b54e.glb",
|
||||
"glb_sha256": "7c2a38b68b0b33d46db13830c12302a1962584e51e628386d654509998e1795f",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"55de8a592ad3d9294583bcf27c80fba3fe71afdc669c5657ee7cc77a4002d255": {
|
||||
"source": "Tree/ymir work/tree/n2_datepalm_rt_02.spt",
|
||||
"source_sha256": "55de8a592ad3d9294583bcf27c80fba3fe71afdc669c5657ee7cc77a4002d255",
|
||||
"glb": "55de8a592ad3d9294583bcf27c80fba3fe71afdc669c5657ee7cc77a4002d255.glb",
|
||||
"glb_sha256": "e7391ec2d87aa7df6f87943e4faaf91de5951dccb045e6935844c997f7de1179",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"2007d4ba90f12b8a00d2a0a539954e420c37f2151f438c5ad06eb63a78fe853d": {
|
||||
"source": "Tree/ymir work/tree/n2_datepalm_rt_03.spt",
|
||||
"source_sha256": "2007d4ba90f12b8a00d2a0a539954e420c37f2151f438c5ad06eb63a78fe853d",
|
||||
"glb": "2007d4ba90f12b8a00d2a0a539954e420c37f2151f438c5ad06eb63a78fe853d.glb",
|
||||
"glb_sha256": "ec41d7cb6c58864cc32bccca5e364d8fa4746501d4bf9a37d3f64c611834e0c9",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 2,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"2bc2d707e302c58d099e64615ae127371c93700f91d52d31e8ec6f63010e2c0f": {
|
||||
"source": "Tree/ymir work/tree/n2_joshuatree_rt_01.spt",
|
||||
"source_sha256": "2bc2d707e302c58d099e64615ae127371c93700f91d52d31e8ec6f63010e2c0f",
|
||||
"glb": "2bc2d707e302c58d099e64615ae127371c93700f91d52d31e8ec6f63010e2c0f.glb",
|
||||
"glb_sha256": "27937a1b7cb30186a7041b4c8e405e531a3152004d5365082d9e0908e3998670",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 4,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"111cb80abecb5c5a35aaa8315ad6ec4c59772af927729780e0add02c9ba262b5": {
|
||||
"source": "Tree/ymir work/tree/n2_joshuatree_rt_02.spt",
|
||||
"source_sha256": "111cb80abecb5c5a35aaa8315ad6ec4c59772af927729780e0add02c9ba262b5",
|
||||
"glb": "111cb80abecb5c5a35aaa8315ad6ec4c59772af927729780e0add02c9ba262b5.glb",
|
||||
"glb_sha256": "6082d34315db4cd58e606b4b35cdbd07ab374d7587580512e07b0e27cfdedb11",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 4,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"a89a40ac942ee7a3d701a6835450a513a336e9835d20750036374e27c259b2d5": {
|
||||
"source": "Tree/ymir work/tree/n2_joshuatree_rt_03.spt",
|
||||
"source_sha256": "a89a40ac942ee7a3d701a6835450a513a336e9835d20750036374e27c259b2d5",
|
||||
"glb": "a89a40ac942ee7a3d701a6835450a513a336e9835d20750036374e27c259b2d5.glb",
|
||||
"glb_sha256": "5964a02431360700dabd0f88cddde3419141f9f2626b48068b80a6da4110ddf6",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 6,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"19685a989e47f21d14fb9c2f2e71fd86930f8841a3dafae42b608988c3317119": {
|
||||
"source": "Tree/ymir work/tree/n2_palmetto_rt_01.spt",
|
||||
"source_sha256": "19685a989e47f21d14fb9c2f2e71fd86930f8841a3dafae42b608988c3317119",
|
||||
"glb": "19685a989e47f21d14fb9c2f2e71fd86930f8841a3dafae42b608988c3317119.glb",
|
||||
"glb_sha256": "6fc27607202b42a36b0cea01228e05e3ffd36fb21800ed5ba171831c8a4b7ae3",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"e167a7cb1d19c9d118be00d5dff39221695a582ec7caeabfae1f7826aff0d823": {
|
||||
"source": "Tree/ymir work/tree/n2_palmetto_rt_02.spt",
|
||||
"source_sha256": "e167a7cb1d19c9d118be00d5dff39221695a582ec7caeabfae1f7826aff0d823",
|
||||
"glb": "e167a7cb1d19c9d118be00d5dff39221695a582ec7caeabfae1f7826aff0d823.glb",
|
||||
"glb_sha256": "1597e961990b4bae697f92238b93978910c39d839f8585baaa44cda135197cde",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
},
|
||||
"d096c9a78ede5fb7db97685b6dab4967f9dad9a24dbf147b762faffdf1281fc4": {
|
||||
"source": "Tree/ymir work/tree/n2_palmetto_rt_03.spt",
|
||||
"source_sha256": "d096c9a78ede5fb7db97685b6dab4967f9dad9a24dbf147b762faffdf1281fc4",
|
||||
"glb": "d096c9a78ede5fb7db97685b6dab4967f9dad9a24dbf147b762faffdf1281fc4.glb",
|
||||
"glb_sha256": "cb67edad8c58da648f2e7b19e5cce0d1ec665bb7738f0fa91ac0fd7dab1176ec",
|
||||
"native_extractor": "spt_extract.exe",
|
||||
"extractor_runs": 2,
|
||||
"primitives": 5,
|
||||
"leaves": "static_extracted_cards",
|
||||
"wind": "not_baked"
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-4
@@ -10,10 +10,21 @@ set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
REPO="$(pwd)"
|
||||
CFG="${1:-debug}"
|
||||
OUT="$REPO/build/export"
|
||||
OUT="${MT_MAC_OUTPUT_DIR:-$REPO/build/export}"
|
||||
APP="$OUT/mtgodot-poc.app"
|
||||
GODOT="${GODOT:-godot}"
|
||||
MAC_ARCHES="${MT_MAC_ARCHES:-universal}"
|
||||
ENGINE_OVERRIDE="${MT_MAC_ENGINE:-}"
|
||||
if [ -n "$ENGINE_OVERRIDE" ]; then
|
||||
test -x "$ENGINE_OVERRIDE"
|
||||
ENGINE_INFO="$(lipo -info "$ENGINE_OVERRIDE")"
|
||||
case "$MAC_ARCHES:$ENGINE_INFO" in
|
||||
universal:*x86_64*arm64*|universal:*arm64*x86_64*|arm64:*arm64*|x86_64:*x86_64*) ;;
|
||||
*) echo "错误:自定义引擎架构不匹配:$ENGINE_INFO" >&2; exit 1 ;;
|
||||
esac
|
||||
echo "自定义引擎:$ENGINE_OVERRIDE"
|
||||
"$ENGINE_OVERRIDE" --version
|
||||
fi
|
||||
BUILD_TYPE="Debug"
|
||||
if [ "$CFG" = release ]; then
|
||||
BUILD_TYPE="Release"
|
||||
@@ -55,10 +66,23 @@ ditto "$REPO/bgm" "$APP/Contents/Resources/bgm"
|
||||
test -f "$APP/Contents/Resources/assets/asset_index.txt"
|
||||
|
||||
echo "== 4. 签名(默认 ad-hoc;CODESIGN_IDENTITY 可切正式证书)=="
|
||||
if [ -n "$ENGINE_OVERRIDE" ]; then
|
||||
cp "$ENGINE_OVERRIDE" "$APP/Contents/MacOS/mtgodot-poc"
|
||||
fi
|
||||
CODESIGN_IDENTITY="${CODESIGN_IDENTITY:--}"
|
||||
find "$APP/Contents" -type f \( -name '*.dylib' -o -name '*.so' -o -name '*.a' \) -exec \
|
||||
codesign --force --options runtime --timestamp=none --sign "$CODESIGN_IDENTITY" {} \; 2>/dev/null || true
|
||||
codesign --force --options runtime --timestamp=none --sign "$CODESIGN_IDENTITY" "$APP" 2>/dev/null || true
|
||||
ENTITLEMENTS="$REPO/macos.entitlements"
|
||||
test -f "$ENTITLEMENTS"
|
||||
|
||||
# The exported Godot executable loads the GDExtension from Contents/Frameworks.
|
||||
# Because this package uses hardened runtime, the main executable must carry
|
||||
# disable-library-validation or macOS rejects the ad-hoc/formally signed dylib
|
||||
# at runtime even when the bundle passes a static codesign verification.
|
||||
find "$APP/Contents/Frameworks" -type f \( -name '*.dylib' -o -name '*.so' \) -exec \
|
||||
codesign --force --options runtime --timestamp=none --sign "$CODESIGN_IDENTITY" {} \;
|
||||
codesign --force --options runtime --timestamp=none --entitlements "$ENTITLEMENTS" \
|
||||
--sign "$CODESIGN_IDENTITY" "$APP/Contents/MacOS/mtgodot-poc"
|
||||
codesign --force --options runtime --timestamp=none --entitlements "$ENTITLEMENTS" \
|
||||
--sign "$CODESIGN_IDENTITY" "$APP"
|
||||
xattr -dr com.apple.quarantine "$APP" 2>/dev/null || true
|
||||
|
||||
echo
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- generated-by: gsd-doc-writer -->
|
||||
# Android 真机测试指南
|
||||
|
||||
本文说明如何在 Android 真机上安装 `mtgodot-poc`、生成并导入资源包、验证资源挂载,以及进行 40250 客户端测试。
|
||||
本文说明如何在 Android 真机上安装本客户端(APK 产物名仍是 `mtgodot-poc.apk`,包名 `org.internal.mtgodotpoc`)、生成并导入资源包、验证资源挂载,以及进行 40250 客户端测试。
|
||||
|
||||
## 1. 当前测试范围与已知前置条件
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
当前仓库的资源部署存在一个需要特别注意的限制:
|
||||
|
||||
- `export-android.sh --install` 会把资源推到 `/sdcard/Android/data/org.internal.mtgodotpoc/files/assets.zip`。
|
||||
- `project/asset_pack.gd` 首先查找 `user://assets.zip`,当前没有显式把上述外部目录加入候选路径。
|
||||
- `project/asset_pack.gd` 的候选顺序是 `MT_ASSETS_ZIP` 环境变量 → `user://assets.zip` → `OS.get_user_data_dir()/assets.zip` → 可执行文件目录 → `res://../assets.zip`(见 `_find_local_zip()`);上述外部目录不在候选路径里。
|
||||
- 因此,Debug 真机测试应把外部目录中的压缩包再复制到应用私有 `files/` 目录,确保客户端的 `user://assets.zip` 能命中。
|
||||
|
||||
另外,40250 classic 网络栈当前由进程环境变量 `MT_PROTOCOL=classic` 选择。Android 通过 Activity 启动 APK 时不能直接继承 Mac 终端的环境变量;如果 APK 尚未增加 Android 侧的协议配置入口或将 classic 设为移动端默认值,则只能完成 APK、资源和 UI 验证,不能据此宣称已经完成真实 40250 登录验收。
|
||||
@@ -34,7 +34,7 @@
|
||||
进入仓库并设置环境变量。路径按本机安装位置调整:
|
||||
|
||||
```bash
|
||||
cd /Users/shenlei/Work/mt/mtgodot-poc
|
||||
cd /Users/shenlei/Work/mt/metin2-client
|
||||
|
||||
export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk"
|
||||
export ANDROID_HOME="$ANDROID_SDK_ROOT"
|
||||
@@ -369,7 +369,7 @@ shasum -a 256 build/export/mtgodot-poc.apk \
|
||||
首次测试按以下顺序执行:
|
||||
|
||||
```bash
|
||||
cd /Users/shenlei/Work/mt/mtgodot-poc
|
||||
cd /Users/shenlei/Work/mt/metin2-client
|
||||
|
||||
./pack-assets.sh
|
||||
./export-android.sh Debug
|
||||
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
# mtgodot-poc — 未完成工作清单
|
||||
# metin2-client — 未完成工作清单
|
||||
|
||||
> 更新:2026-08-29 · 配套 [`GODOT-POC-PLAN.md`](./GODOT-POC-PLAN.md)(计划)、[`MIDREVIEW.md`](./MIDREVIEW.md)(中期评审)、
|
||||
> [`SHINSOO-WORLD-RENDERING.md`](./SHINSOO-WORLD-RENDERING.md)(世界渲染实施)、[`PARITY-GAP.md`](./PARITY-GAP.md)(距参考图的保真化差距)。
|
||||
@@ -55,8 +55,8 @@
|
||||
| B6 | 贴图采样设置(filter / wrap / mip / 各向异性) | ⬜ | S | 现在 shader 里写死 `filter_linear_mipmap, repeat_enable`。 |
|
||||
| B7 | 顶点色 | ✅ 排查=不适用 | — | 全资产 `.gr2`(PC/monster2/effect)无 `DiffuseColor`/`Color0` 顶点成员(grep assets = 0)。Metin2 逐顶点色 = 地形雾(`MapOutdoorRenderSTP` 运行时动态 VB,非资产,Godot `Environment` 雾已覆盖)+ `.mse` `colorfactor`/粒子色(属 E7/§1.2)。libgr2 / `build_mesh` 无需动。详见 PARITY §2.6。 |
|
||||
| B8 | 切线帧(若确有法线贴图资产) | ⬜ | M | PNT332 无切线。xrender 时期结论:Metin2 资产**基本不用**法线贴图 —— 先排查有没有,再决定是否做(`SurfaceTool::generate_tangents()` 或从 UV 算)。 |
|
||||
| B9 | 镜面 / 自发光 | 🟡 | M | Sphere-map 高光管线已端口(`SRC_MIX`/`SRC_SKIN` 加 `spec_map`/`spec_power`/`spec_enable`,复现 `Material.cpp:305 __ApplySpecularRenderState`:不透明面、相机空间 `reflect().xy` 查 `spheremap.jpg`、`EMISSION += sphere*tex.a*power`)。`Metin2Model.specular_power` 属性,默认 0 休眠 → 需装备层用 `item_proto bSpecular/100` 逐部位驱动。`SRC_ADD` / `SRC_ADD_SKIN` 已覆盖 additive 发光的一种,且 additive 动画面不再漏蒙皮。 |
|
||||
| B10 | 背面剔除 / 双面 | 🟡 | S | 世界静态对象(W3/B1)已按 `two_sided` + 贴图名切 `CULL_DISABLED`。角色 `m2_material` shader 仍写死 `cull_back`(`MaterialDesc::two_sided` 死字段)。需给角色也按材质切。 |
|
||||
| B9 | 镜面 / 自发光 | 🟡 | M | Sphere-map 高光管线已端口(`SRC_MIX`/`SRC_SKIN` 加 `spec_map`/`spec_power`/`spec_enable`,复现 `Material.cpp:305 __ApplySpecularRenderState`:不透明面、相机空间 `reflect().xy` 查 `spheremap.jpg`、`EMISSION += sphere*tex.a*power`)。`Metin2Model.specular_power` 属性,默认 0 休眠。✅ 装备层已接:`project/ui/equip_model.gd:283-288` `_apply_body()` 读 `item_proto` 的 `specular` 列并 `set("specular_power", sp / 100.0)`。⬜ 只驱动身体/护甲一个部位(武器 / 发型 / 时装未接),且 power 未按受控参考帧标定(PARITY §0 门禁)。`SRC_ADD` / `SRC_ADD_SKIN` 已覆盖 additive 发光的一种,且 additive 动画面不再漏蒙皮。 |
|
||||
| B10 | 背面剔除 / 双面 | ✅ 首版 | S | 世界静态对象(W3/B1)已按 `two_sided` + 贴图名切 `CULL_DISABLED`。✅ 角色也已按材质切:`m2_material.cpp:188-211` `shader_for()` 对 `two_sided` 把 `cull_back` replace 成 `cull_disabled`(opaque/blend × 普通/蒙皮 四个变体各自缓存),`metin2_model.cpp:1182`(身体)/ `:769`(武器)经 `decide_two_sided()` 驱动,`_load_hair()` 直接置 true。⬜ 判据仍是启发式 —— `gr2::MaterialInfo.two_sided` 按材质名(`2side`/`twoside`/`double`/`leaf`/`tree`/`ivy`/`fence`)+ 表面名兜底(`hair`/`cloak`/`cape`/`skirt`/`ribbon`/`leaf`),不是真 `ExtendedData` 的 "Two-sided"。 |
|
||||
| B11 | winding 逐模型验 | ⬜ | S | `flip_winding` 默认 false(4 个骨架验过,未全量)。 |
|
||||
|
||||
---
|
||||
@@ -117,14 +117,14 @@
|
||||
|
||||
| ID | 项 | 状态 | 规模 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| F0 | vendored 原生依赖 | ✅ | S | libsodium / libzstd / miniLZO 从 Homebrew 改为**源码内建**(`extension/third_party/`,pinned submodule + vendored miniLZO)—— 同一棵树可交叉编 NDK / iOS SDK。别名 `mt3p::sodium` / `mt3p::zstd` / `mt3p::minilzo`,无源码改动,macOS 9/9 CTest + 真实 item/mob_proto 解码逐字一致。详见 `docs/THIRD-PARTY.md`。miniLZO 是 GPL —— 自用可接受(同 oodle1.c),发布前须换。 |
|
||||
| F0 | vendored 原生依赖 | ✅ | S | libsodium / libzstd / miniLZO 从 Homebrew 改为**源码内建**(`extension/third_party/`,pinned submodule + vendored miniLZO)—— 同一棵树可交叉编 NDK / iOS SDK。2026-09-02 起第四个:**Crypto++ 8.4.0**(vendored 源码,`MT_PROTOCOL=classic` 的 DH2/CTR cipher 用,公有领域许可)。别名 `mt3p::sodium` / `mt3p::zstd` / `mt3p::minilzo` / `mt3p::cryptopp`,无源码改动,macOS 9/9 CTest + 真实 item/mob_proto 解码逐字一致。详见 `docs/THIRD-PARTY.md`。miniLZO 是 GPL —— 自用可接受(同 oodle1.c),发布前须换。 |
|
||||
| F1 | iOS(iPhone 16 / Metal) | 🟡 | M | ✅ 交叉编译打通:`./build-ios.sh` 出 `libmtgodot.ios.template_{debug,release}.a`(arm64 / minos 15.0),全依赖(libsodium/zstd/miniLZO/libgr2/formats/mtnet/godot-cpp)随之交叉编过;iOS 强制 extension 为 STATIC(不能 dlopen),`.gdextension` 加了 `[dependencies] ios.*` 归档清单。⬜ 剩 Godot 4.7 iOS 导出模板 + 导出 preset 链 `project/bin/ios/*.a` + 免费 provisioning 签名 + iPhone 16 真机跑 + Release/strip。预留 2–3 天。详见 `docs/PLATFORMS.md`。 |
|
||||
| F2 | Android(一加 13 / Vulkan) | 🟡 | M | ✅ CMake 已接 `CMAKE_SYSTEM_NAME==Android`(SHARED `.so` + `arm64` 名字后缀);`./build-android.sh` 走 NDK 自带 `android.toolchain.cmake`(`arm64-v8a` / `android-24`)。⬜ 本机无 NDK —— 装 NDK 后 `./build-android.sh` 出 `.so`,再 Godot Android 导出 preset(Gradle)+ 一加 13 真机跑。**只验 Vulkan**,不做 Compatibility(GLES3) / 老机。详见 `docs/PLATFORMS.md`。 |
|
||||
| F3 | 三端一致性 | ⬜ | S | 同工程 / 同 t / 同机位截图,iPhone 16 · 一加 13 · Mac 对齐。 |
|
||||
| F4 | 移动端性能 / 帧预算 | 🟡 | M | ✅ **GPU 纹理压缩**:`extension/src/texture_util.{h,cpp}` `make_color_texture()` —— 移动端(`OS.has_feature("mobile")`)或 `MTGODOT_TEXCOMP=1` 时对颜色贴图运行时 ASTC 8x8(~2bpp vs RGBA8 32bpp),编码失败回退 RGBA8;桌面默认关,逐调用点保留原 mipmap 标志 → OFF 时与旧路径逐字节一致。接入:角色皮肤(`_load_dds`)、建筑 albedo(`static_object`)、树皮/树冠(`tree_placeholder`);splat 控制图 / 阴影图 / 水 / HUD 保持 RGBA8。macOS+iOS 编过,ctest 9/9,桌面渲染无变化,`MTGODOT_TEXCOMP=1` 角色渲染正常。⬜ 剩:一加 13 / iPhone 16 单 + N 角色 bench(`MTGODOT_GPUSKIN=1` 人群)、构建成本(~170ms/角色,A5/G2)、移动端画质核对。 |
|
||||
| F5 | App 生命周期 | 🟡 | S–M | ✅ `project/app_lifecycle.gd`(AppLifecycle 节点):把 `NOTIFICATION_APPLICATION_PAUSED/RESUMED` / `FOCUS_IN/OUT` / `OS_MEMORY_WARNING` / `WM_GO_BACK_REQUEST` 收成信号,默认动作 = 后台暂停树 + 停 BGM + 降 `max_fps`,前台还原;`bind(m2client, audio)` 一键接。`M2Client`(C++):`_notification` 收 PAUSED/RESUMED → `suspend()/resume()`(挂起时不 pump socket),`reconnect()` 用存好的凭据重登;新信号 `suspended`/`resumed`。已接 `login.gd`(回前台若在游戏中自动重连)+ `world_demo.gd`。headless smoke(suspend/resume/reconnect 绑定 + 幂等 + 信号)通过,ctest 9/9,iOS 编过。渲染上下文丢失由 Godot Vulkan 自恢复,GPU 资源全 RenderingServer 托管,无需处理。⬜ 剩真机验证后台 30s→掐连接→回前台重连、iOS 内存告警实际触发。 |
|
||||
| F6 | 打包 | ⬜ | S–M | macOS / iOS / Android export preset、资产打包策略、iOS 签名。自用,无商店上架。 |
|
||||
| F8 | 实体点选精度 | ✅ 首版 | S | `player_controller._ray_pick_t()`:射线 vs 每个 pickable 下所有 `MeshInstance3D` 的**世界 AABB 合并 + slab 相交**(逐实体精确,大怪 / 小怪不再被固定 1.4 m 半径误判;`grow(0.15)` 宽容度)。无网格回退旧胶囊近似。对齐 `EterGrnLib/ModelInstanceCollisionDetection::Intersect` 的**结果**,不复刻逐三角。`eterngrn_polish_test.gd` 覆盖(命中 t / 未命中 -1 / 擦边 / 无网格回退)。⬜ 逐三角 / 骨骼包围体、`GetHeight`。 |
|
||||
| F9 | 实体点选精度 | ✅ 首版 | S | `player_controller._ray_pick_t()`:射线 vs 每个 pickable 下所有 `MeshInstance3D` 的**世界 AABB 合并 + slab 相交**(逐实体精确,大怪 / 小怪不再被固定 1.4 m 半径误判;`grow(0.15)` 宽容度)。无网格回退旧胶囊近似。对齐 `EterGrnLib/ModelInstanceCollisionDetection::Intersect` 的**结果**,不复刻逐三角。`eterngrn_polish_test.gd` 覆盖(命中 t / 未命中 -1 / 擦边 / 无网格回退)。⬜ 逐三角 / 骨骼包围体、`GetHeight`。 |
|
||||
| F7 | 触屏输入 / 手势相机 | ✅ | S | `game_camera.gd`:单指拖拽环绕(8px deadzone,低于视作点击)/ 双指捏合缩放;`player_controller.gd`:单指轻点(≤12px 位移 & ≤0.35s)= 点地 / 点选,拖拽或双指手势时不触发。`project.godot` 关 `emulate_mouse_from_touch`(避免与轻点重复触发),桌面鼠标路径不变。两脚本 `--check-only` + 项目导入无错。 |
|
||||
| F8 | `godot-cpp` 钉稳定版 | ✅ | S | gitlink 精确锁定 `101ae38034304346a46ea9ea84ae156d3e860496`,`.gitmodules` 已移除移动的 `master` branch 配置;目标 API 固定为 Godot 4.7。 |
|
||||
|
||||
@@ -183,7 +183,7 @@ UI / Python 脚本层、多角色 AI、网络、玩法逻辑、eterpack(Phase
|
||||
|
||||
### Sprint 1 —— 小项收尾(~1 周)
|
||||
|
||||
已完成:`A3` · `A6` · `F8` · `I1`,并补完 `A9`/`A10` 正确性问题。
|
||||
已完成:`A3` · `A6` · `F8`(`godot-cpp` 钉版)· `I1`,并补完 `A9`/`A10` 正确性问题。
|
||||
剩余:`A5`(CPU 路径原地更新)· `A7`(前台 Metal stress 基线)· `A8`+`H1`(桥接层畸形用例与全语料 draw 冒烟)。
|
||||
|
||||
### Sprint 2 —— 组合基础(~2 周)
|
||||
|
||||
+154
-11
@@ -10,7 +10,7 @@
|
||||
> **[待读参考]** 并给出应读的参考文件,而不是臆造。
|
||||
>
|
||||
> 路径约定:`REF/` = `/Users/shenlei/Work/mt/40250/ClientVS22/source/`,
|
||||
> `POC/` = `/Users/shenlei/Work/mt/mtgodot-poc/`。
|
||||
> `POC/` = `/Users/shenlei/Work/mt/metin2-client/`。
|
||||
>
|
||||
> 创建 / 修订日期:2026-09-04
|
||||
|
||||
@@ -355,8 +355,10 @@
|
||||
普攻 `_swing_skill=0`),被击退目标记 `_victim_flush`。`_emit_swing()` 改为**只有拿不到
|
||||
命中窗**(headless / 缺资源)才在挥击时立即发 `CG_ATTACK`。`_flush_victim_list()`(对齐
|
||||
`PythonPlayerEventHandler.cpp:194`)帧末把 `_victim_flush`(≤16)打包 `client.sync_positions()`。
|
||||
几何判定为近似:`reach = max(WeaponLength, 窗内采样最大水平偏移)`,命中 = 目标落在正面 `±60°`、
|
||||
`(reach+20+45) cm` 弧内;真实动态圆柱扫掠需骨骼矩阵 + defending sphere(随 §3.1 留桩)。
|
||||
~~几何判定为近似:`reach = max(WeaponLength, 窗内采样最大水平偏移)`,命中 = 目标落在正面 `±60°`、
|
||||
`(reach+20+45) cm` 弧内;真实动态圆柱扫掠需骨骼矩阵 + defending sphere(随 §3.1 留桩)。~~
|
||||
**增量 130 已替换**为 `.msa` 刀尖扫掠 Z 圆柱 vs `.msm` 防御球的 `detect_z_cylinder` 判定(见 §3.5 修改 4 /
|
||||
C.5 增量 130)。
|
||||
`combat_fx_test.gd` 加 `FakeNetWorld` + 6 段断言(`CG_ATTACK` 延后 / 窗内命中 / `CG_SYNC_POSITION` /
|
||||
COMBO 单次 / 正面弧 / 越窗收起)。C++ 21/21 + 7 个 GDScript 回归全绿。留给增量 84:武器种类 →
|
||||
`combo_motion_mode` 映射。
|
||||
@@ -700,7 +702,7 @@
|
||||
新增 `_attack_ctx()` 从 `client.get_duel()` / `get_pvp_relations()` / `get_guild_wars()` /
|
||||
`get_party()` 装配 ctx(observer / main_vid / pk_mode / duel_mode / duel_opponents /
|
||||
pvp_pairs / gvg_pairs / party_vids)。5 处调用点(含 `__ReserveProcess_ClickActor` 第 3 步、
|
||||
`_can_shot`、`_hit_geometry`)无签名变化。
|
||||
`_can_shot`、`_hit_geometry`;增量 130 起后者并入 `_normal_attack_process`)无签名变化。
|
||||
④ 自检 `project/entity_rules_test.gd`(第 15 个 canonical,25 组断言);`combat_fx_test` /
|
||||
`netplay_test` / `fly_test` 的怪物夹具补 `ch_type: 2`(此前无 `ch_type` → `_entity_kind` 归 PC,
|
||||
桩按 PC 也「可打」;1:1 规则下和平同帝国 PC 不可打 → 夹具需明确怪类别,与真实服务器一致)。
|
||||
@@ -2352,9 +2354,23 @@ OnHit(uSkill, victimActor, isSendPacket):
|
||||
**只有拿不到命中窗数据**(headless / 缺资源)才在挥击时立即发 `CG_ATTACK`,有窗时交给
|
||||
`_attack_process`。`_flush_victim_list()`(对齐 `PythonPlayerEventHandler.cpp:194`)在
|
||||
`_process` 帧末把 `_victim_flush`(≤ `SYNC_POSITION_LIMIT` 16)打包 `client.sync_positions()`。
|
||||
几何判定是 **近似**:`reach = max(WeaponLength, 窗内采样最大水平偏移)`,命中 = 目标落在正面
|
||||
~~几何判定是 **近似**:`reach = max(WeaponLength, 窗内采样最大水平偏移)`,命中 = 目标落在正面
|
||||
`±60°`、`(reach + 20 + 45) cm` 弧内;真实的动态圆柱-圆柱扫掠需要骨骼矩阵 + defending
|
||||
sphere 数据(同 §3.1 actor 碰撞一起留桩)。`combat_fx_test.gd` 加 `FakeNetWorld` +
|
||||
sphere 数据(同 §3.1 actor 碰撞一起留桩)。~~
|
||||
**增量 130 升级为逐行判定**:删除 `_hit_deduped` / `_hit_geometry`,新增 `_normal_attack_process()`
|
||||
对齐 `__NormalAttackProcess`:
|
||||
- 距离门 `v3Distance = (dX, dZ, dZ)`:出货代码平面 Y 不参与、高度差算两次,原样保留;上限 300 cm,
|
||||
`IS_HUGE_RACE` 为 500 cm。
|
||||
- 命中窗 `[start,end]` 与 `[t-dt, t]` 相交后查 `m_HitDataMap`:COMBO 同窗不再判,其余等 `fInvisibleTime`。
|
||||
- 窗内每个采样的刀尖 `last_pos → pos` 按攻击者朝向转到世界 cm,作为半径 20 的动态 Z 圆柱,
|
||||
对受击方每个防御球做 `HitCollision.detect_z_cylinder()`(逐行移植
|
||||
`DetectCollisionDynamicZCylinderVSDynamicZCylinder` + `IntersectLineSegments`)。
|
||||
- 碰上后 `_register_hit()` → `_process_attack_success()`。
|
||||
- `_register_hit` 修正为 `map::insert` 语义:已有目标不覆盖冷却,插入后超上限才返回 FALSE。
|
||||
- 防御球取 `.msm` 的 `CollisionType 3`(`HitCollision.parse_msm_defending`):PC 读
|
||||
`root/msm/<class>_<m|w>.msm`,怪物读模型目录 `.msm`。上一帧球心缓存在 `_def_last`。
|
||||
- 判定时间改为 `_attacking_elapsed() = (_local_time - _motion_start_t) * _atk_speed_factor`
|
||||
(`GetAttackingElapsedTime`);`_local_time` 由 `_advance_local_time()` 先扣 `m_fDelay` 再推进。`combat_fx_test.gd` 加 `FakeNetWorld` +
|
||||
命中窗几何判定 / `CG_ATTACK` 延后 / `CG_SYNC_POSITION` / COMBO 单次 / 正面弧 / 越窗收起 6 段断言。
|
||||
5. `OnAttack` 事件(动作真正起手时)发 `CG_CHARACTER_MOVE{FUNC_COMBO, wMotionIndex}`,
|
||||
与 `CG_ATTACK` 是**两个不同时刻**的两个包,不能合并。**[已在增量 78 `_do_attack_swing` 落地]**
|
||||
@@ -2395,8 +2411,10 @@ OnHit(uSkill, victimActor, isSendPacket):
|
||||
修改 6 完成(增量 84:`motion_mode_for` + `_refresh_motion_mode` 按装备武器 subtype / 骑乘 / 变身
|
||||
切 `combo_motion_mode`,对齐 `RefreshState`);修改 7 完成(增量 85:`_clickable_distance()` 弓箭
|
||||
`__GetBowRange()` 分支 + `_bow_range_cm()` + `POINT_BOW_DISTANCE` 加成)。C++ 21/21 + 7 GDScript
|
||||
全绿。仍待:几何判定升级为真实动态圆柱扫掠(需骨骼矩阵 + defending sphere,随 §3.1 actor 碰撞)、
|
||||
服务端合法性校准。§3.6 箭矢 `MOTION_EVENT_TYPE_FLY` 事件已在增量 86 落地(见 §3.6)。
|
||||
全绿。~~仍待:几何判定升级为真实动态圆柱扫掠(需骨骼矩阵 + defending sphere,随 §3.1 actor 碰撞)、
|
||||
服务端合法性校准。~~ —— 增量 130 已落地:Z 圆柱 vs `.msm` 防御球,以及 `__ProcessDataAttackSuccess`
|
||||
的完整效果(见修改 4 / §3.7 / C.5 增量 130)。仍待:服务端合法性校准;防御球当前是模型本地近似,
|
||||
未跟骨骼矩阵走。§3.6 箭矢 `MOTION_EVENT_TYPE_FLY` 事件已在增量 86 落地(见 §3.6)。
|
||||
|
||||
---
|
||||
|
||||
@@ -2512,6 +2530,35 @@ handler 由 `__OnPressActor` 通过
|
||||
`netplay_test` / `netbridge_test` / `gamescene_test` / `player_motion_test`
|
||||
全绿。
|
||||
|
||||
**增量 130(受击方反应 1:1,2026-09-12)**
|
||||
|
||||
- 新增 `project/ui/hit_reaction.gd`,由 PlayerView / MobView 共用。`good()` / `greate()` / `stone()`
|
||||
逐分支对齐 `__HitGood` / `__HitGreate` / `__HitStone`:
|
||||
- 击倒中不再换受击动作,Greate 在起身中也不换。
|
||||
- 晕眩时:Good → `Die`(死亡动作由服务端驱动,seam);Greate 只播 `DAMAGE_FLYING(_BACK)`,
|
||||
并置 `m_isRealDead`,不起身。
|
||||
- `isLock`(普攻 / 连击 / 技能 / 表情 / 钓鱼等)只抖动不换动作;Greate 在 `IsUsingSkill` 时也只抖。
|
||||
- `scalar = dot(攻击方朝向, 受击方朝向)`:小于 0 走正面 `DAMAGE` / `DAMAGE_FLYING → STAND_UP`;
|
||||
否则先试 `_BACK` 版,缺资源退回正面版。
|
||||
- 动作链 = `InterceptOnceMotion` + `PushOnceMotion` + 链尾 `PushLoopMotion`,回到受击前的
|
||||
wait / walk / run。
|
||||
- `__Shake(100)`:100 ms 内模型位置每帧偏移 ±`rand()%10` cm,结束复位。
|
||||
- `InsertDelay(fStiffenTime)`:`time_scale = 0` 冻结,到期恢复该动作的 `fSpeedRatio`;冻结期间新绑定的
|
||||
动作同样保持冻结。
|
||||
- PC 受击文件按 `playersettingmodule` 注册表取,同名多份等权随机:
|
||||
- `damage` / `damage_1`;BACK 版 `damage_2` / `damage_3`
|
||||
- `damage_flying` / `back_damage_flying`
|
||||
- `falling_stand` / `back_falling_stand`
|
||||
- 怪物在 `STATE_MOTIONS` 新增 `BACK_DAMAGE` / `FRONT_KNOCKDOWN` / `BACK_KNOCKDOWN` / `FRONT_STANDUP` /
|
||||
`BACK_STANDUP`。
|
||||
- `is_in_hit_reaction()` 改为返回 `_hit.active`:整条链播完才清 `net_play._knock_down`。原来的
|
||||
`_state == "damage"` 分支并入链尾处理。
|
||||
- 击退:`net_world.push_victim()` 用 `physics_push.gd`(逐行移植 `CPhysicsObject` +
|
||||
`CEaseOutInterpolation`),每帧叠加位移。
|
||||
- `blending_position()` = `GetBlendingPosition`,供 `OnHit` 的 `CG_SYNC_POSITION` 使用。
|
||||
- 推动期间服务端位置变化:以新位置为基准继续叠加。
|
||||
- 推动结束后服务端位置一变,即丢弃偏移。
|
||||
|
||||
---
|
||||
|
||||
### 3.8 技能缺少统一合法性检查
|
||||
@@ -7880,7 +7927,7 @@ dx² + dy² > s_fLimitDistance → 不播
|
||||
project/inventory_ui_test.gd —— FakeProto.item() 补 sub_type=0 / anti_flags=0 /
|
||||
wear_flags=1<<4 / limits=[] 让 iv.use(5)(vnum 19 武器)仍过新前置门
|
||||
|
||||
测试:M2_ASSETS=/Users/shenlei/Work/mt/mtgodot-poc/assets ctest --test-dir build → 21/21
|
||||
测试:M2_ASSETS=/Users/shenlei/Work/mt/metin2-client/assets ctest --test-dir build → 21/21
|
||||
(无 C++ 改动);56 个 GDScript 回归全 PASS(新增 equip_rules_test;inventory_test /
|
||||
inventory_ui_test 保持绿)。
|
||||
|
||||
@@ -7961,7 +8008,7 @@ dx² + dy² > s_fLimitDistance → 不播
|
||||
weapon_gr2 / shield_gr2 / hair_gr2、脱时装武器重解析、婚纱(桩返回 201)遮武器保头发、
|
||||
婚纱换捧花(vnum 50201)_last_weapon_vnum 恢复为 50201
|
||||
|
||||
测试:M2_ASSETS=/Users/shenlei/Work/mt/mtgodot-poc/assets ctest --test-dir build → 21/21
|
||||
测试:M2_ASSETS=/Users/shenlei/Work/mt/metin2-client/assets ctest --test-dir build → 21/21
|
||||
(无 C++ 改动);57 个 GDScript 回归全 PASS(新增 part_hiding_test;equip_model_test /
|
||||
equip_rules_test / inventory_ui_test 保持绿)。
|
||||
|
||||
@@ -9083,7 +9130,7 @@ dx² + dy² > s_fLimitDistance → 不播
|
||||
🔎 真机目视:鼠标悬停某 NPC / 怪 → 其头顶名字立即强显(即便未开「总显名字」且超 3500 距)、
|
||||
移开 → 复原;鼠标压 UI / 悬停地面物品时不强显任何角色名。
|
||||
参考(sole baseline = /Users/shenlei/Work/mt/40250/ClientVS22/source/;运行时 python =
|
||||
mtgodot-poc/assets/root/game.py):
|
||||
metin2-client/assets/root/game.py):
|
||||
root/game.py:1519 GameWindow.OnRender()
|
||||
root/game.py:1531 textTail.UpdateAllTextTail()
|
||||
root/game.py:1533 if True == wndMgr.IsPickedWindow(self.hWnd) —— 鼠标在 3D game 窗口上才拾取
|
||||
@@ -10145,3 +10192,99 @@ dx² + dy² > s_fLimitDistance → 不播
|
||||
seam ⑨ 名字与气泡合并为单尾标链表;完整 Quest / fishing / dungeon / mount / observer 玩法与
|
||||
复杂 UI 分支;真实服务器、真机、纯 pack、双架构和正式签名验收。
|
||||
```
|
||||
|
||||
### C.5 批次记录 · 增量 130(W2 / §3.5 · §3.7 战斗与 40250 对齐:命中判定、命中效果、受击反应、攻速、连击类型、技能包)
|
||||
|
||||
```text
|
||||
批次:增量 130 —— 逐项修正与 40250 参考端战斗实现的差异(2026-09-12)。每项先写失败断言再改实现。
|
||||
|
||||
1. 连击类型:
|
||||
net_play.gd 监听 client.combo_changed,由 _on_combo_changed() 处理,对齐
|
||||
CPythonPlayer::SetComboSkillFlag:
|
||||
· 查连击技能 122 的等级;缺槽或等级 <= 0 直接返回,不改 combo type。
|
||||
· 否则 _combo_type = enabled ? MIN(level, 2) : 0。
|
||||
· 不在本地伪造技能等级。
|
||||
|
||||
2. 命中判定:
|
||||
删除 _hit_deduped / _hit_geometry(reach + 正面 ±60° 近似)。
|
||||
· 新增 project/hit_collision.gd,逐行移植:
|
||||
IntersectLineSegments / FindNearestPointOnLineSegment / FindNearestPointOfParallelLineSegments /
|
||||
AdjustNearestPoints / DetectCollisionDynamicZCylinderVSDynamicZCylinder;
|
||||
另含 .msm CollisionType 3 防御球解析与 IS_HUGE_RACE。
|
||||
· net_play._normal_attack_process() 流程:
|
||||
(dX, dZ, dZ) 距离门 300 / 500 cm → 命中窗相交 → m_HitDataMap →
|
||||
刀尖采样半径 20 的 Z 圆柱 vs 受击方防御球(上一帧球心存 _def_last)。
|
||||
· PlayerView 取 root/msm/<class>_<m|w>.msm,MobView 取模型目录 .msm,都经 get_defending_spheres() 提供。
|
||||
· 没有 .msm 的占位节点退化为单球 HIT_FALLBACK_SPHERE(seam)。
|
||||
|
||||
3. _register_hit:
|
||||
改为 map::insert 语义:已登记的目标不刷新冷却,插入后超上限才返回 FALSE。
|
||||
|
||||
4. 攻速:
|
||||
_atk_speed_factor(bAttackSpeed/100,>1100 → 0)同时用于两处:
|
||||
· _attacking_elapsed() = (_local_time - _motion_start_t) * fSpeedRatio
|
||||
· PlayerView.play_attack_motion(mode, index, speed_ratio) 的 time_scale
|
||||
play_attack_motion 按 MOTION_MODE 目录绑定 attack(_1) / combo_0N,模式目录缺该段时回退 general。
|
||||
|
||||
5. 连击清零:
|
||||
删除本地连击超时清空。PlayerView / MobView 新增 motion_bound(state) 信号(__SetMotion 尾),
|
||||
由 net_play._on_motion_bound() 处理:
|
||||
· 新动作带 AttackingData → 清 m_HitDataMap。
|
||||
· 连击中换到无 ComboInputData 的动作 → _combo_index = 0。
|
||||
|
||||
6. __ProcessDataAttackSuccess(_process_attack_success):
|
||||
· InsertDelay(fStiffenTime):攻击者写 _delay(_advance_local_time 先扣),视图 time_scale 冻结;
|
||||
受击方同样 insert_delay,并记 m_fInvisibleTime(_victim_invisible_until,期间 AttackingProcess 跳过它)。
|
||||
· 击退门 __CanPushDestActor(_can_push):
|
||||
建筑 / 门 / 石头 / NPC / 巨型不推;晕眩必推;否则要求 owner 为主角且 owner 时间 <= 3 s。
|
||||
通过后 net_world.push_victim() 推动(physics_push.gd 逐行移植 CPhysicsObject + CEaseOutInterpolation)。
|
||||
OnHit 时目标仍在推动中 → GetBlendingPosition 进 CG_SYNC_POSITION 列表。
|
||||
· 命中特效 blow_1_low.mse:
|
||||
建筑 / 门放在攻击者身前 30 cm、不转向;巨型放在命中点;其余放在受击方。
|
||||
game_scene 装配 net_play.fx = fx、fx_parent = Entities。
|
||||
· 受击反应:石头 / 门 → hit_stone;HIT_TYPE_GOOD → hit_good;HIT_TYPE_GREAT → hit_greate;
|
||||
scalar = cos(攻击方 yaw − 受击方 yaw)。状态机 ui/hit_reaction.gd 见 §3.7 增量 130。
|
||||
· 最后 _on_hit:SetTarget + CG_ATTACK。
|
||||
|
||||
7. 技能包:
|
||||
ClassicSession::send_use_skill 删除夹带的 CG_FLY_TARGETING,只发 TPacketCGUseSkill(对齐
|
||||
SendUseSkillPacket)。飞行目标仍由施法方的 CG_ADD_FLY_TARGETING / OnSetFlyTarget 发送。
|
||||
net_classic_session_test 新增 "use skill wire: no extra fly targeting" 断言。
|
||||
|
||||
8. 既有测试随行为调整:
|
||||
受击 damage 按 playersettingmodule 注册为 damage / damage_1 等权随机。
|
||||
· gpu_pose_bounds_test:CPU / GPU 两个视图绑定前用同一 seed,保证选中同一段。
|
||||
· race_motion_assembly_test:damage 允许任一注册变体。
|
||||
这两个测试在本批次改动后曾失败(CPU / GPU 选到不同段、断言写死 damage.msa),调整后通过。
|
||||
|
||||
回归(godot --headless --path project --script <test>.gd):
|
||||
新增 PASS:hit_collision_test、physics_push_test、hit_view_test、net_world_push_test。
|
||||
PASS:combat_fx_test、gamescene_test、netplay_test、skill_test、player_move_test、input_key_test、
|
||||
weapon_attach_test、mob_view_test、player_motion_test、fly_test、remote_player_test、
|
||||
net_world_vis_test、forest_mob_render_test、p2b_test、playable_harness_test、playable_combat_test、
|
||||
gpu_pose_bounds_test、race_motion_assembly_test。
|
||||
已知失败(与本批次无关):equip_model_test "armor 11000 -> values[3]=0 回退 =vnum"(夹具期望过期)。
|
||||
forest_map_render_test 是 extends Node 的 MT_TEST_MODE 入口,不能用 --script 直跑,本批次未运行。
|
||||
ctest --test-dir build:22/23 PASS。net.classic_session 仍是既有 25 条失败
|
||||
(quest / duel / messenger / exchange / guild / safebox / mall / sync / ground item / despawn),
|
||||
都与 use_skill 无关;新增的 use skill 断言通过。
|
||||
|
||||
验收边界:
|
||||
已验证(离线):Z 圆柱几何、.msm 防御球解析、命中表 / 上限、攻速缩放、连击类型与清零、
|
||||
硬直 / 击退 / 同步位置 / 特效挂载、受击动作链 / 抖动 / 冻结、技能包线格式。
|
||||
未验证:真实服务器下的命中与击退手感、真机视觉。
|
||||
seam:
|
||||
· 击退没有地形 / 角色碰撞,也无 AdjustCollisionWithOtherObjects、溅射、IsResistFallen。
|
||||
· owner 时间取客户端观测时刻。
|
||||
· 防御球按模型本地坐标、不跟骨骼矩阵;占位节点退化为单球。
|
||||
· 远端角色不跑 AttackProcess;晕眩 → Die 不在本地播。
|
||||
· 攻击 / 受击动作变体等权随机;受击动作固定取 general 目录。
|
||||
· 抖动用模型位置偏移,InsertDelay 用 time_scale 冻结。
|
||||
· 受击链期间的循环动作请求延后到链尾。
|
||||
· 推动结束后服务端位置一变即丢弃偏移。
|
||||
· 本地 GC 伤害包仍直接走 set_anim_state("damage")。
|
||||
改动 C++ 后已重建 mtgodot 扩展;脚本改动需要重新导出 PCK 才进包。
|
||||
|
||||
下一批次:
|
||||
击退世界碰撞与 IsResistFallen;防御球跟骨骼矩阵;远端 AttackProcess;真实服务器战斗验收。
|
||||
```
|
||||
|
||||
+116
-65
File diff suppressed because one or more lines are too long
+16
-7
@@ -1,6 +1,12 @@
|
||||
# 客户端移植 —— 从素材渲染器到能联机的客户端
|
||||
|
||||
> 起点:`mtgodot-poc` 的渲染纵切「差不多能用」(见 [`PARITY-GAP.md`](./PARITY-GAP.md))。
|
||||
> **适用范围(2026-09-08 复核)**:本文描述的是 **m2dev fork 协议**后端。该后端**已不是默认**——
|
||||
> `project/client_main.gd:14-15` 在 `MT_PROTOCOL` 为空时无条件兜底成 `classic`,当前默认走
|
||||
> 40250 经典协议。迁移方案与 classic 后端的协议细节见 [`CLIENT-40250-PORT.md`](./CLIENT-40250-PORT.md)。
|
||||
> 本文仍然有效的部分:m2dev 后端自身的握手 / 封包 / 相位编排(`MT_PROTOCOL=m2dev` 时仍可切回),
|
||||
> 以及 §2 记录的移植进度。**不要**把本文的封包号或 `Packet.h` 依据用到 classic 后端上。
|
||||
|
||||
> 起点:本仓库(`metin2-client`)的渲染纵切「差不多能用」(见 [`PARITY-GAP.md`](./PARITY-GAP.md))。
|
||||
> 本文是把它变成**能连服务端玩**的客户端的分层计划。分水岭是**网络层**——别的玩家、
|
||||
> 物品、战斗、聊天都以封包为数据源。
|
||||
>
|
||||
@@ -9,8 +15,8 @@
|
||||
|
||||
## 0. 目标服务端
|
||||
|
||||
- LAN:`192.168.21.203`(这台 Mac 能路由到,但握手端口目前 **connection refused** ——
|
||||
服务端进程没起 / 端口和默认不同,需确认)。
|
||||
- LAN:`192.168.21.203`。~~握手端口 connection refused~~ —— **已解决(2026-08-30)**:真机
|
||||
端到端已打通到 PHASE_GAME,见本文 §3。
|
||||
- 默认端口(`assets/root/serverinfo.py`):auth `11000`,频道/游戏 `11011/11021/11031/11041`。
|
||||
- 测试账号:`admin` / `123456789`。
|
||||
|
||||
@@ -217,7 +223,10 @@ AEAD 加密 session token。
|
||||
|
||||
## 4. 下一步
|
||||
|
||||
1. 打通到 `.203` 的连通性(见上)。可达后立即能测:
|
||||
> **本节 1–4 项已于 2026-08-30 全部完成**(见 §3 与 [`CLIENT-ROADMAP.md`](./CLIENT-ROADMAP.md)
|
||||
> 的 P0–P10)。保留为当时的计划记录,不要再当作待办执行。
|
||||
|
||||
1. ~~打通到 `.203` 的连通性~~ ✅。可达后立即能测:
|
||||
- `./build/extension/net_probe 192.168.21.203 11000 admin 123456789` → 完整握手 + `CGLogin3` → `login_key`
|
||||
- GDScript 里 `M2Client.connect_to_server(...)` → 一路到 `char_list` / `entered_game`
|
||||
2. **`GCLoginSuccess3` 布局对真实字节校准**:`net_probe` / `M2Client` 收到后 dump 原始字节,
|
||||
@@ -228,15 +237,15 @@ AEAD 加密 session token。
|
||||
`Metin2World` 当场景。里程碑「角色连上、站在地图里、别的实体在动」。
|
||||
4. 输入(点地移动 → `CG_MOVE`)、聊天(`CG_CHAT`/`GC_CHAT` 接 HUD)。
|
||||
|
||||
## 4. 风险
|
||||
## 5. 风险
|
||||
|
||||
- **协议版本漂移**:`Packet.h` 结构体要和服务端 build 一致。冻结一对 client/server commit。
|
||||
- **端到端测试阻塞**:目前握手端口 refused,走不到 `CGLogin3` 之前的验证。
|
||||
- ~~**端到端测试阻塞**:目前握手端口 refused,走不到 `CGLogin3` 之前的验证。~~ 已解除(§3)。
|
||||
- **移动端 libsodium**:Android/iOS 要静态 vendor(本身可移植,非阻塞)。
|
||||
- 自用范围可跳过:商城 / GM 工具 / 部分社交系统。**反作弊(`CG_HACK` / `ProcessCRC` /
|
||||
`ProcessScanner`)已在 `CLIENT-GAP.md`「不做清单」标注 ❌ 不做**,除非服务端强制校验。
|
||||
|
||||
## 5. 移植面(客户端源码)
|
||||
## 6. 移植面(客户端源码)
|
||||
|
||||
`EterBase/SecureCipher` · `EterLib/{NetStream,ControlPackets,NetPacketHeaderMap}` ·
|
||||
`UserInterface/{Packet.h, AccountConnector, PythonNetworkStream, PythonNetworkStreamPhase*}` ·
|
||||
|
||||
@@ -7,6 +7,14 @@
|
||||
> 标记:🌐 需服务器端到端 · 💻 离线可做(mock server / 合成封包 / 假 client)
|
||||
> 更新日期:2026-08-30 · 自用,无发布门禁
|
||||
> **P0–P10 首版全部完成**;`192.168.21.203` 已联通,`net_e2e` 端到端到 PHASE_GAME。里程碑见文末。
|
||||
>
|
||||
> **适用范围(2026-09-08 复核)**:本文整篇以 **m2dev fork 协议**为基线。该后端已不是默认——
|
||||
> `project/client_main.gd:14-15` 默认走 40250 `classic`(见 [`CLIENT-40250-PORT.md`](./CLIENT-40250-PORT.md))。
|
||||
> 玩法拆解、UI 与阶段规划仍然适用;但文末「通用做法」第 4 条「封包号 / 结构以
|
||||
> `m2dev-client-src-main/src/UserInterface/Packet.h` 为准」**只适用于 `MT_PROTOCOL=m2dev`**。
|
||||
> classic 后端的封包依据是 `40250/ClientVS22/source/UserInterface/Packet.h` +
|
||||
> `extension/src/net/classic/wire_classic.h`。上面「已联通」也是指 m2dev 联调服;
|
||||
> 40250 真服(FreeBSD + MySQL)尚未搭起,见 `CLIENT-40250-PORT.md` §7.1。
|
||||
|
||||
## 已就绪的地基(这些不重复做)
|
||||
|
||||
@@ -348,5 +356,5 @@ PHASE_GAME —— 收到 121 个实体、HP/SP/等级、20 格背包、好友列
|
||||
1. **每个 P 先做 💻 部分**:`wire.h` 加封包 + `EntityStore` 解析 + 合成封包单测(`net_entity_test` 风格)+ 假 client 驱动 UI(`netbridge_test` 风格)。
|
||||
2. 🌐 端到端用 `build/extension/net_e2e`(真机跑 auth→game→选人→进游戏);`MT_NET_TRACE=1` 逐包 header/len/consumed、`MT_NET_DUMP=1` 逐包 hex,对字节用。
|
||||
3. UI 一律走 P1 的 uiscript 装载器,不手搓布局。
|
||||
4. 封包号 / 结构以 `../m2dev-client-src-main/src/UserInterface/Packet.h` 为准,`static_assert` 尺寸;**真机字节和参考头文件不符时以真机为准**(已踩:`GC_LOGIN_SUCCESS4`、`bType`、`CG_CLIENT_VERSION`)。
|
||||
4. 封包号 / 结构:`MT_PROTOCOL=m2dev` 时以 `../m2dev-client-src-main/src/UserInterface/Packet.h` 为准,**默认的 `classic` 后端**以 `../40250/ClientVS22/source/UserInterface/Packet.h` + `extension/src/net/classic/wire_classic.h` 为准,`static_assert` 尺寸;**真机字节和参考头文件不符时以真机为准**(已踩:`GC_LOGIN_SUCCESS4`、`bType`、`CG_CLIENT_VERSION`)。
|
||||
5. 玩法逻辑尽量**服务器驱动、客户端只渲染**(尤其 quest / 商店 / 公会),少搬业务规则。
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
# 首个 Mac 联网内测版:开发实施文档
|
||||
|
||||
日期:2026-09-11。范围:Apple Silicon / arm64 Release。
|
||||
|
||||
本文将联网闭环、基础战斗、首测地图和稳定性四项需求拆为可开发任务。本文新增的文件、API、环境变量均为**待实现设计**,不是已存在功能;列为“现有”的入口已按当前工作树核对。本轮只编写文档,不执行联网测试或修改运行时代码。
|
||||
|
||||
## 1. 基线与交付边界
|
||||
|
||||
现有候选包:`build/export-native-trees-20260911/mtgodot-poc.app`。已通过离线包内加载及干净退出;树木专项覆盖 87 种资源、六图 2092 棵树,不能代替联网或树怪验收。
|
||||
|
||||
首版放行不是“渲染全部完成”。必须交付:固定哈希的候选包、实际联网闭环证据、基础战斗矩阵、首测地图截图、稳定性报告和已知问题。风动、逐叶朝向、SpeedTree 原生 LOD、40250 全环境像素一致性可延期。
|
||||
|
||||
首测地图拟为出生城镇及练级区、鬼木林、赤鬼木林。开发前通过资源和实际服务器确定 map key、进入坐标、合法路线、角色槽位与怪物刷新;不得凭中文名硬编码地图路径。测试角色等级、装备、技能、掉落条件需由测试环境负责人准备;没有条件时报告 BLOCKED,禁止伪造事件或偷偷修改服务器。
|
||||
|
||||
## 2. 已有实现与明确缺口
|
||||
|
||||
| 现有文件 / API | 可复用部分 | 本轮必须补齐 |
|
||||
| --- | --- | --- |
|
||||
| `script/live_smoke_test.sh` | 指定 MT_SMOKE_APP、凭据输入、报告与进程码 | 地址预检写死;无完整退出错误门禁;缺墙钟超时和战斗流程 |
|
||||
| `project/live_smoke_test.gd` | setup、状态机、世界读取、移动、聊天、reconnect | 发包成功不是服务端结果;无完整打怪拾取链 |
|
||||
| `project/client_main.gd` | 包内 MT_TEST_MODE=smoke/render 分流 | 增加 playable、地图视觉入口;普通启动不启用测试 |
|
||||
| `project/app_flow.gd` | start、state、登录/选角/进场和断线生命周期 | 提供只读场景快照,避免测试遍历私有节点 |
|
||||
| `project/net_play.gd` | set_attack_key、pick_ground_item、skill_context | 提取公共选目标入口,沿用真实战斗逻辑 |
|
||||
| `project/ui/quickbar.gd` | activate、assign、restore_from_server;skill_cast_started、skill_rejected | 输入、服务端结果与视觉证据关联 |
|
||||
| `project/player_skill.gd` | use_skill、可用性与目标检查 | 新增负向/生命周期覆盖,不另造施法实现 |
|
||||
| `project/ui/mob_view.gd` | build、set_anim_state、motlist 映射 | 树怪矩阵及禁止静默动作回退的验收 |
|
||||
| `project/rendering_scenario_test.gd` | 离线 CPU/GPU 多角色、帧时间、内存计数 | P99、事件关联、RSS、长期联网负载;现有假客户端不是实网证据 |
|
||||
| `script/package_render_test.sh` | 进程退出后扫描完整日志 | 抽取通用门禁供联网/稳定性使用 |
|
||||
|
||||
当前 `mob_winding_test.gd` 只覆盖 101、110、20001,不覆盖树怪。`native_tree_test.gd` 测的是静态场景树,不能复用其 PASS 证明怪物蒙皮正确。
|
||||
|
||||
## 3. 开发拆分与依赖
|
||||
|
||||
每个任务需单独可审查 diff,先添加失败用例再修复;工作树已有修改必须保留,不把无关修改混进任务结论。
|
||||
|
||||
| ID | 开发内容 | 依赖 | 完成产物 |
|
||||
| --- | --- | --- | --- |
|
||||
| INF-01 | 场景清单、报告协议、事件采集、配置校验 | 无 | 配置负测及报告协议测试 |
|
||||
| INF-02 | 通用包运行器、墙钟超时、退出门禁 | INF-01 | 假进程门禁测试 |
|
||||
| NET-01 | 包内真实联网状态机、只读诊断接口 | INF-01/02 | 3 次真实闭环 |
|
||||
| CBT-01 | 技能/普攻输入路径与证据关联 | NET-01 | 四职业矩阵 |
|
||||
| MAP-01 | 地图/树怪资源审计与离线 Metal 截图 | INF-01,可与 NET 并行 | 资源清单、动作截图 |
|
||||
| MAP-02 | 实际地图定位、战斗、落地检查 | NET-01、MAP-01 | 首测地图验收 |
|
||||
| STB-01 | 采样、循环场景、故障与窗口测试 | NET-01、CBT-01、MAP-02 | 2 小时报告 |
|
||||
| REL-01 | 重打包、聚合门禁、已知问题 | 全部 | 可追溯内测包 |
|
||||
|
||||
实际运行缺陷的修复范围由证据决定;不能预先将未知 bug 标成已定位。缺陷修复卡必须写出:失败用例 ID、资源/角色/地图、原因、修改文件、修复前后证据、回归集合。
|
||||
|
||||
## 4. INF-01:测试基础设施的数据契约
|
||||
|
||||
### 4.1 新增文件
|
||||
|
||||
- `test/playable/scenario.example.json`:无账号密码的模板,未解析的地图/技能字段留空并拒绝运行。
|
||||
- `project/testing/playable_config.gd`:验证配置、场景与资源前置条件。
|
||||
- `project/testing/playable_report.gd`:统一检查、事件记录与最终报告。
|
||||
- `project/testing/playable_probe.gd`:只读订阅生产对象,不发包、不写实体数据。
|
||||
- `project/playable_harness_test.gd`:假客户端验证状态机和证据判定,不作为实网验收。
|
||||
|
||||
配置采用 schema_version=1;包含 scenario_id、protocol、serverinfo 中选定地址、character_slot、map_key、waypoints_cm、allowed_mob_vnums、allowed_drop_vnums、skill_cases、resolution、loops、timeout_seconds。所有坐标字段显式带单位,网络到世界换算沿用生产代码;不把 Vector2/Vector3 强转用于凑通过。路线必须预先人工确认安全可达。
|
||||
|
||||
账号密码仅通过现有 MT_ACCOUNT/MT_PASSWORD 或安全交互输入提供;禁止写入 JSON、命令行参数、截图或报告。报告不复制进程环境。启动脚本不能使用 set -x。日志在落盘前脱敏,测试账号名也不写入最终公开报告。
|
||||
|
||||
### 4.2 报告契约
|
||||
|
||||
`report.json` 必须具有如下字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 1,
|
||||
"run_id": "unique-run-id",
|
||||
"suite": "playable",
|
||||
"status": "BLOCKED",
|
||||
"build": {"engine_sha256": "...", "extension_sha256": "...", "pck_sha256": "...", "arch": "arm64"},
|
||||
"environment": {"os": "...", "renderer": "...", "resolution": [1280, 720]},
|
||||
"cases": [{"id": "NET-ATTACK-01", "status": "BLOCKED", "duration_ms": 0, "reason": "fixture_not_ready", "evidence": []}],
|
||||
"failures": [],
|
||||
"blocked": ["fixture_not_ready"],
|
||||
"coverage": {"required": 1, "passed": 0},
|
||||
"exit_gate": {"checked": false, "process_code": null, "errors": []}
|
||||
}
|
||||
```
|
||||
|
||||
状态限定 PASS/FAIL/BLOCKED/SKIP;必测项 BLOCKED、SKIP 均不得放行。未知 schema、空 cases、缺哈希、证据文件不存在、required 与清单不一致均失败。客户端只能写 `client-report.json`,父运行器在真实退出后生成最终 `report.json`,防止退出前 PASS 掩盖泄漏。
|
||||
|
||||
事件写 `events.jsonl`,每条含 monotonic_us、run_id、case_id、connection_epoch、stage、kind、actor_vid、target_vid、payload(白名单字段)。重连后 VID 可变化,按角色身份与新 epoch 重新绑定,禁止等待旧 VID。检测“来自服务端”的依据必须是接收端分发,而非本地预测信号。
|
||||
|
||||
### 4.3 必须先有的负向测试
|
||||
|
||||
无凭据/坏配置、空覆盖、旧报告、错 run_id、报告 PASS 但进程失败、PASS 后输出 RID 警告、只有本地动画无服务端事件、重连后旧事件、超时不退出,均应返回非零。任何缺测都不能降级成 PASS。
|
||||
|
||||
## 5. INF-02:统一运行与退出门禁
|
||||
|
||||
新增 `script/run_client_gate.sh` 和 `script/validate_playable_report.mjs`,由 `script/playable_test.sh` 调用;复用 `package_render_test.sh` 的错误匹配规则,不弱化现有门禁。
|
||||
|
||||
1. 每次创建唯一输出目录,记录本次 run_id 和包哈希;不复用历史报告。
|
||||
2. 校验包可执行、架构和签名;清除 MT_ASSETS,保证验收用包内资源。
|
||||
3. 预检地址与 `project/net/serverinfo.gd` 的实际选中配置一致。新增测试配置覆盖只能在测试模式生效;删除冒烟脚本预检地址与客户端连接地址分叉的风险。
|
||||
4. 只管理本运行器启动的子进程 PID;超时先 TERM,宽限 10 秒后 KILL,再 wait 收集状态。不得 pkill 所有客户端或修改全机网络。
|
||||
5. 读取完整标准输出/错误,检查 SCRIPT ERROR、ERROR、leaked at exit、shaders never freed。无过滤 RID 警告的允许名单。
|
||||
6. 同时满足进程 0、报告协议正确、全部必测 PASS、完整日志门禁通过,才写最终 PASS。
|
||||
|
||||
建议退出码:0=PASS,1=断言或退出门禁失败,2=配置/前置条件阻塞,124=墙钟超时。进程原始退出码另存报告,不丢失。
|
||||
|
||||
门禁单测使用脚本生成的假子进程输出,不需游戏服务器。确认超时分支、信号退出和 stdout 管道不会绕过真实进程码。
|
||||
|
||||
## 6. NET-01:真实联网闭环状态机
|
||||
|
||||
### 6.1 修改点与接口
|
||||
|
||||
- 新增 `project/playable_live_test.gd`,实现 `setup(flow: Node, client: Node, config: Dictionary)`。
|
||||
- `client_main.gd` 增加 `MT_TEST_MODE=playable` 分支,在 AppFlow 建立后挂载该 Node;不得导出后用 --script 替代包内入口。
|
||||
- `app_flow.gd` 新增只读 `get_playable_snapshot() -> Dictionary`,返回 stage、角色身份摘要、scene_ready 和当前地图。测试对象引用通过明确的测试 adapter 获取,不把 Node 放入 JSON。
|
||||
- `game_scene.gd` 新增只读 `get_playable_context() -> Dictionary`,在测试模式提供现有 net_play、quickbar、net_world、world、player 的引用;场景销毁时失效。
|
||||
- `net_play.gd` 新增公共 `select_target(vid: int) -> bool`,复用现有 `_change_target_to_picked_instance` 与 `_on_pick` 的共同目标选择逻辑;保留距离、死亡和可攻击检查,不直接改私有字段。
|
||||
|
||||
先核实 M2Client 信号签名与 classic 收包源;缺少来源可辨识证据时,向现有接收分发处增加测试诊断通知,不添加假业务事件,不改变协议格式。
|
||||
|
||||
### 6.2 状态及判定
|
||||
|
||||
| 状态 | 动作 | 成功证据 | 默认超时 |
|
||||
| --- | --- | --- | --- |
|
||||
| LOGIN | 复用 AppFlow 自动登录 | char_list 接收且指定槽位存在 | 30s |
|
||||
| SELECT | 现有选角流程 | entered_game + 主实体有效 | 45s |
|
||||
| WORLD_READY | 等待场景加载 | map key 符合、地图与角色就绪、HUD 可用 | 60s |
|
||||
| MOVE | 通过玩家控制器走配置路线 | 本地到达 + 无服务端纠正;重登/服务端观察验证落点 | 20s/点 |
|
||||
| TARGET | select_target 选择允许范围怪物 | 当前 epoch 中存活实体、race 合法 | 30s |
|
||||
| ATTACK | set_attack_key(true),结束/失败必释放 | 指定目标接收血量/伤害变化与死亡结果 | 90s |
|
||||
| DROP | 观察真实掉落 | 新地面物品、允许 vnum、可拾取归属和邻近位置 | 30s |
|
||||
| PICKUP | pick_ground_item(iid) | 地面消失 + 背包对应 vnum 总量增加 | 15s |
|
||||
| EXIT | 正常退出入口 | 父运行器检查真实退出和完整日志 | 20s |
|
||||
|
||||
MOVE 不要求服务器必然回显主角每一个移动包;classic 若无回显,使用重登位置或服务器/第二观察客户端确认,不把本地 position 变化叫做服务端确认。若没有可用证据,标记该断言 BLOCKED。
|
||||
|
||||
拾取比较所有背包格的 vnum 总量(支持堆叠),并关联时间窗和地面 iid;只看到地面删除不能证明由自己拾取。金钱掉落另测点数,不套背包断言。无掉落的随机战斗不能无限重试:测试环境准备确定可拾取掉落,最多 3 次允许怪物击杀,无条件则 BLOCKED。
|
||||
|
||||
每个状态入口记录快照,失败保存截图;禁止跨状态复用旧计数。断线立即取消输入、释放目标和待处理操作。统一 teardown 断开监听,场景 free 后 probe 不再访问节点。
|
||||
|
||||
### 6.3 用例与完成条件
|
||||
|
||||
- NET-01:完整闭环 3 次,每次独立进程与报告。
|
||||
- NET-02:无效账号和不存在槽位,明确错误且有界退出(限制尝试,避免账号锁定)。
|
||||
- NET-03:进场期间断线,不能留下半加载操作对象。
|
||||
- NET-04:目标在攻击前消失,取消操作而非继续攻击旧 VID。
|
||||
- NET-05:掉落被他人拾取、背包已满,不能误报成功;需专用夹具或离线负测,实网缺条件须标出。
|
||||
|
||||
自动调用业务入口不等于鼠标命中正确;另做一次真实鼠标/键盘闭环,记录输入设备与截图,作为手动必测项。
|
||||
|
||||
## 7. CBT-01:基础战斗和技能
|
||||
|
||||
新增 `project/playable_combat_test.gd`(离线事件与输入断言)、`test/playable/skill-cases.json`(实际角色技能矩阵)。联网用例由 playable_live_test 调度,不再创建第二条发包路径。
|
||||
|
||||
### 7.1 实现与定位
|
||||
|
||||
1. 通过 Quickbar.assign/restore_from_server 构造测试账号实际槽位;需要持久化变更时仅对专用账号执行,记录原值并在可行时恢复。无服务端技能等级不得本地伪造。
|
||||
2. 调用 activate 复用 PlayerSkill.use_skill,监听现有 skill_cast_started(skill_id,target_vid) 与 skill_rejected(skill_id,code)。cast_started 只是本地施法开始,不是服务端命中证明。
|
||||
3. case_id 绑定施法时目标;施法中换目标后,定点效果仍使用原目标快照,跟随效果按技能定义更新。
|
||||
4. probe 关联接收端资源/状态变化、目标血量或伤害事件;不同技能配置 required_evidence,不强制所有技能都有伤害或资源消耗。
|
||||
5. 在 `game_scene.gd`、`fx/skill_fx.gd`、`fx/effect_player.gd` 的实际生成/结束边界记录测试事件。不可只用节点数量增加判定特效正确。
|
||||
6. 自动截图覆盖施法前、触发帧、峰值、结束;短命特效按事件时间采样,不统一等一秒。
|
||||
|
||||
诊断路由:图标/点击区域→quickbar;拒绝条件/目标→player_skill;动作触发→net_play 与玩家视图;挂点/生命周期→game_scene、skill_fx、effect_player;骨骼坐标→metin2_model/metin2_anim。只在复现后修改对应层。
|
||||
|
||||
### 7.2 测试矩阵
|
||||
|
||||
每职业从真实已学技能中选择适用类型:单体、范围、自身增益、飞行效果;不存在的类型标注不适用并经清单确认,不擅自补技能 ID。每技能成功施放 10 次;另覆盖无目标、超距、冷却、资源不足、目标死亡、自身死亡、切图/断线、目标切换。
|
||||
|
||||
断言包括:拒绝不发有效施法请求;正常请求数无重复;服务端效果可观察;角色持续可见且包围盒有限;特效在定义寿命+1秒宽限内清理;挂点相对预期骨骼/目标坐标误差默认不超过 0.1m(有资源偏移需记录校准值)。
|
||||
|
||||
在 `skill_test.gd`、`player_skill_test.gd`、`combat_fx_test.gd`、`target_effect_test.gd` 扩展相应失败用例,并纳入 rendering_batch_test。截图必须人工复核一次,像素非空不能证明技能外观正确。
|
||||
|
||||
完成条件:必测职业/技能覆盖完整、功能阻断清零、首次施法与重复施法均通过;高级特效差异写入已知问题,不改成假 PASS。
|
||||
|
||||
## 8. MAP-01/02:鬼木林、赤鬼木林与树怪
|
||||
|
||||
### 8.1 资源审计
|
||||
|
||||
新增 `script/audit_playable_maps.mjs`,输出 `map-assets.json`。读取实际 map 配置、AreaData/Property、npclist、MSM、motlist 和引用文件,分别列出静态 SPT、动态 GR2、贴图、动作及缺失项。没有服务端刷新数据时只报告候选树怪,不声称已确定地图所有怪物。
|
||||
|
||||
已核实 `assets/root/npclist.txt`:2301–2307 对应 ent_trent/ent_guru/ent_hu/ent_red/ent_black/ent_huge/ent_elder;2311–2315 对应前五种。共享模型仍保留独立 race 用例,避免漏掉 proto/外观配置差异。实际 map key 与刷新关联由前置审计填入配置。
|
||||
|
||||
### 8.2 单模型 GPU 验收
|
||||
|
||||
新增 `project/forest_mob_render_test.gd`,沿用 MobView.build、set_anim_state 和现有 Metin2Model/Metin2AnimPlayer。读取 motlist 的具体文件,报告 requested_state、resolved_motion、fallback_reason;“调用 dead 却播放 wait”不能通过。
|
||||
|
||||
对 12 个候选 race × CPU/GPU × wait/run/attack/damage/dead 生成基准集合;资源确无动作时据旧客户端回退规则单独判定,不能静默跳过。动作每个采样起点、25%、50%、75%、末段;固定随机种子或明确选择变体。死亡动作不能为了截图强行循环。
|
||||
|
||||
自动断言:构建成功;贴图实际加载;顶点/包围盒有限;无非法材质;同一姿态 CPU/GPU 包围盒一致(初始容差 1cm 或高度0.5%,取较大值);截图非空。容差变更需记录理由,不通过放宽到无限解决失败。
|
||||
|
||||
输出每 race 的正面、侧面、动作 contact sheet 和 JSON。检查材质双面/裁剪应依资源,不对所有树怪强制双面;蒙皮异常先检查骨骼索引、权重、bind pose、坐标,再修改 C++ 公共路径。`mob_winding_test.gd` 增加这些 race,若影响全怪物必须回归原 101/110/20001。
|
||||
|
||||
### 8.3 地图内验收
|
||||
|
||||
新增 `project/forest_map_render_test.gd` 和包内 `MT_TEST_MODE=forest_render` 分支,加载配置指定的生产地图。新测试模式不存在于旧包,必须重新构建后执行。
|
||||
|
||||
在经确认的平地、坡地、密林和传送点保存固定机位截图,记录 world.sample_height、怪物世界位置、ground offset、材质和实际动作路径。平地不允许持续悬空/埋地超过校准阈值;坡地需人工检查脚/根部接触,AABB 底部不是精确足部,不能用它宣布足部 IK 完成。
|
||||
|
||||
实网追加逐地图进入、选中树怪、攻击、死亡、拾取、离开。静态地图截图与动态服务器刷新分别记录证据,不混为一次测试。
|
||||
|
||||
完成条件:首测区域关键资源无未解释缺失、主要动作和目标交互正常、Metal 截图人工签核;其余地图不在本轮覆盖中。
|
||||
|
||||
## 9. STB-01:稳定性与长帧
|
||||
|
||||
新增 `project/testing/playable_metrics.gd` 和 `script/playable_soak.sh`,扩展 rendering_scenario_test 的 P99 与事件时间点,但保留“离线合成”和“真实联网”两种 suite 标签。
|
||||
|
||||
### 9.1 指标实现
|
||||
|
||||
- 每帧记录 monotonic 间隔;按 map/phase/actor_count/gpu_skin/动作切换标记。加载与游玩分段统计。
|
||||
- 固定大小环形缓冲,按时间窗口输出分位数和 >50ms/>100ms 样本;不得无限数组增长制造测试自身内存泄漏。
|
||||
- 默认关闭逐帧打印,只保留长帧事件;采样开启/关闭各跑短基线,量化探针开销。
|
||||
- 外部采样父运行器所持 PID 的 RSS,每秒一次,记录单位 KiB;Godot MEMORY_STATIC 单独记录。GPU 内存拿不到写 null/unavailable,不填写 0 或据此宣称无显存泄漏。
|
||||
- 缓存预热后比较重复路线每轮结束并静置30秒的低水位;记录前5轮与后5轮中位数。连续5轮增长且后5轮中位数高出 max(50MiB,5%) 时门禁失败并分析;阈值以下也不能证明长期无泄漏。
|
||||
|
||||
### 9.2 执行场景与边界
|
||||
|
||||
2小时实网循环移动/战斗/拾取;20次经合法传送入口切图;10次重连;3种受支持逻辑分辨率各切10次;10次正常退出。窗口物理像素与逻辑尺寸都记入报告,不能把 Retina 缩放当成分辨率错误。
|
||||
|
||||
主动 reconnect() 与真实传输故障分别计数。真实故障至少覆盖“连接被关闭”和“短时不可达”;仅测试专用连接,可使用经确认的局部代理/测试网络条件,不改全机路由、防火墙、不关生产服务。缺少该条件标为 BLOCKED,不用主动重连替代断网验收。
|
||||
|
||||
时间采用墙钟期限,不用固定帧数冒充2小时。重连后重新获取主 VID、场景和 UI 对象,检测重复信号、重复实体、旧目标/技能残留。跨服切图需核实测试服务器支持,失败不能通过直接传送客户端节点掩盖。
|
||||
|
||||
### 9.3 长帧处理流程
|
||||
|
||||
先标记同步模型 build、动作 reload、GR2解析、材质初次使用和实体批量生成;记录缓存命中。确认瓶颈后才做路径级修改:动画缓存→metin2_anim;实例建立→net_world/game_scene;材质预热→实际渲染建立路径。后台工作只做线程安全的解析,不把 SceneTree/RenderingServer 操作随意搬入工作线程。
|
||||
|
||||
相同机器/路线对比修改前后3轮,保留最大帧而非只报平均。正常游玩目标60FPS;同一交互3次重复中至少2次出现 >100ms 视为阻断,任何 >50ms 样本需归因。首次加载独立预算在基线采集后固定,不临时扩大预算让门禁通过。
|
||||
|
||||
完成条件:零崩溃/永久卡死、循环后功能正常、无达到上述阈值的未解释内存增长、无重复严重长帧、每次退出干净。冷启动报告注明进程冷启动/系统缓存状态未知,不执行系统缓存清空来影响用户其他程序。
|
||||
|
||||
## 10. 执行命令与验证顺序
|
||||
|
||||
以下命令在仓库根目录执行。账号通过安全交互提供,禁止放入命令历史。新脚本落地前不得宣称这些未来命令已可运行。
|
||||
|
||||
现有可执行回归:
|
||||
|
||||
```bash
|
||||
bash script/rendering_batch_test.sh
|
||||
MT_RENDER_APP="$PWD/build/export-native-trees-20260911/mtgodot-poc.app" bash script/package_render_test.sh
|
||||
```
|
||||
|
||||
待实现 CLI 契约(各脚本必须有 --help、配置校验、非零失败码):
|
||||
|
||||
```bash
|
||||
# 离线资源/蒙皮/报告门禁,不连接服务器
|
||||
node script/audit_playable_maps.mjs --config test/playable/scenario.local.json --output build/playable/map-assets.json
|
||||
godot --headless --path project --script playable_harness_test.gd
|
||||
godot --path project --script forest_mob_render_test.gd
|
||||
|
||||
# 重新构建带新包内测试入口的候选包,不能用旧包冒充
|
||||
MT_MAC_ARCHES=arm64 MT_MAC_ENGINE="$PWD/build/godot-particle-diagnostic/bin/godot.macos.template_release.arm64" MT_MAC_OUTPUT_DIR="$PWD/build/export-playable-rc1" bash build-macos-client.sh release
|
||||
|
||||
# 明确显式允许专用账号上的游戏操作;默认仅校验配置,不发移动/战斗请求
|
||||
bash script/playable_test.sh --app "$PWD/build/export-playable-rc1/mtgodot-poc.app" --config test/playable/scenario.local.json --suite full --allow-gameplay --repeat 3
|
||||
bash script/playable_soak.sh --app "$PWD/build/export-playable-rc1/mtgodot-poc.app" --config test/playable/scenario.local.json --allow-gameplay --duration-seconds 7200
|
||||
node script/validate_playable_report.mjs --release-dir build/playable/rc1
|
||||
```
|
||||
|
||||
新脚本参数还需支持 --output;聚合器只接受显式列出的本次 run_id 与相同包哈希,不扫描历史 PASS 凑覆盖。测试模式、测试账号均禁止自动聊天、交易、出售、丢弃物品或创建/删除角色;不沿用旧 smoke 的聊天副作用。
|
||||
|
||||
配置 local.json、凭据文件、运行产物加入适当忽略规则;提交无敏感信息的 example/schema。最终修复 C++ 后必须重建同步扩展、重新签名和打包;脚本变更也必须重新导出 PCK。
|
||||
|
||||
## 11. REL-01:放行检查表
|
||||
|
||||
- [ ] INF-01/02 负向用例通过,必测项缺失不能 PASS。
|
||||
- [ ] 同一候选包3轮联网闭环通过,另有鼠标键盘流程证据。
|
||||
- [ ] 四职业基础战斗、技能及异常路径清单完整。
|
||||
- [ ] 首测地图和树怪资源/动作/Metal画面验收通过。
|
||||
- [ ] 2小时、切图、故障恢复、窗口缩放、退出门禁达到配置次数。
|
||||
- [ ] P0(崩溃/数据异常/无法进场)与 P1(核心操作失效/主要模型丢失/严重错位/重复严重卡顿)清零。
|
||||
- [ ] 所有 BLOCKED 明确处理;首测必测项不得以“已知问题”绕过。
|
||||
- [ ] 包哈希、签名、引擎来源、设备信息与报告一致。
|
||||
- [ ] 已知 P2、未覆盖地图/装备/技能及未验收平台明确列出。
|
||||
|
||||
官方 Release 模板仍有粒子退出警告;必须显式使用验证过的自编译 arm64 引擎,并对最终包重新跑退出门禁。不将当前方案表述为已修复所有官方模板或 Intel 平台。
|
||||
|
||||
完成文档不等于完成上述开发。开发起点是 INF-01/02;它们完成后 NET-01 与 MAP-01 可并行推进。工期在首次真实闭环和树怪截图产生后根据实际缺陷估算。
|
||||
@@ -0,0 +1,115 @@
|
||||
# 首个 Mac 联网内测版:实施状态与已知问题(REL-01)
|
||||
|
||||
日期:2026-09-11。对应计划:`docs/FIRST-MAC-PLAYABLE-IMPLEMENTATION.md`。
|
||||
|
||||
后续审查:提交 `f39a55fd` 的观察器缓存保留、运行取消清理、外部内存门禁与异常 JSON 处理问题,见 [审查与修复记录](REVIEW-f39a55fd.md)。以下环境数据是原实施时的快照。
|
||||
|
||||
本文只记录已核对的事实。**当前没有可放行的候选包,也没有任何实网证据**;所有依赖服务器、测试账号、环境负责人确认或人工签核的条目均为 BLOCKED。离线/假进程测试 PASS 只证明门禁和状态机按契约工作,不能代替联网验收。
|
||||
|
||||
## 1. 结论
|
||||
|
||||
| 项 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| INF-01 契约与配置校验 | 离线 PASS | `playable_harness_test.gd` 负向用例、`validate_playable_report.mjs` 静态夹具全部通过 |
|
||||
| INF-02 运行器与退出门禁 | 离线 PASS | `script/playable_gate_test.sh` 用假签名 arm64 包覆盖 PASS/退出码/信号/超时 TERM→10s→KILL/残留 FIFO/RID 与泄漏警告/凭据脱敏/聚合 |
|
||||
| NET-01 真实联网闭环 | **BLOCKED** | 包内入口已实现;缺 `scenario.local.json`、测试账号、环境负责人确认的路线/怪物/掉落,未联网运行 |
|
||||
| CBT-01 四职业技能矩阵 | **BLOCKED** | `test/playable/skill-cases.json` 全部 `unconfirmed`;脚本不补技能 ID |
|
||||
| MAP-01 树怪资源与离线 Metal 截图 | 离线 PASS,**待人工签核** | 12 个候选树怪 × CPU/GPU × wait/run/attack/damage/dead 全部组装通过;截图需人工看过 |
|
||||
| MAP-02 实际地图定位与落地 | **BLOCKED** | `forest-viewpoints.example.json` 机位均 `unconfirmed`;坡地脚/根接触需人工检查 |
|
||||
| STB-01 2 小时稳定性 | 工具已实现,**未实跑**,BLOCKED | `script/playable_soak.sh` 可运行(见 §4);真实断网与切图需环境确认 |
|
||||
| REL-01 放行 | **BLOCKED** | 无重建候选包;上述必测项均未产生实网证据 |
|
||||
|
||||
## 2. 候选包与环境
|
||||
|
||||
- 计划中的候选包 `build/export-native-trees-20260911/mtgodot-poc.app` 和自编译引擎 `build/godot-particle-diagnostic/bin/godot.macos.template_release.arm64` 在当前工作树**不存在**。仅有 `build/export/mtgodot-poc.app`(2026-09-08),早于本轮全部 playable 代码,**不能**作为候选包。
|
||||
- 本轮修改了 GDScript(包内测试入口、流程、指标、窗口适配),**必须重新导出 PCK**;若最终修复涉及 C++,还需 `./build.sh Release` 重建扩展、重新签名打包。重建后对最终包重新跑退出门禁。
|
||||
- 官方 Release 模板的粒子退出警告未修复;必须显式使用经过验证的自编译 arm64 引擎。不宣称已修复官方模板或 Intel 平台。
|
||||
- 数据盘剩余约 7.5 GiB(99% 已用)。2 小时 soak 的 `events.jsonl`、`rss.jsonl`、截图与日志会持续写盘,实跑前需由用户腾出空间;脚本不会自行清理任何文件或系统缓存。
|
||||
|
||||
## 3. 已知问题与限制
|
||||
|
||||
### 3.1 树怪动作(MAP-01)
|
||||
|
||||
- `ent_trent`(2301/2311)的 motlist 只有 WAIT、WAIT1、NORMAL_ATTACK、NORMAL_ATTACK1、FRONT_DAMAGE、FRONT_DEAD,**没有 RUN/WALK**。按旧客户端 `CRaceData::GetMotionKey` 未命中→`SetLoopMotion` 直接返回的规则,移动时继续播放当前循环(`reference_keep_current_motion`)。`forest_mob_render_test` 报告记为 4 条 fallback(2 个 race × CPU/GPU),标注“需实网确认:服务器移动该种族时位置变化且保持原循环”。未经实网确认前不能宣称行走表现与原版一致。
|
||||
- 七种 ent 目录的 motlist 均只有 FRONT_DEAD,没有 BACK_DEAD。背后击杀时的死亡动作按旧客户端回退规则判定,需实网对照确认。死亡姿态、材质、轮廓已进入接触表截图,**必须人工签核**;AABB 底部不是脚部接触,离线测试不能证明坡地脚/根贴地。
|
||||
- `mob_winding_test.gd` 仍固定覆盖 101/110/20001;树怪由 `forest_mob_render_test.gd` 单独覆盖。
|
||||
|
||||
### 3.2 帧时间(离线合成 suite,非实网)
|
||||
|
||||
`rendering_scenario_test.gd`(Metal,suite=`offline_synthetic`,FakeClient + 真实资源)本轮结果:
|
||||
|
||||
- 689 帧,>50ms 14 帧,全部已归因(unattributed=0);>100ms:loading 6、gameplay 2。
|
||||
- gameplay 的 2 帧(119.5ms、237.0ms)都带 `viewport_resize` 标记,发生在测试主动切换窗口尺寸时。它们不属于正常游玩的重复交互,但在实网 soak 中要继续按“同一交互 3 次中 2 次 >100ms 即阻断”规则判定。
|
||||
- loading 段:同步模型构建 447–746ms,切图 1861ms 与 4489ms。首次加载预算尚未固定(计划要求基线采集后再定,不临时放宽)。
|
||||
- CPU 蒙皮 8/16 角色时 p99 分别为 70.1ms/50.5ms(90 帧窗口,p99 即最大值);GPU 蒙皮 1/8/16 角色 p99 ≤ 26.1ms。
|
||||
- 视口 1280×720、1920×1080、2560×1440 均按请求尺寸生效(screen_scale=1);Retina 缩放下的物理/逻辑换算由 `testing/playable_window.gd` 记录,未在 Retina 屏实测。
|
||||
- 冷启动:进程冷启动/系统缓存状态未知,测试不清空系统缓存。
|
||||
- 显存:`gpu_memory_kib=null`(unavailable)。Godot RenderingDevice 计数 843,616 KiB 不是系统显存,不据此判断显存泄漏。探针开销:每次采样 CPU 约 1.26µs;开/关探针 p50 差 −0.018ms,处于帧节奏噪声内。
|
||||
|
||||
### 3.3 稳定性工具的边界(STB-01)
|
||||
|
||||
- **切图**:`soak.warp.status` 默认 `unconfirmed`,STB-WARP-01 为 BLOCKED。只有环境负责人确认合法传送入口(`portal_cm`、`return_portal_cm`、`destination_map_key`、`cross_server`、偶数且 ≥20 的往返次数)后才会走传送门;不以直接改客户端节点位置代替。跨服切图须核实测试服支持。
|
||||
- **真实断网**:`soak.faults.status` 默认 `unconfirmed`,STB-DISCONNECT-01 为 BLOCKED;主动 `reconnect()`(STB-RECONNECT-01)与真实传输故障分开计数,不能互相替代。确认后由 `run_client_gate.sh` 在 127.0.0.1 上启动 `script/playable_fault_proxy.mjs`,只代理本测试客户端的连接(`server.*` 与 serverlist 必须指向代理端口,`soak.faults.upstream` 为真实测试服)。不修改全局路由、防火墙,也不关闭任何服务。
|
||||
- **已知限制**:如果服务器传送时下发了直连的 game 地址,之后的连接会**绕过代理**,故障注入对切图后的连接无效。需要在确认故障条件时一并核实,或在同一地图服务器内完成故障用例。
|
||||
- **窗口**:headless、全屏、最大化窗口不可切换尺寸;请求尺寸(含标题栏)超出屏幕可用区域时如实记为 BLOCKED,不缩小目标冒充通过。
|
||||
- **内存**:父运行器每秒采样子进程 RSS(KiB),在每轮静置 30s 后取低水位;必须 ≥ warm-up + 10 轮才判定。连续 5 轮增长,且后 5 轮中位数比前 5 轮高出 max(50MiB, 5%) 时 FAIL。低于阈值也不能证明长期无泄漏。
|
||||
- 10 次正常退出由 10 个独立进程完成,每次都经过完整退出门禁;任何一次失败,后续运行(包括 2 小时 soak)不会启动,记为 BLOCKED。
|
||||
|
||||
### 3.4 人工项(不能自动化替代)
|
||||
|
||||
- 真实鼠标/键盘闭环(点击移动、选怪、普攻、技能栏、拾取)需要单独的人工证据。
|
||||
- MAP-01/MAP-02 Metal 截图人工签核(`forest_map_render_test` 报告里 `manual_signoff.status` 恒为 `PENDING`,自动 PASS 不代表视觉签核)。
|
||||
- CBT-01 技能特效截图需人工看过一次。
|
||||
|
||||
## 4. 已可运行的命令
|
||||
|
||||
以下命令在 `metin2-client/` 下执行。账号只通过 `MT_ACCOUNT`/`MT_PASSWORD` 环境变量或隐藏输入提供,禁止写进配置、参数或命令历史。
|
||||
|
||||
离线(不连服务器,本轮均 PASS):
|
||||
|
||||
```bash
|
||||
bash script/playable_gate_test.sh
|
||||
node script/playable_soak_metrics_test.mjs
|
||||
node script/playable_fault_proxy_test.mjs
|
||||
node script/audit_playable_maps_test.mjs
|
||||
(cd project && godot --headless --path . --script playable_harness_test.gd)
|
||||
(cd project && godot --path . --script forest_mob_render_test.gd)
|
||||
bash script/rendering_batch_test.sh
|
||||
```
|
||||
|
||||
联网(需要重建候选包、`test/playable/scenario.local.json` 与测试账号;**本轮未运行**):
|
||||
|
||||
```bash
|
||||
bash script/playable_test.sh --app "$PWD/build/export-playable-rc1/mtgodot-poc.app" --config test/playable/scenario.local.json --suite full --allow-gameplay --repeat 3
|
||||
bash script/playable_soak.sh --app "$PWD/build/export-playable-rc1/mtgodot-poc.app" --config test/playable/scenario.local.json --allow-gameplay --duration-seconds 7200
|
||||
node script/validate_playable_report.mjs --release-dir <本批次输出目录>
|
||||
```
|
||||
|
||||
`playable_soak.sh` 行为:
|
||||
|
||||
- 先用 soak suite 校验配置和资源。缺少 `--allow-gameplay` 时只做校验,返回 2,不启动客户端。
|
||||
- 依次运行 `exit-1..exit-N`(suite playable,N ≥ 10)和 `soak-1`(suite soak,墙钟时长 = `soak.duration_seconds`,超时 ≥ 时长 + 900s)。
|
||||
- 写出只列本批次运行的 `release-manifest.json`(required_runs `{playable:N, soak:1}`),再聚合。
|
||||
- 退出码:0 PASS / 1 FAIL / 2 BLOCKED / 124 超时。
|
||||
|
||||
## 5. 放行检查表对照(计划 §11)
|
||||
|
||||
| 检查项 | 当前 |
|
||||
| --- | --- |
|
||||
| INF-01/02 负向用例通过,必测项缺失不能 PASS | ✅ 离线通过 |
|
||||
| 同一候选包 3 轮联网闭环 + 鼠标键盘证据 | ❌ BLOCKED(无候选包、无账号/夹具、无人工证据) |
|
||||
| 四职业基础战斗、技能及异常路径 | ❌ BLOCKED(技能矩阵未确认) |
|
||||
| 首测地图和树怪资源/动作/Metal 画面 | ⚠️ 离线组装通过;机位未确认、人工签核未做、实网未跑 |
|
||||
| 2 小时、切图、故障恢复、窗口、退出次数 | ❌ BLOCKED(工具就绪,未实跑;切图/断网条件未确认) |
|
||||
| P0/P1 清零 | ❌ 未知:没有实网运行,无法判定 |
|
||||
| 所有 BLOCKED 明确处理 | ⚠️ 本文已列出;首测必测项不得以“已知问题”绕过 |
|
||||
| 包哈希、签名、引擎来源、设备信息一致 | ❌ 需重建候选包后由运行器生成 |
|
||||
| 已知 P2、未覆盖地图/装备/技能及未验收平台列出 | ⚠️ 本文 §3;未覆盖:首测三图以外的地图、Intel、官方模板 |
|
||||
|
||||
## 6. 需要环境负责人提供
|
||||
|
||||
1. 自编译 arm64 引擎和重新导出的候选包(含本轮脚本),以及足够的磁盘空间。
|
||||
2. `test/playable/scenario.local.json`:由 `scenario.example.json` 复制,填写 serverinfo 中的地址、角色槽位、map_key、安全路线、怪物/掉落 vnum;soak 需 `timeout_seconds ≥ duration_seconds + 900`。
|
||||
3. 专用测试账号(等级、装备、已学技能、掉落条件由负责人准备),以及 `skill-cases.local.json` 中各职业的确认记录。
|
||||
4. 如需 STB-WARP/STB-DISCONNECT:合法传送入口的确认;确认可在 127.0.0.1 代理后运行,并核实传送是否下发直连地址。
|
||||
5. 树怪机位(平地/坡地/密林/传送点)的确认,以及 Metal 截图人工签核人。
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user