- 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>
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>
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>
The network stream phases, AccountConnector, NetStream/NetDevice/
NetAddress, EterPack*, lzo/tea/cipher/Timer and friends were copied in
2V1/2A but never marked. port_copy diff: 23 exact mechanical copies,
5 with // PORT: edits only; no platform stand-ins. Logic layer 67.9%.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CScreen::SetCursorPosition and CPythonGraphic::SetCursorPosition are the 40250
bodies, so RenderGame builds the pick ray under the cursor each frame.
CPythonBackground::GetPickingPoint* march that ray as
CMapOutdoor::__PickTerrainHeight does, against the native CMapManager height
(PR_FLOAT_TO_INT's x87 rounding becomes floor); object picking waits for
CMapOutdoor. CMapManager::isAttrOn reads the packed <map>/<xxxyyy>/attr.atr
as CMapOutdoor::isAttrOn + CTerrain::isAttrOn do, and CheckAdvancing with its
collision checkers is verbatim (no map objects are registered yet). All of
this stays in the pending/platform layer and is marked ADAPTED.
port.login_flow clicks the ground below the actor after the key walk. The
actor walks to the picked point (334 cm offline), and the fake server sees
FUNC_MOVE, then FUNC_WAIT. It also checks that the actor's cell is free and
that its terrain block has blocked cells. port.login_live against the real
server passed (key 133 cm, click 296 cm), and python_game_render_test.sh
passes offline. MT_TEST_MODE=python_ui now adds the 3D surface, so the port
route can be played by hand.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>