docs(parity): mirror 40250 layout for the logic layer; evaluate embedded Python UI
- SKILL.md: logic units port into extension/src/port/<Lib>/<File>, platform adapters under extension/src/platform; legacy GDScript owners are migration sources; python layer frozen until the embedding decision - port_map.py: logic/python/platform layers with per-layer progress, queue --layer, LEGACY layout check; inventory adds EterBase, EterPythonLib, ScriptLib, SpeedTreeLib, SphereLib, EterImageLib - py_embed_spike.py + docs/PYTHON-EMBED-EVAL.md: the 40250 system.py bootstrap loads 67/74 root modules unchanged under CPython 2.7 with stub natives Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,32 +24,50 @@ The 40250 source is the specification. Do not design behavior; transcribe it. Co
|
||||
runtime never loads (e.g. a `*_system.gd` referenced only by its own `test_*_parity.gd`) must be
|
||||
deleted or wired in by porting the real 40250 caller, never cited as parity.
|
||||
|
||||
## Porting target per layer
|
||||
## Code layout: mirror 40250
|
||||
|
||||
| 40250 layer | How to port | Where |
|
||||
| --- | --- | --- |
|
||||
| Platform-independent C++ logic (packet structs/handlers, sequence table, formulas, state machines in `UserInterface/`, `GameLib/`; `EterPack`, `EterLocale`) | Transliterate C++ -> C++, keeping class/function structure and names so each function has one counterpart | `extension/src/` |
|
||||
| 40250 C++ logic that currently lives in GDScript | Port function by function, same names in snake_case, same order of statements | existing `.gd` owner |
|
||||
| Python UI (40250 `Client/Eternexus/root/*.py` + `uiscript/`, **not** `assets/root`) | Translate per `.py` file into its GDScript window, keeping method structure | `project/ui/` |
|
||||
| Direct3D, Granny, Miles, Win32 input/window, IME, DirectX math | Platform adapter; equivalence by observable output | `extension/`, `project/` |
|
||||
The logic layer has the 40250 structure, not a new architecture. `port_map.py` assigns every unit
|
||||
one of three layers:
|
||||
|
||||
Mark every ported function with a one-line tag at its definition so coverage can be scanned
|
||||
mechanically: `// 40250: CInstanceBase::SetMoveSpeed` (C++) or `# 40250: CInstanceBase::SetMoveSpeed`
|
||||
(GDScript). Tag only real counterparts.
|
||||
| Layer | 40250 units | How to port | Where |
|
||||
| --- | --- | --- | --- |
|
||||
| `logic` | `UserInterface/`, `GameLib/`, `EterLib` net/timer/text parsing, `EterPack`, `EterLocale` (everything not listed below) | Copy C++ -> C++. Same file name, class name, method names, member names and statement order; one reference file = one implementation file | `extension/src/port/<Lib>/<File>.{h,cpp}` |
|
||||
| `python` | `Client/Eternexus/root/*.py`, `uiscript/`, `UserInterface/*Module.cpp`, `EterPythonLib/`, `ScriptLib/` | Being evaluated as embedded CPython 2.7 running the scripts unchanged (`docs/PYTHON-EMBED-EVAL.md`). **Do not port or translate this layer until that evaluation is decided.** Reference is 40250 `Eternexus/root`, **not** `assets/root` | `extension/src/port/<Lib>/` (bindings), scripts from pack |
|
||||
| `platform` | Direct3D/`Grp*`, Granny (`EterGrnLib`), Miles, SpeedTree, `EffectLib`/terrain rendering, Win32 window/input/IME, threads, anti-cheat | Adapter behind the interface the 40250 caller uses; equivalence by observable output | `extension/src/platform/` + existing render code (`metin2_model`, `metin2_anim`, `gr2_bridge`, ...) |
|
||||
|
||||
Rules for the `logic` layer:
|
||||
|
||||
- Port a whole unit into its mirror file. Where 40250 calls a platform class (`CGraphicThingInstance`,
|
||||
`CStateManager`, `CSoundManager`, ...), call a same-named adapter interface declared under
|
||||
`extension/src/platform/`; never inline Godot calls into ported logic.
|
||||
- 40250 singletons (`CPythonPlayer::Instance()`, `CPythonCharacterManager`, `CPythonNetworkStream`)
|
||||
stay singletons owned by the extension. GDScript does not hold gameplay state.
|
||||
- GDScript (`net_play.gd`, `net_world.gd`, `game_scene.gd`, `player_controller.gd`) and
|
||||
`extension/src/net/entity_store.cpp` are migration sources. In the commit that ports a unit, delete
|
||||
the old logic it replaces there and leave only glue: node creation, forwarding Godot input to the
|
||||
ported input handlers, and reading ported state to place nodes.
|
||||
- Keep 40250 types and units (`TPixelPosition` in cm, `DWORD` ms from `ELTimer_GetMSec`, degrees).
|
||||
Convert to Godot space only in the adapter.
|
||||
- `port_map.py check` prints `LEGACY` for a `logic` function whose `impl` is outside its mirror file.
|
||||
|
||||
Mark each ported function with a one-line tag at its definition:
|
||||
`// 40250: CInstanceBase::SetMoveSpeed`. Tag real counterparts only. In mirror files the tag is
|
||||
optional, because the file and method name already map one to one.
|
||||
|
||||
## Round workflow
|
||||
|
||||
1. **Pick a unit** from the current batch in `audit/remediation-roadmap.md`, or from
|
||||
`port_map.py queue` (ordered by user-visible gameplay; see Priority). Run
|
||||
`port_map.py queue` (logic layer by default, ordered by user-visible gameplay; see Priority). Run
|
||||
`port_map.py init <unit>` and `port_map.py show <unit>` to get the function list.
|
||||
2. **Read the whole reference unit** under the reference root (see `references/project-map.md`;
|
||||
use `grep -a`, many files contain CP949 bytes). Read every current counterpart, found by the
|
||||
`40250:` tags, the port-map entry, or `references/project-map.md`.
|
||||
3. **For each reference function**, compare statement by statement: preconditions and early
|
||||
returns, branches, formulas, constants and units, state writes and their order, timing/event
|
||||
source, data source (proto/msa/msm/txt, never hardcoded), packets sent, cleanup. Then:
|
||||
- transliterate it where missing or divergent;
|
||||
- delete current-only logic it replaces;
|
||||
3. **Copy the unit into its mirror file** and, for each reference function, compare it with the
|
||||
old counterpart statement by statement: preconditions and early returns, branches, formulas,
|
||||
constants and units, state writes and their order, timing/event source, data source
|
||||
(proto/msa/msm/txt, never hardcoded), packets sent, cleanup. Then:
|
||||
- keep the 40250 version; record each old behavior that differed as a divergence found;
|
||||
- delete the old logic it replaces and rewire callers to the mirror class;
|
||||
- mark `N_A` only for pure platform plumbing (D3D state, Python binding glue, Win32), with a reason.
|
||||
4. **Test what changed**: a focused test using the reference's own boundary values for each changed
|
||||
formula/branch (fails before, passes after). Do not write tests for unchanged or trivial code.
|
||||
@@ -110,9 +128,12 @@ behavior verified from code inspection alone.
|
||||
|
||||
## Tools
|
||||
|
||||
- `scripts/port_map.py status | queue | init <unit> | show <unit> | check` — function inventory
|
||||
(active `.vcxproj` sources + the 40250 Python root), per-unit status, and tag/port-map consistency.
|
||||
Run `check` before every commit that touches `audit/port-map/`.
|
||||
- `scripts/port_map.py status | queue [--layer logic|python|platform] | init <unit> | show <unit> | check`
|
||||
— function inventory (active `.vcxproj` sources + the 40250 Python root), progress per library and
|
||||
per layer, and tag/port-map/layout consistency. Run `check` before every commit that touches
|
||||
`audit/port-map/`.
|
||||
- `scripts/py_embed_spike.py` (Python 2.7) — runs the 40250 `system.py` bootstrap with stub native
|
||||
modules; used by the embedded-Python evaluation.
|
||||
- `scripts/audit_ledger.py refresh --write | report --write | validate` — run once per batch, not
|
||||
per round. Missing reference, implementation or test files are an error; `evidence.tests` holds
|
||||
paths only, command lines go in `evidence.commands`.
|
||||
|
||||
Reference in New Issue
Block a user