docs(port-plan): add 2A/2R/2V prerequisites after plan review
- keep 40250 widths/overflow semantics (Win32 long = 32-bit), fixed-width serialized structs with static_assert, instead of copying C type names - 2A base batch (types, header closure, port_logic target, platform stubs, header gate, port-map re-baseline) and include-order porting - 2R pack inventory: six EPK compression types, HybridCrypt key source, index override order, path case, mobile delivery - 2P: shared source list, per-platform pyconfig.h, all five platforms - 2V minimal vertical slice; old and new paths coexist until wired - strict asset tests (MT_ASSETS vs M2_ASSETS), RUN_AS_IS instead of N_A, void the 6 pre-architecture 'done' functions Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,13 +26,14 @@ The 40250 source is the specification. Do not design behavior; transcribe it. Co
|
||||
|
||||
## Code layout: mirror 40250
|
||||
|
||||
The logic layer has the 40250 structure, not a new architecture. `port_map.py` assigns every unit
|
||||
The logic layer has the 40250 structure, not a new architecture. Route, batch order and
|
||||
prerequisites (2A base, 2R pack inventory, 2V vertical slice) are in `docs/PORT-PLAN.md`. `port_map.py` assigns every unit
|
||||
one of three layers:
|
||||
|
||||
| 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 |
|
||||
| `python` | `Client/Eternexus/root/*.py`, `uiscript/`, `UserInterface/*Module.cpp`, `EterPythonLib/`, `ScriptLib/` | Decided: embedded CPython 2.7.18 runs the scripts unchanged (`docs/PYTHON-EMBED-EVAL.md`, batch 2P); port only the C++ side. Never translate the scripts. Script functions get `RUN_AS_IS` (after the 2A re-baseline), never `N_A`. 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:
|
||||
@@ -43,11 +44,18 @@ Rules for the `logic` layer:
|
||||
- 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).
|
||||
`extension/src/net/entity_store.cpp` are migration sources. Old and new paths coexist behind a
|
||||
switch until the new path is wired into the runtime; delete the old logic in the same commit that
|
||||
switches its callers to the ported code, leaving only glue (node creation, forwarding Godot input,
|
||||
reading ported state to place nodes). A ported function nothing calls at runtime stays `TODO`.
|
||||
- Keep 40250 **widths and overflow semantics**, not its C type names: 40250 is Win32, where `long` and
|
||||
`unsigned long` are 32-bit. Use the fixed-width types from `port/common/Win32Types.h`; every
|
||||
serialized struct (proto records, packets, EPK index, msa/msm) gets 40250's `#pragma pack` and a
|
||||
`static_assert(sizeof(T) == N)`; pointers stored in `DWORD` become `uintptr_t` with a port-map note.
|
||||
- Keep 40250 units (`TPixelPosition` in cm, `DWORD` ms from `ELTimer_GetMSec`, degrees).
|
||||
Convert to Godot space only in the adapter.
|
||||
- Port in `#include`-dependency order: a shared header belongs to the first unit that needs it, and
|
||||
units depending on it start only after it lands. Separate `.cpp` files do not make units independent.
|
||||
- `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:
|
||||
@@ -67,7 +75,8 @@ optional, because the file and method name already map one to one.
|
||||
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;
|
||||
- when the ported path is wired into the runtime, delete the old logic it replaces and rewire
|
||||
callers in the same commit (see `docs/PORT-PLAN.md`, "迁移方式");
|
||||
- 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.
|
||||
|
||||
Reference in New Issue
Block a user