port: 2A step 6, port-map re-baseline
Fix the per-function inventory against the clang-derived platform skeleton: strip comments, accept indented qualified definitions in namespace blocks, long parameter/initializer lists and all-caps qualified ctors, and skip constructor initializer entries. Split EterBase by unit: tea/lzo/cipher/ Random/Stl/Timer/Poly become logic, the file/OS units stay platform; drop the 8 obsolete platform stubs and regenerate audit/slices. Baseline: logic 3343, python 5175, platform 2091 (10609), 0 done. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -32,9 +32,9 @@ 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}` |
|
||||
| `logic` | `UserInterface/`, `GameLib/`, `EterLib` net/timer/text parsing, `EterPack`, `EterLocale`, `EterBase` pure units (`tea`, `lzo`, `cipher`, `Random`, `Stl`, `Timer`, `Poly/`) (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/` | 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` once its evidence gate passes, 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`, ...) |
|
||||
| `platform` | Direct3D/`Grp*`, Granny (`EterGrnLib`), Miles, SpeedTree, `EffectLib`/terrain rendering, Win32 window/input/IME, threads, anti-cheat, `EterBase` file/OS units (`_ETERBASE_PLATFORM` in `port_map.py`) | 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:
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ PY_ROOT = "../../Client/Eternexus/root"
|
||||
UNIT_DIRS = REFERENCE_DIRS + ("EterBase", "EterPythonLib", "ScriptLib", "SpeedTreeLib", "SphereLib", "EterImageLib")
|
||||
PORT_DIR = "extension/src/port"
|
||||
LAYERS = ("logic", "python", "platform")
|
||||
# EterBase units that wrap Win32 file/OS/UI resources. The rest (tea, lzo, cipher, Random, Stl, Timer, Poly/*)
|
||||
# is plain logic and is ported into the mirror; CRC32 and Utils mix pure helpers with Win32 calls and stay here.
|
||||
_ETERBASE_PLATFORM = ("CPostIt", "CRC32", "Debug", "FileBase", "FileDir", "FileLoader", "MappedFile", "TempFile",
|
||||
"Utils", "error")
|
||||
# First matching pattern wins; anything unmatched is `logic`.
|
||||
LAYER_PATTERNS = [
|
||||
("python", [f"{PY_ROOT}/*.py", "EterPythonLib/*", "ScriptLib/*", "UserInterface/*Module.cpp",
|
||||
@@ -49,7 +53,7 @@ LAYER_PATTERNS = [
|
||||
"EterLib/LensFlare.cpp", "EterLib/ScreenFilter.cpp", "EterLib/Decal.cpp", "EterLib/EnvironmentMap.cpp",
|
||||
"EterLib/JpegFile.cpp", "EterLib/TargaResource.cpp", "EterLib/DibBar.cpp", "EterLib/BlockTexture.cpp",
|
||||
"EterLib/CullingManager.cpp", "EterLib/Thread.cpp", "EterLib/Mutex.cpp", "EterLib/FileLoaderThread.cpp",
|
||||
"EterLib/TextBar.cpp", "EterLib/Dimm.h", "EterBase/*", "GameLib/MapOutdoorRender*.cpp", "GameLib/MapOutdoorWater.cpp",
|
||||
"EterLib/TextBar.cpp", "EterLib/Dimm.h", *[f"EterBase/{u}.cpp" for u in _ETERBASE_PLATFORM], "GameLib/MapOutdoorRender*.cpp", "GameLib/MapOutdoorWater.cpp",
|
||||
"GameLib/SnowParticle.cpp", "GameLib/SnowEnvironment.cpp", "GameLib/TerrainDecal.cpp",
|
||||
"GameLib/TerrainPatch.cpp", "UserInterface/PythonApplicationLogo.cpp", "UserInterface/MovieMan.cpp",
|
||||
"UserInterface/HackShield.cpp", "UserInterface/NProtectGameGuard.cpp", "UserInterface/ProcessCRC.cpp",
|
||||
@@ -81,6 +85,10 @@ DEFAULT_PRIORITY = "P4"
|
||||
# Column-0 definition: `<ret> [Class::]name(` where the body `{` follows on this or the next line.
|
||||
_DEF = re.compile(r"^(?!return\b|else\b|if\b|while\b|for\b|switch\b|case\b|#|//|/\*|\s)"
|
||||
r"[^;(){}=]*?\b((?:[A-Za-z_]\w*::)*~?[A-Za-z_]\w*)\s*\(")
|
||||
# Indented qualified definition inside a namespace block: `\t<ret> Class::name(...)` with a return type,
|
||||
# or a constructor/destructor `\tClass::[~]Class(`, so calls in function bodies are not taken.
|
||||
_INDENTED_DEF = re.compile(r"^[ \t]+(?:(?!return\b|else\b|delete\b|new\b|throw\b|case\b)[A-Za-z_][\w:<>,*& ]*[\s*&]+"
|
||||
r"((?:[A-Za-z_]\w*::)+~?[A-Za-z_]\w*)|((?:[A-Za-z_]\w*::)*([A-Za-z_]\w*)::~?\3))\s*\(")
|
||||
_PY_CLASS = re.compile(r"^class\s+(\w+)")
|
||||
_PY_DEF = re.compile(r"^(\s*)def\s+(\w+)\s*\(")
|
||||
_TAG = re.compile(r"(?://|#)\s*40250:\s*([A-Za-z_][\w:.~]*)")
|
||||
@@ -90,17 +98,32 @@ def sha256(path: Path) -> str:
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
_COMMENT_OR_LITERAL = re.compile(r'//[^\n]*|/\*.*?\*/|"(?:\\.|[^"\\\n])*"|\'(?:\\.|[^\'\\\n])*\'', re.S)
|
||||
|
||||
|
||||
def _strip_comments(text: str) -> str:
|
||||
"""Blank out comments (keeping line breaks) so commented-out code and comment prose are not scanned."""
|
||||
def blank(m: re.Match) -> str:
|
||||
s = m.group(0)
|
||||
return s if s[0] in "\"'" else re.sub(r"[^\n]", " ", s)
|
||||
return _COMMENT_OR_LITERAL.sub(blank, text)
|
||||
|
||||
|
||||
def cpp_functions(path: Path) -> list[str]:
|
||||
lines = path.read_bytes().decode("latin-1").splitlines()
|
||||
lines = _strip_comments(path.read_bytes().decode("latin-1")).splitlines()
|
||||
names: list[str] = []
|
||||
for i, line in enumerate(lines):
|
||||
m = _DEF.match(line)
|
||||
m = _DEF.match(line) or _INDENTED_DEF.match(line)
|
||||
if not m or line.rstrip().endswith(";"):
|
||||
continue
|
||||
name = m.group(1)
|
||||
if name.isupper() or name.split("::")[-1].isupper(): # macros
|
||||
prev = next((l.rstrip() for l in reversed(lines[:i]) if l.strip()), "")
|
||||
if prev.endswith((",", ":")) and not prev.endswith("::") and "::" not in m.group(0):
|
||||
continue # member initializer `m_x(NULL),` of a constructor above
|
||||
name = next(g for g in m.groups() if g)
|
||||
if "::" not in name and name.isupper(): # macros; CLZO::CLZO is a real constructor
|
||||
continue
|
||||
rest = "\n".join(lines[i:i + 8])
|
||||
# The body `{` may follow a long parameter or initializer list; a `;` first means a declaration or call.
|
||||
rest = "\n".join(lines[i:i + 40])
|
||||
body = rest.find("{")
|
||||
semi = rest.find(";")
|
||||
if body < 0 or (0 <= semi < body):
|
||||
|
||||
Reference in New Issue
Block a user