Commit Graph
60 Commits
Author SHA1 Message Date
shenandshen 3c52ced02e Adapt Android mobile controls and native client UI 2026-09-28 19:39:13 -07:00
shenleiandClaude Opus 5.5 a1ae69aa7a zh locale: pack locale_zh and add reviewed Chinese names
eterpack_pack writes locale packs in the original format (COMPRESS
entries, LZO+TEA index), and build_zh_locale.py packs locale/zh into
locale_zh.eix/.epk registered in pack/Index instead of leaving loose
files.

The reviewed translations for names and keys still in English are
kept apart from the server snapshot in data/zh_40250/*_zh_overlay.txt
(1,607 items, 231 mobs/NPCs, 45 locale_game keys) and override it at
build time. Only YMIR, the coordinate-named warp markers and the empty
TOOLTIP_UNSEAL_LEFT_TIME remain English.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:45:58 +09:00
shenleiandClaude Opus 5.5 fd051cc3ed android-native: SDL3 APK build for the native client
build-android-native.sh downloads SDL 3.4.16 (sha256-checked), builds
libSDL3.so and libmain.so (native_render + port_platform + embedded
Python) at API 24, and wraps them in the SDLActivity shell under
android-native/ (package org.metin2port.client). push-android-client.sh
copies the 40250 Client directory into the app's files/ with run-as
(--locale XX selects locale_XX.cfg). port_logic links with
--no-dependent-libraries on ELF targets so the verbatim
`#pragma comment(lib, ...)` lines do not break lld.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:45:58 +09:00
shenleiandClaude Opus 5.5 0b701d88c3 codepage: replace iconv with bundled WindowsBestFit tables
mt_codepage implements code pages 874/932/936/949/950/1250-1258 from
Microsoft's bestfit<cp>.txt sources (script/gen_codepage_tables.py,
SHA-256 pinned). Win32Crt's MultiByteToWideChar/WideCharToMultiByte/
IsDBCSLeadByteEx and net/text_codec use it, so the Android API 24 build
no longer depends on iconv. port.codepage checks every table against
its source file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 18:45:49 +09:00
shenleiandClaude Opus 5.5 22ca5da387 UserInterface: 32-bit LONG sockets in TItemData/TShopItemData
The 40250 wire structs hold Win32 long (4 bytes) sockets; on LP64 `long`
is 8, so each TShopItemData was too wide and SHOP_SUBHEADER_GC_START/_EX
misread every item after the first. Pin the wire size with a static_assert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:56:36 +09:00
shenandshen d3cf586849 render and server locale parity fixes 2026-09-28 00:18:37 -07:00
shenleiandClaude Opus 5.5 0e8a1574cb render parity unit I: 40250 PythonGraphic SetGamma, cooldown fan, up/down buttons
SetGamma, RenderCoolTimeBox, RenderUp/DownButton and GetAvailableMemory are
transliterated from 40250 in place of stubs. The cooldown fan is emitted as
untextured polygon UI commands (native_render + python_ui_surface.gd draw
Bar+quad as a polygon); D3D8 shim gains SetGammaRamp/D3DGAMMARAMP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:17:27 +09:00
shenleiandClaude Opus 5.5 91ce13c3cf EterLib: port GrpMarkInstance.cpp verbatim
Replace the platform_stub skeleton (every member unimplemented) with the 40250 source, so
guild marks in text tails and mark boxes load and draw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:34:03 +09:00
shenleiandClaude Opus 5.5 d817bd7cab SpeedTreeLib: port 40250 wrapper/forest verbatim over a CSpeedTreeRT stand-in
Delete the platform proxy tree renderer and copy SpeedTreeWrapper, SpeedTreeForest,
SpeedTreeForestDirectX8, SpeedTreeConfig.h and VertexShaders.h from 40250. The SDK
SpeedTreeRT.h public API becomes the shim; the closed CSpeedTreeRT is reimplemented in
platform/SpeedTreeLib/SpeedTreeRT.cpp (procedural geometry, static lighting, single LOD,
DIVERGENT). Shims gain the D3D8 vertex shader declaration tokens, D3D_OK,
CreateVertexShader/DeleteVertexShader, ID3DXBuffer/D3DXAssembleShader, MessageBox and
__min/__max.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:31:57 +09:00
shenleiandClaude Opus 5.5 86e602cb32 port EterLib/GrpShadowTexture verbatim; D3D top-left fill rule for the shadow target (unit C/D)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:05:55 +09:00
shenleiandClaude Opus 5.5 5be37b6363 port EterLib LensFlare/ScreenFilter/Decal verbatim (unit C part 1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:02:40 +09:00
shenleiandClaude Opus 5.5 96ea03d0a0 port EterLib/GrpLightManager.cpp verbatim, initialise CLightManager (unit B)
Replaces the platform_stub skeleton with the 40250 source and mirrors
m_LightManager.Initialize() from 40250 PythonApplication.cpp:1263.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:59:31 +09:00
shenandshen 25dd65f2ce feat: complete native client rendering parity updates 2026-09-27 19:44:41 -07:00
shenandshen 8a759f5718 fix(port): preserve 64-bit quest image pointer in quest.GetQuestData 2026-09-24 01:20:04 -07:00
shenandshen a57c83dd71 Build self-contained macOS client and verify native beta path 2026-09-24 00:59:08 -07:00
shenandshen 330ec9745b port: verify root pack ledger and repair runtime adapters 2026-09-24 00:18:33 -07:00
shenandshen 3981cbe5e6 port: purge obsolete GDScript UI, legacy flows, and deprecated controllers
- Purged 66 obsolete GDScript UI components and mobile prototype UI from project/ui/ (retaining ui_assets.gd)
- Purged deprecated GDScript game scene, flow state machines, and local gameplay controllers (app_flow, game_scene, player_controller, net_world, etc.)
- Purged deprecated local system simulation scripts (consumable_system, chest_system, equip_rules, etc.) and project/fx/
- Purged legacy GDScript unit tests targeting obsolete classes
- Unified viewport back buffer sizing in CGraphicBase/CGraphicDevice/PythonBoot
- Cleaned up client_main.gd and python_host_check.gd for pure native port architecture
- Verified all port tests passing: port_map.py check (0 errors), port_gate.sh macos PASS (19/19 suites), python_game_render_test PASS
2026-09-23 22:48:41 -07:00
shenandshen 837c830182 port: complete 100% logic layer, eliminate pending dir, and unify client_main on port route
- Completed batch 4-f (Messenger, Guild, GuildMark), 4-g (PythonSystem, systemSetting), 4-h (PythonSoundManagerModule, MilesLib CSoundManager)
- Ported UserInterface/Locale.cpp, EterLocale/Japanese.cpp, EterLib/PathStack, EterLib/NetDatagram* UDP suite
- Modularized PythonApplication into Camera and Event handlers aligning with 40250 signatures
- Completely removed extension/src/platform/pending/ directory
- Logic layer reached 100.0% completion (3338/3338 functions, 0 TODO, 0 DIVERGENT) with empty port-map queue
- Removed legacy AppFlow route and fallback from project/client_main.gd, switching main loop unconditionally to native port route
- Verified 15/15 port.login_flow integration steps and 19/19 port_gate suites passing
2026-09-23 22:17:59 -07:00
shenlei ee7a9cd3e2 WIP port 4-d quest dialogue modules 2026-09-24 09:53:02 +09:00
shenleiandClaude Opus 5.5 a12e7fea42 Port route 4-c: NPC shop (PythonShop.cpp) + app cursor state
- UserInterface/PythonShop.cpp ported verbatim (shop module, initshop after initfly);
  pending stub and module stubs removed.
- 40250 PythonApplicationCursor.cpp and SetMouseHandler moved into the platform
  CPythonApplication on file-static members; GetCursorNum out of line, since uishop's
  app.GetCursor() dereferenced the missing application object.
- Fake server: general store (npclist 9003) answers CG_ON_CLICK with GC_SHOP START,
  CG_SHOP BUY/SELL2/END like CShop::Buy / CShopManager::Sell.
- port.login_flow step 10: click the shopkeeper, right-click buy, drag-sell, ESC close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 09:30:47 +09:00
shenleiandClaude Opus 5.5 6ea0fa9889 port 4-a: text input through CPythonIME (login typed, in-game chat)
- UserInterface/PythonIME(+Module) ported verbatim; ime module stubs removed, initime() after initdbg()
- EterLib/IME.cpp in platform/: 40250 buffer/WMChar bodies, IMM/TSF processors no-op; committed
  multi-byte text via PythonBoot::UIChar emulating GCS_RESULTSTR
- GameApplicationAdapter RunIME* -> CWindowManager; Godot keys -> ui_ime_key/ui_char
- port.login_flow/login_live type the account through the IME; chat CG_CHAT round-trip on the fake server
- python_game_render_test logs in with Godot key events

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 08:35:53 +09:00
shenleiandClaude Opus 5.5 2ead95756e port: CMapOutdoor + PythonBackground + minimap (1:1 40250)
GameLib map/area/terrain units, PRTerrainLib Terrain/TextureSet,
PythonBackground(+Module) and ColorTransitionHelper ported verbatim;
pending stand-ins and background module stubs removed. Hand edits:
BeginEnvironment's pointer tag via uintptr_t, LoadWaterMap reads the
file's 32-bit longs. Terrain draw passes stay platform no-ops (Godot
draws the terrain). RecordingDevice gains textures, buffers and render
targets; orthographic draws become UI commands so CPythonMiniMap's
masked tiles show through minimap_image_filter in python_ui_surface.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:50:09 +09:00
shenleiandClaude Opus 5.5 b69116992c port: EffectLib + EterBase/Utils platform bodies (1:1 40250)
EffectLib's 18 units are copied verbatim (Type.h: drop a comment backslash
that clang splices into the next enum line). The remaining Utils stubs get
the 40250 bodies, so .msf fly data resolve relative .mse attachments, and
CPythonResource registers mde/mdatr as 40250 does. login_flow spawns
level_up.mse and sees its particle draws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:19:30 +09:00
shenleiandClaude Opus 5.5 03de3f314a port: CPythonSkill + skill module + EterBase/Poly (1:1 40250)
Copy PythonSkill.cpp and the EterBase/Poly formula parser verbatim, drop the
pending stand-in and the skill module stub, register initskill() after
initfly() and build CPythonSkill in m_pySkill's place. LoadLocaleData now
loads skilldesc/skilltable. Skill and item icon handles go through
Py_BuildPointer/PyTuple_GetPointer (ILP32 ints truncate 64-bit pointers).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:07:15 +09:00
shenleiandClaude Opus 5.5 7358bf444a port: P3-e PythonMiniMap + miniMap module (1:1 40250)
Copy PythonMiniMap.cpp/PythonMiniMapModule.cpp and PRTerrainLib/StdAfx.cpp
verbatim, drop the pending stand-in and the miniMap module stub, register
initMiniMap() after initnet(). PR_FLOAT_TO_INTASM uses lrintf off MSVC;
D3DXColorModulate added. CMapOutdoor is not ported, so the pending
CMapManager::IsMapOutdoor() returns false (DIVERGENT) and the minimap's terrain
and atlas paths stay on 40250's no-outdoor-map branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 01:18:57 +09:00
shenleiandClaude Opus 5.5 070a27b2cb port: P3-d PythonTextTail + textTail module (1:1 40250)
Copy PythonTextTail.cpp/PythonTextTailModule.cpp verbatim, drop the pending
stand-in and the textTail module stub, register initTextTail() after
initChat() and call CPythonTextTail::Initialize() in Create as 40250 does.
Implement CScreen::ProjectPosition/UnprojectPosition (were stubs) with
D3DXVec3Project/Unproject, and ApplicationStringTable_GetString(DWORD) over
UserInterface.rc's English string table. port.login_flow projects the ground
item's name tail in an ALT frame and picks it back by screen position.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 01:10:41 +09:00
shenleiandClaude Opus 5.5 72b19b677d port: P3-c PythonExchange + exchange module (1:1 40250)
Copy PythonExchange.cpp/PythonExchangeModule.cpp verbatim, drop the pending
stand-in and the exchange module stub, register initTrade() after
initNonPlayer(). The fake server answers CG_EXCHANGE START with the partner's
item + gold and CANCEL with END; port.login_flow drives the exchange round-trip
through the Python exchange/net modules and uiexchange.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 00:59:05 +09:00
shenleiandClaude Opus 5.5 9298500df9 port: PythonItem + item module (batch 2 P3-b)
Verbatim 40250 CPythonItem and the item Python module replace the
pending stand-in and the module stub; CPythonApplication::Create calls
m_pyItem.Create() in 40250 order. itemGetIconImage returns its handle
through Py_BuildPointer (the ILP32 int truncated it and wndMgr.SetSlot
crashed on the live inventory). CMapManager::GetNormal evaluates
CTerrain::CalculateNormal on the native height tile; the item text-tail
members stay stubs, Pick answering -1 like an empty tail map.

The fake server drops vnum 19 next to the actor at entergame and answers
CG_ITEM_PICKUP with GC_ITEM_GROUND_DEL; login_flow picks it up through
player.PickCloseItem and checks item.SelectItem(19).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 00:50:16 +09:00
shenleiandClaude Opus 5.5 f0564a7f12 port: ItemData, ItemManager, PythonNonPlayer + LoadLocaleData (batch 2 P3-a)
Verbatim 40250 GameLib ItemData/ItemManager and UserInterface
PythonNonPlayer(+Module) replace their pending stand-ins and the
nonplayer module stub. LoadLocaleData's body moves into the platform
CPythonApplication stand-in, so the select phase loads item_proto and
mob_proto; CPythonSkill is still pending, so it returns false after the
tables load. login_flow checks item 19 (Sword+9) and mob 101 (Wild Dog),
offline and live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 00:36:10 +09:00
shenleiandClaude Opus 5.5 ce9f96398e port: ServerStateChecker + module (batch 2 P2)
Verbatim 40250 CServerStateChecker and the ServerStateChecker Python
module replace the stub; PythonBoot owns the instance like
CPythonApplication::m_kServerStateChecker. The fake server gets a state
port that answers CG_STATE_CHECKER the way CInputHandshake and
CInputDB::RespondChannelStatus do; login_flow requests the channel list
after the character list (live: {1: 1, 2: 1}).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 00:27:35 +09:00
shenleiandClaude Opus 5.5 9dcf34dffc port: FlyingData/Instance/ObjectManager/FlyTrace + effect/fly modules (batch 2 P1)
Verbatim copies of the 40250 flying-object units and the effect/fly
Python modules replace the pending CFlyingManager stand-in and the two
module stubs; initeffect/initfly run after initnet as in 40250 and the
flying manager gets the background as its map manager.
CMapManager::GetTerrainHeight is added over the native height tiles.
login_flow checks playersettingmodule registered the indexed fly data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 00:12:19 +09:00
shenleiandClaude Opus 5.5 ff0983d3c8 2V3-a: walk with the keyboard through the ported player chain
PythonPlayer, PythonPlayerInput{,Keyboard,Mouse}, PythonPlayerEventHandler,
PythonPlayerSkill, PythonPlayerModule and GameType are verbatim copies; the
`player` stub module and the pending PythonPlayer/GameType stand-ins are gone.
Unported callees (CPythonSkill, CItemData, CItemManager, CPythonItem, ...) are
pending stubs. 64-bit fixes: emotion icon handles use Py_BuildPointer, and
PyDict_Next takes Py_ssize_t.

The actor did not move because GrannyUpdateModelMatrix passed the model matrix
through. Walk/run motions use constant root-motion extraction
(AccumulationFlags=AccumulationExtracted, LoopTranslation e.g. (0,-300,0) for
the warrior run, same as the .msa Accumulation). libgr2 now reads both fields
from TrackGroups[0], and the runtime moves by LoopTranslation over each
control's local-clock span, blended by control weight. VDA extraction is not
implemented.

port.login_flow presses DIK_UP; the actor walks more than 100 cm, and the fake
server parses CG packets and sees CG_MOVE FUNC_MOVE, then FUNC_WAIT at the new
position. port.login_live against the real server walked 132 cm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 23:41:31 +09:00
shenlei 702fef7b47 2V2-e.5a: restore 40250 min-max helpers for camera update 2026-09-23 22:05:24 +09:00
shenleiandClaude Opus 5.5 1fe8a4b643 2V2-e.2: Godot consumer of the 3D draw commands, offline screenshot
python_3d_surface.gd turns RenderGame's recorded draws into meshes under a
camera read back from SetPerspective; textures come from the 40250 packs.
GetFarClip and the CMapManager ctor ported verbatim. Until the environment
is ported, lit draws with no light/ambient are shown unshaded (stand-in).
script/python_game_render_test.sh runs system.py login -> select -> game
against port_fake_login_server (or --live via MT_LIVE_*) and screenshots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 20:35:36 +09:00
shenleiandClaude Opus 5.5 5bfa13c5cc 2V2-e.1: 3D draw-command channel — recording D3D8 device, StateManager, GrpBase, camera
EterLib/StateManager.cpp and GrpBase.cpp ported verbatim. CGraphicDevice::Create builds a platform
IDirect3DDevice8 that keeps the device state and records every Draw* call as a Render3DDraw
(vertices decoded by FVF, strips/fans expanded, textures, world/view/proj, blend/depth/light state).
The 40250 camera (__UpdateCamera, SetCenterPosition, ...) and the Process order
(__UpdateCamera -> OnCameraUpdate -> OnUIUpdate -> Begin/SetInterfaceRenderState/OnUIRender/End)
are in place; CScreen Begin/End, CPythonGraphic render states and CCullingManager::Process matrix
updates are verbatim. port.login_flow asserts a textured, lit character draw under the RH
perspective with every vertex on screen; offline and live pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 20:15:54 +09:00
shenleiandClaude Opus 5.5 668f48d6ec port 2V2-d.2: Granny runtime on libgr2, main character model animates
Implement the Granny SDK 2.11 API the client uses on top of libgr2
(platform/EterGrnLib/GrannyRuntime.cpp, shim granny.h declared from the
SDK header): file sections, type-definition vertex conversion, material
textures by Usage, mesh/bone bindings, deformer, control clock/loop/ease
and weighted SRT sampling. Port EterGrnLib (LODController, Material, Mesh,
Model, ModelInstance*, Motion, Thing, ThingInstance, Util) plus EterLib
GrpObjectInstance/GrpCollisionObject/CollisionData verbatim and drop their
platform skeletons and pending stand-ins; register the gr2 resource
factory; vertex/index buffers are CPU-side until the 2V2-e render adapter.

app.UpdateGame/RenderGame now run 40250's bodies, reaching the
CPythonApplication members through their singletons (the platform has no
app object); CPythonGraphic joins GameSingletons in member order, and
GetMousePosition reads the host cursor.

port.login_flow asserts the main instance's PART_MAIN model has meshes,
its diffuse image loaded and the WAIT motion moves the bones between
frames; offline and live pass, port_gate macos PASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:43:27 +09:00
shenleiandClaude Opus 5.5 5266b00c6e port 2V2-d.1: ActorInstance/InstanceBase closure creates the main character
Port the ActorInstance*/InstanceBase* siblings plus GameUtil, FlyTarget,
PhysicsObject, GameEventManager, WeaponTrace, MapUtil and lineintersect_utils
verbatim and drop their pending stand-ins; CGameEventManager and CPythonSystem
join PythonBoot in CPythonApplication member order.

Root cause of the intermittent Loading-phase header 7: TPlayerSkill::tNextRead
is time_t, 32-bit in 40250 (_USE_32BIT_TIME_T) but 64-bit on LP64, so
SKILL_LEVEL (76) was read as 2551 bytes instead of 1531. Packet.h now uses
LONG with a static_assert, and the fake server sends SKILL_LEVEL in Loading.

The fake server's CHARACTER_ADD now uses CHAR_TYPE_PC; port.login_flow
asserts the main instance exists with race 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:02:21 +09:00
shenleiandClaude Opus 5.5 996d793f0c port 2V2-c: chrmgr/chr modules + race registration chain
PythonCharacterManagerModule/PythonCharacterModule ported verbatim; the
2V0 chr/chrmgr stubs are gone and initchr/initchrmgr run in 40250 order.
The registration chain they need (RaceData/RaceDataFile/RaceManager/
RaceMotionData, GameType, AttributeData/AttributeInstance, TextFileLoader,
Util, Camera/CameraProcedure) is ported; CRaceManager is created in
PythonBoot. port.login_flow asserts race 0 has its wait motions and no
unhandled packet header; port.login_live 8/8 against 192.168.21.203.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 18:40:47 +09:00
shenleiandClaude Opus 5.5 62b6e23bfc port 2V2-b: GamePhase dispatch consumes the Entergame burst
PythonNetworkStreamPhaseGame/PhaseGameActor/PhaseGameItem/Command,
NetworkActorManager and PythonChat/PythonChatModule are ported verbatim and
dispatched at runtime; the 2V0 chat stub module is removed and initChat()
runs before initnet() as in 40250. InstanceBase, PythonCharacterManager and
GameLib ActorInstance/RaceData/RaceManager compile but stay TODO until
2V2-c/d wire them.

Units not ported yet get their singletons from PythonBoot's GameSingletons
(CPythonApplication member order) and platform/pending stand-ins generated
by platform_stub.py pending; const char* stand-ins return "".

port.login_flow's fake server now sends the CInputLogin::Entergame order
(actor insert, NPC positions, PHASE_GAME, land list, time, channel, greet
notice, ping) and a TraceError observer asserts no unknown packet header.
port.login_live passes against the real server for 10 s of game phase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 18:20:57 +09:00
shenleiandClaude Opus 5.5 d16fabf61c 2V2-a: game.GameWindow opens after Loading and sends CG_ENTERGAME
The 2V0 stub modules now carry the 40250 module constants (copied from each
module's init function by stub_constants.py) and return zero values shaped like
each reference function's Py_BuildValue, so interfaceModule.MakeInterface runs
through (uiSafebox no longer divides by a zero SAFEBOX_SLOT_Y_COUNT).

UserInterface/StdAfx.h includes Locale.h before GameType.h as the 40250 PCH
does; the reversed order dropped GameType.h's ENABLE_NEW_EQUIPMENT_SYSTEM
branches.

port.login_flow's fake server checks CG_ENTERGAME; port.login_live reaches the
GameWindow on 192.168.21.203.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 16:56:23 +09:00
shenleiandClaude Opus 5.5 2a8750e736 2V1-e: live login smoke harness (port.login_live)
port_login_flow_test gains a `live` mode that runs the same script path
against a real 40250 server and checks the client's own state: the
character list, then LoadingWindow.LoadData from GC_MAIN_CHARACTER (which
CPythonNetworkStream answers with CG_CLIENT_VERSION), exiting before the
game phase. Host, ports, account and slot come only from MT_LIVE_* env
vars, are handed to Python as objects and never printed; without them
the test skips. Not yet run live: the server was unreachable today.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:26:56 +09:00
shenleiandClaude Opus 5.5 8d9d863c7e 2V1-d: offline login -> select -> loading against a fake 40250 server
port.login_flow drives the real 40250 root scripts through the ported
CPythonNetworkStream and CAccountConnector against a loopback auth + game
server built from net/classic (wire layouts, sequence table, cipher) that
answers like the 40250 desc.cpp/input*.cpp: handshake, key agreement,
LOGIN3/AUTH_SUCCESS, LOGIN2, the character list, DirectEnter reconnect,
CHARACTER_SELECT, the loading packets and CLIENT_VERSION, with every
sequence byte checked.

- NetStream::ActivateCipher decrypts ciphertext already buffered behind
  KEY_AGREEMENT_COMPLETED (PORT)
- CPythonApplication is final (PORT): no application object exists on the
  platform yet, so its virtual overrides must be called directly
- app.GetTime (GetGlobalTime) and camera/center-position stubs
- SendClientVersionPacket verbatim in the PhaseGame stand-in

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:20:32 +09:00
shenleiandClaude Opus 5.5 4d9b800efb 2V1-b/c: PythonNetworkStream phases, AccountConnector and the net module
Port PythonNetworkStream with its HandShake/Login/Select/Loading/Offline
phases, AccountConnector and PythonNetworkStreamModule verbatim; the net
stub goes. PythonBoot creates the network stream, account connector,
player, flying manager and effect manager like CPythonApplication, and
app.Create/Process drive CNetworkDevice and both connectors.

Packet.h long fields become 32-bit LONG; port.packet checks 38
login/select/loading packet sizes against wire_classic.h. Unported units
in the link closure live under platform/pending/ as stand-ins. The macOS
gate now builds all and finds iconv.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:02:14 +09:00
shenleiandClaude Opus 5.5 cd3b8b506f 2V1-a: port the EterLib network layer and the Crypto++ packet cipher
NetStream/NetAddress/NetDevice/NetPacketHeaderMap and EterBase/cipher.cpp
are mechanical copies. The winsock shim maps Winsock onto BSD sockets and
keeps the Winsock semantics CNetworkStream relies on: select ignores nfds,
a socket whose connect failed is not writable (40250 times out instead),
EINPROGRESS reads as WSAEWOULDBLOCK, and SIGPIPE is ignored.

port.net covers loopback connect, send/recv, peer close, the refused
connect timeout and the client/server key agreement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:27:57 +09:00
shenleiandClaude Opus 5.5 afe63bfa61 2V0-g: port the .fnt font pipeline over a FreeType GDI emulation
CGraphicText, CGraphicFontTexture and CGraphicDib are the 40250 bodies
verbatim; CGraphicTextInstance is verbatim except that its D3D draws become
UI render commands (one image quad per glyph, Bar for cursor/underline).

- platform/Win32Gdi.cpp: the GDI subset those files call, over vendored
  FreeType 2.13.3, following GDI's LOGFONT cell height, win metrics and gasp
  rules; system font lookup with substitute and CJK fallback faces
- Win32Crt: MultiByteToWideChar / WideCharToMultiByte (UTF-8 and 1252 by
  hand, other code pages through iconv)
- CGraphicImageTexture memory textures: glyph pages reach Godot as
  "mem:<id>@<revision>"; Metin2PythonHost.memory_texture + Canvas cache
- Util.cpp code page / font face table, SetDefaultCodePage at boot,
  DefaultFont_* block, fnt resource type, GetMaxTextureWidth/Height
- TextTag, StringCodec, Arabic, Vietnamese copied from 40250
- tests: port.text (Tahoma 12 metrics, alignment, CP949), port.app_loop
  and python_host_test.gd now check glyph quads instead of text commands

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:17:25 +09:00
shenleiandClaude Opus 5.5 141206cb69 2V0-f: run the real system.py app loop in Godot
- system.py runs app.Loop() on the script fiber; each UIUpdate is one
  CPythonApplication::Process(). Logo -> Login, popup ESC/click and
  app.Exit teardown (launcher cleared first, as in 40250 Main) work.
- Image commands are base-texture quads with UVs (a .sub shares its parent
  texture); ImageInstance/ExpandedImageInstance OnRender and SetRenderingRect
  ported verbatim, so scale/rotation/rendering rect are drawn.
- CGraphicBase::GetColor / grp.GenerateColor ported (ThinBoard background).
- port.app_loop test, python_host_test app-loop checks, MT_TEST_MODE=python_ui.
- TODO: .fnt/CGraphicText font pipeline, ExpandedImage blend modes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 13:38:13 +09:00
shenandshen b221a9eaf5 Port 2V0 UI Python bindings and app module link surface 2026-09-22 19:57:35 -07:00
shenandshen a0ad587f78 port(2V0-b): verify window tree and fix 64-bit LZO lengths 2026-09-22 19:18:11 -07:00
shenleiandClaude Code b4c9d6cefc port(2V0-b): EterPythonLib 窗口树实现 + EterLib 资源层
- port: PythonWindow/PythonSlotWindow/PythonGridSlotWindow/PythonWindowManager(布局/命中/事件/插槽渲染)
- port: EterLib ReferenceObject/Resource/ResourceManager(资源引用与查找)
- platform: EterLib Util、EterPythonLib PythonGraphic
- tests: port.window_tree(需要解释器,不需要 40250 Client/pack)
- 顺带补上 4 个缺失的 Godot .uid

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 11:09:05 +09:00
shenleiandClaude Opus 5 369a80fc10 port(2V0-a): EterPythonLib 窗口系统的头进镜像
2V0 的入口实测:audit/slices/2V0.json 的 212 个头里 164 个已经在镜像中,缺 48 个
(1 个 EterLib、5 个 EterPythonLib、42 个 UserInterface);10 个单元里已移植 2 个。
本轮补 EterPythonLib 这 5 个,外加必须先有的 EterPythonLib/StdAfx.h —— port_header_gate
按 40250 的做法把每个头放在所属库的 StdAfx.h 后面编译,没有它这五个既看不到
<Python.h> 也看不到 STL 和 CSingleton。

6 个文件全是 port_copy.py 的机械拷贝,0 处手改。

顺带修正清单的一处误报:EterLib/Dimm.h 不是 40250 的源文件,是 Windows SDK <dimm.h>
的 MIDL 产物,port/common/shim/win32/Dimm.h 已经顶掉了;镜像一份反而遮住 shim,
EterLib/IME.h 的 #include "Dimm.h" 会去找 rpc.h。拷进来验证后删掉。

只有头,没有 .cpp,所以没有 port-map 条目 —— 只有声明,没有可调用的东西。
port_header_gate 新增 6 个 TU 全绿;ctest 27/27。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 10:50:24 +09:00