Commit Graph
22 Commits
Author SHA1 Message Date
shenleiandClaude Opus 5 5fad769ee8 port 2P step 1: vendor CPython 2.7.18 as the mtpython static library
The embedded 40250 script layer needs its own interpreter on five platforms.
2.7 is end-of-life, so nothing can be fetched from the target SDKs and the
source is vendored (official 2.7.18 tarball, trimmed to 25MB; Lib/ stays for
step 3's python27.zip).

cpython-2.7.18/CMakeLists.txt builds one `mtpython` static library from exactly
the 133 objects the reference libpython2.7.a contains, off by default behind
-DMTGODOT_EMBED_PYTHON=ON. The source list and the built-in module table
(config/config.c, 39 entries) are shared; pyconfig.h is a probe result and is
not, so each platform keeps its own under config/<platform>/, regenerated by
tools/py_embed/gen_pyconfig.sh and checked against the shared table.

Three vendor patches, documented in docs/THIRD-PARTY.md: configure/configure.ac
learn arm64 on macOS, and posixmodule.c undefines the process-control calls it
hard-defines past pyconfig.h when building for iOS.

macOS (ctest python.embed: every builtin imports, codecs and pickle work off the
vendored Lib/), Android arm64 and iOS arm64 build. Linux needs a Linux host and
Windows needs a MinGW-vs-MSVC decision; both are noted for step 4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 08:27:35 +09:00
shenleiandClaude Opus 5 a9b31dec67 port 2D steps 3-4: strict 40250 asset gate with a provenance manifest
tools/asset_manifest.py records path/size/sha256 of pack/Index, every .eix/.epk
and Eternexus/root/*.msm (audit/assets/40250-client.json). The gate script sets
MT_ASSETS_STRICT=1, verifies the manifest, runs the native pack/proto tests and
four Godot tests, and fails on a missing client, a mismatch or a skip.
MT_40250_CLIENT now comes from the environment for the native tests too.
remote_player_test accepts both weighted WAIT variants (wait/wait_1).
PORT-PLAN §5 records the 2D status.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 01:41:38 +09:00
shenleiandClaude Opus 5 232d0461be port 2D step 2: 40250 item_proto/mob_proto through CLZO and pack://locale/<lang>/
proto.cpp reads the 40250 MIPX/MMPT tables with the ported CLZO/TEA (156-byte
TItemTable, 255-byte SMobTable), replacing the m2dev XChaCha20 236/335 reader.
Names follow CItemData::GetName / GetMonsterName (szLocaleName, cp1252).
GDScript callers load AssetRoot.locale_file() = pack://locale/en/<name>, which
makes the EterPack chain runtime-reachable; port-map entries for the functions
a coverage run hit move to PORTED/ADAPTED.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 01:34:08 +09:00
shenleiandClaude Opus 5 5a26e93f07 port 2D step 5b: PackInitialize + pack:// asset_io backend over the ported EterPackManager
Platform UserInterface PackInitialize/PackSingletons (40250 bootstrap, on-disk dbname
resolution), EterBase/FileLoader.cpp mirror, mtpack40250 backend behind asset_io's
pack:// scheme and a Metin2Pack node. port_eterpack_test now registers through
PackInitialize. Nothing reads pack:// at runtime yet; port-map stays TODO.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 01:31:17 +09:00
shenleiandClaude Opus 5 1f1004da79 port 2D step 5a: EterPack/EterPackManager + EterBase file units against the real 40250 packs
- Mirror copies: EterPack (EterPack, EterPackManager, EterPackCursor, CSHybridCrypt policy, Inline.h)
  and EterBase logic units tea/lzo/Timer/Stl/Random, with PORT-tagged width fixes (LONG index
  fields, static_assert(sizeof(TEterPackIndex) == 192), tea_word = Win32 unsigned long).
- TEA pack keys are extracted from the reference EterPack.cpp at configure time into
  build/.../EterPackKeys.generated.h; nothing key-bearing is tracked.
- Platform EterBase: FileBase (stdio, case-insensitive fallback), MappedFile (mmap /
  MapViewOfFile), CRC32, Debug, Utils StringPath/StringLowers.
- Win32Crt: CreateDirectory/DeleteFile/_access/MAKEFOURCC; Win32MinMax.h min/max (force-included
  on MinGW, whose windows.h omits them in C++).
- tests/port_eterpack_test: registers pack/Index like PackInitialize and checks 119
  registrations / 103 packs + root / 54891 entries / 52609 paths / 2282 overrides with
  first-registered-wins, and that exactly the 4 short-layout SECURITY files fail to load.
- 2R count corrected (136 -> 119 registrations, 103 distinct packs + root).

Not runtime-reachable yet (asset_io pack backend is step 5b), so port-map statuses stay TODO.
port_gate: macos/android/ios/windows PASS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 00:56:39 +09:00
shenleiandClaude Opus 5 f210f47076 Batch 2R: 40250 pack inventory (epk_scan) and delivery decision
Read-only scanner for Client/pack following PackInitialize -> CEterPackManager
-> CEterPack::__BuildIndex/Get2. Keys are read from the reference EterPack.cpp
at run time; none are stored. Pure-Python TEA + LZO1X.

- 136 registered packs, 54,891 entries: NONE/COMPRESS/SECURITY only, no
  PANAMA/HybridCrypt, all entries decode
- first-registered pack wins; 2,282 shadowed entries (2,194 differ)
- metin2_patch_{sd,mineral,mundi} use a second packer layout; 4 SECURITY
  files fail 40250's CRC check and never load in the original
- no case collisions; paths are already lowercase
- PORT-PLAN: read EPK on device via ported EterPack, base install minus
  extra locales, rebuild dict in Index order on any pack change

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 23:59:18 +09:00
shenleiandClaude Opus 5 220f15b404 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>
2026-09-22 23:21:24 +09:00
shenleiandClaude Opus 5 4521845a69 audit(2A): include-dependency tool, 2V0-2V3 slice unit lists and batch-2 order
port_deps.py resolves explicit #include edges plus the implicit edges each
40250 library's StdAfx.h supplies (symbol index restricted to StdAfx-visible
headers), writes cumulative slice lists and the P0 topological order.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 19:21:10 +09:00
shenandshen ae68ec5944 docs(port-plan): close migration prerequisite gaps 2026-09-22 03:01:57 -07:00
shenleiandClaude Opus 5 dcefc83211 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>
2026-09-22 18:38:04 +09:00
shenleiandClaude Opus 5 67a62e3390 docs(port-plan): data-source switch from m2dev assets to 40250 (batch 2D)
Records the root/uiscript/locale comparison: npclist, msm contents and
motion/combo registration match; msm location differs; item_proto and
mob_proto use a different record layout and TEA instead of XChaCha20,
so proto.cpp cannot read them; pack contents not yet compared.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 18:28:41 +09:00
shenleiandClaude Opus 5 184b631ce8 docs: PORT-PLAN.md as the single entry for the 40250 port route
Records the decisions (mirror-layout logic port, embedded CPython 2.7 UI),
layers and code layout, batch route and status, and the directory/toolchain
setup needed to resume on another machine. Marks the older refactor plan as
superseded and points CLAUDE.md/AGENTS.md/roadmap at it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 18:20:14 +09:00
shenleiandClaude Opus 5 9d0e50de8f 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>
2026-09-22 18:06:32 +09:00
shenleiandClaude Opus 5 a989b8f19b chore: delete 106 unreachable *_system.gd and their parity tests
These files were loaded only by their own test_*_parity.gd and never by
the runtime (transitively checked, incl. client_phase_integration_system).
Removes 76 manifest implementation/evidence references across 18
contracts; contract docs get a note that conclusions based on them are
void. Live systems kept: chest, consumable, item_attr, metin_socket,
whisper_chat.

Full headless suite: no new failures (7 failing + 5 headless-hanging
render tests are identical before the deletion).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 17:51:52 +09:00
shenleiandClaude Opus 5 5afd5a4f0d audit: refresh fingerprints after phase 0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 17:17:54 +09:00
shenleiandClaude Opus 5 55f733fda6 audit: phase 0 tooling for file-by-file 40250 porting
- refroot.py: one reference-root resolver (MT_40250_SOURCE, then manifest)
  used by every audit script; missing tree or fingerprint input is an error
- port_map.py: per-function inventory of active 40250 units plus the
  40250 Python root, status/queue/init/show/check, 40250: tag scan
- manifest: fix 18 wrong reference paths (Python UI now points at the
  40250 Client/Eternexus/root, not the m2dev assets/root), drop 2 deleted
  implementation files, move 64 prose test entries to evidence.commands
- first port-map entry: PythonPlayerEventHandler.cpp
- roadmap replaced by a batch/unit queue

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 17:17:49 +09:00
shenleiandClaude Opus 5 6a175ee293 fix(movement): drop idle FUNC_WAIT resend with no 40250 counterpart
40250 only calls OnWaiting inside CInstanceBase::Transform() while
IsWalking() (InstanceBase.cpp:1922-1930); it never resends position
while standing. Remove _tick_on_waiting and its throttle state.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 17:12:16 +09:00
shenleiandClaude Sonnet 5 c5c183da37 fix(movement): remove unreferenced [0.25,3.0] clamp on local player's movSpd scale
CInstanceBase::SetMoveSpeed only guards moving_speed > 1100 -> 0; the local
player's set_server_speed() was additionally floor/ceil-clamping the scale to
an arbitrary [0.25, 3.0] band with no basis in the reference or in this
project's already-fixed remote-entity equivalent (EntityStore::motion_move_speed).
A heavy haste stack or slow debuff on the local player would silently diverge
from what everyone else sees. Removed the extra clamp; kept the moving_speed<=0
early-return guard against pre-spawn/malformed values.

audit: movement.keyboard.motion/server-speed-scale-clamp closed with reference
citation, regression test, and full related-suite pass; contract stays PARTIAL.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 16:31:17 +09:00
shenleiandClaude Sonnet 5 a4ac48db24 audit(movement.keyboard.motion): close Paralysis/Faint/Sleep gate as false positive
Investigated the prior round's flagged gap ("CanAct()'s Paralysis/Faint/Sleep
movement doors not wired into net_play.gd") via exhaustive reachability
tracing of the 40250 reference source. All three resolve to non-gaps:

- Paralysis: its only setter (__Shaman_SetParalysis, InstanceBaseEffect.cpp:821)
  has zero callers anywhere in the reachable source -- dead code, never true
  in live gameplay.
- Sleep: the AFFECT_SLEEP case in SetAffect() is commented out; the only live
  setter is the AFFECT_STUN case (SetSleep(), InstanceBaseEffect.cpp:932-933),
  i.e. IsSleep() is just an alias for AFFECT_STUN -- already covered by the
  existing `stunned` field and _can_process_network_state()'s dead/stunned/
  knock_down gate.
- Faint: only setter is chrFaintTest(), a debug-only Python binding operating
  on GetSelectedInstancePtr(); unverifiable from the available 40250 checkout
  (no root/ UI scripts) -- evidence-blocked, left unresolved per the skill's
  reachability rule.

Byproduct finding while tracing IsStun(): main-character GC_STUN routes to
Die() in the reference (RecvStunPacket), not Stun(); verified this causes no
movement.keyboard.motion discrepancy since CanAct() blocks movement equally
on IsDead()/IsStun() and the current client already blocks movement equally
on dead/stunned. The Die()-vs-Stun() distinction only affects death-system
semantics, already tracked under combat.affect-status.md (Remaining #2, rows
63/67) -- not duplicated here.

No implementation code changed. Removed the resolved item from manifest.json
and movement.keyboard-motion.md's Remaining list; documented full evidence
in the contract doc and remediation roadmap. Contract stays PARTIAL
(AccumulationMovement root-motion, OnMove/OnMoving event-source parity,
sync/hit/death/warp gate stacking, and real-model bone-flip test remain open
for future rounds).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 16:20:49 +09:00
shenleiandClaude Sonnet 5 7df97e01f9 fix(movement): camera auto-rotates to face WASD input direction
40250 parity: CPythonPlayer::NEW_MoveToDirection's m_isCmrRot branch
continuously rolls the camera toward the held movement direction every
frame while a direction key is down, independent of whether a new
translation target was just set. Add _camera_auto_rotate() to replicate
this (forward/back = no rotation, strafe = max rate, diagonal = half
rate), called unconditionally after the frozen/locked/shop/emotion gate
in _process(). Godot's yaw-increase handedness is opposite the
reference's D3D Roll(), so the sign is flipped as a platform adaptation;
verified by convergence invariants in keyboard_motion_timeline_test.gd
rather than bit-for-bit angle matching.

Closes movement.keyboard.motion/camera-auto-follow-rotation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 16:17:00 +09:00
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00
shenandshen 1522a8a1a1 完善客户端功能并加入40250一致性审计 2026-09-21 16:38:58 -07:00