Commit Graph
100 Commits
Author SHA1 Message Date
shenleiandClaude Opus 5.5 f96b339309 audit: EterBase/error.cpp N_A (Win32 SEH crash log)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:43:38 +09:00
shenleiandClaude Opus 5.5 bda85eea50 port: grp.SaveScreenShot via next-frame swapchain readback + JPEG
CPythonGraphic::SaveScreenShot queues a readback of the next presented
frame (ScreenShotHost -> VulkanWindow::request_frame); WriteScreenShot runs
the rest of 40250's function verbatim (X8R8G8B8 rows, SaveJPEG, EXIF tag).
jpeg_save is encoded with stb_image_write. SHGetSpecialFolderPath returns
$HOME/Documents (else cwd); CreateDirectory/_access/jpeg_save accept '\\'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:43:03 +09:00
shenleiandClaude Opus 5.5 c21e012965 Port map: correct the WebPage/Logo/MovieMan evidence (scripts grepped with LC_ALL=C)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:32:49 +09:00
shenleiandClaude Opus 5.5 ff71726ff0 Port PythonExceptionSender and install it at boot as 40250 Main does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:31:04 +09:00
shenleiandClaude Opus 5.5 3dfb09df92 Port map: mark the platform units the 40250 SINGAPORE build never reaches N_A
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:27:25 +09:00
shenleiandClaude Opus 5.5 549e12db7c Mark GrpDIB, GrpText, CullingManager and FileLoader PORTED; test the text file loader
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:25:28 +09:00
shenleiandClaude Opus 5.5 3c2ef81536 SphereLib: mark the verbatim sphere tree PORTED with a query test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:24:24 +09:00
shenleiandClaude Opus 5.5 ed61b2d20f SpeedTree: read the .spt collision and composite texcoord blocks
The CSpeedTreeRT stand-in now returns the collision objects stored in
the .spt (12000 section: spheres and cylinders) instead of one fixed trunk
cylinder, and takes leaf texture rects from the 10000 section instead of
hand-picked atlas rects (trees without leaf maps use the frond rect).
SpeedGrass/BoundaryShapeManager are N_A (no 40250 caller).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:20:34 +09:00
shenleiandClaude Opus 5.5 17cb7326c1 docs: PORT-PLAN MilesLib done, platform 61.2%
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:07:51 +09:00
shenleiandClaude Opus 5.5 11991d4d1f MilesLib: run the 40250 sound sources verbatim over an AIL software mixer
Copy SoundBase/SoundData/SoundInstance*/SoundManager*/Type from 40250 and
implement the AIL_* calls they make in MilesAil.cpp (2D pan, 3D distance and
listener pan, threaded stream decode, loop counts). The SDL host drains the
mixer. CSoundManager is created/updated/destroyed where 40250 does it and the
old AudioCommands bridge is removed. Port-map MilesLib 142/142 PORTED.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:07:37 +09:00
shenleiandClaude Opus 5.5 d509f0a8b4 PORT-PLAN §4: performance batch 2 status
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:43:00 +09:00
shenleiandClaude Opus 5.5 e4331bca3e gr2: binary-search the curve knot (upper_bound) when knots are ascending
Curve::eval scanned every knot to find the first one past t; long animation
tracks made that the top of CPythonCharacterManager::Deform. Knots are checked
for ascending order at load and unsorted curves keep the linear scan, so the
chosen knot is unchanged. Desktop live game: Deform samples 93 -> 58.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:42:31 +09:00
shenleiandClaude Opus 5.5 6bfcac7d68 RecordingDevice: lend cached geometry instead of copying it per draw
A geometry-cache hit moved every vertex vector out of the cache into the draw
(deep copy of positions/normals/uv/diffuse/indices/bones each frame). The cache
now lends its vectors to the frame's first draw of that geometry and takes them
back in Render3DBeginFrame; later draws of the same key+revision in the frame
(terrain splat layers, shadow-map pass) are marked shared_geometry and carry no
vectors -- the native host looks the GPU geometry up by key+revision, and draw
captures expand them (Render3DExpandSharedGeometry). Index reads reuse a scratch
buffer. Desktop live game: RenderGame rnd 1.7 -> 1.2 ms, no visual change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:39:01 +09:00
shenleiandClaude Opus 5.5 44a020f01e native renderer: game world at MT_RENDER_SCALE (0.75 on Android), MSAA default 2
Draws recorded inside CPythonApplication::RenderGame are marked Render3DDraw::scene and
drawn by a scene pass compatible with pass_ into a reduced-resolution image, composited
where RenderGame drew; the UI stays full resolution. --render-scale / MT_RENDER_SCALE,
desktop default 1.0 (unchanged path).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:28:05 +09:00
shenleiandClaude Opus 5.5 b7c215ee42 zh locale: translate all 40250 itemdesc descriptions, wrapped for the tooltip
itemdesc_translate_zh.tsv maps the English description/summary text to Chinese (1,788 entries,
every itemdesc row covered). build_zh_locale.py replaces the cells and wraps Chinese into
26-byte lines joined by ' |', which 40250's Western SplitDescription turns into forced line
breaks; the 50307 overlay row is wrapped the same way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:17:21 +09:00
shenleiandClaude Opus 5.5 3fcb27dd4d Server: hunt set once per character, rebuild.sh for patch build/deploy/rollback
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:01:36 +09:00
shenleiandClaude Opus 5.5 d163aab949 hunt-set: 小狩猎套装礼包 is free in the item mall
CShopEx::Buy rejected price 0 as a hack; allow it like CShop::Buy already does.
Rebuilt and deployed game on 203; buying the box for 0 verified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:30:46 +09:00
shenleiandClaude Opus 5.5 7155785167 Add 小狩猎套装礼包: level-1 +9 set with full attributes, sold in the item mall
Server (tools/server/hunt-set, deployed on 203): game patch adds quest function
item.set_attribute (CItem::SetForceAttribute); quest hunt_set turns the unused
ITEM_QUEST 50307 into a per-class box of eight +9 pieces with five max-value
attributes each. Item mall sells it for 2,000,000.

Client locale: name overlay plus whole-row overlays for item_list.txt (gift-box
icon) and itemdesc.txt (build_zh_locale.py ROW_FILES).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:23:33 +09:00
shenleiandClaude Opus 5.5 20b189a9da client: the player's own character walks through buildings and blocked cells
The server checks a move only for its distance and speed, so the local
character skips the background-object and map-attribute collision.
Other characters and doors still block it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:42:10 +09:00
shenleiandClaude Opus 5.5 34c6049199 zh locale: translate skill names and descriptions
skilldesc.txt takes Longju's name, description and condition columns
and its affect texts where their format arguments match 40250's; a
reviewed overlay fills the gaps and renames the empire languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:56:03 +09:00
shenleiandClaude Opus 5.5 f8bbfc7fb3 server: support skills at max level on a character's first login
support_skills_max.quest sets 121/122/124/126-129/131 to their skill_proto
max, the horse to level 30 (skill 130) and the horse skills 137-139 (140 for
assassins), once per character. install.sh adds it to locale_list and
pc.set_skill_level to quest_functions (qc rejects it otherwise), then make.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:45:58 +09:00
shenleiandClaude Opus 5.5 42e4cf1a9f server: unlimited teleport ring 70058, sold in a two-page item mall
ring-warp/: ring_warp.quest without use count or cooldown (the ring is never
used up) + install.sh (GBK, make.py, item name 移动戒指).
npc-shops: [page] lines in items.tsv make an extended shop written to
shop_table_ex.txt; item-mall is now 增益 (29) + 道具 (12, incl. 70058 at 1 gold).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:18:56 +09:00
shenleiandClaude Opus 5.5 000d4841fd quest zh: translate the inline quest text (change_name, item_delete, manwoo, forked_road, ...)
128 literals written directly in the quest sources, outside gameforge.*;
build_zh_quest_inline.py patches them in GBK before make.py (qc) on the server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:32:33 +09:00
shenleiandClaude Opus 5.5 808e711f74 quest zh: translate the remaining translate.lua strings (chunks 57-72: pony, heavens cave, reset scrolls, ride, skill groups, spider dungeon, subquests, grand master training, mount training, refine scrolls, warehouse, olympic badge)
All 8477 gameforge strings now have a Chinese row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:06:14 +09:00
shenleiandClaude Opus 5.5 5440045f1e quest zh: translate chunks 47-56 (map_warp, marriage, side quests lv7-lv80, npc_talk, oxevent, patrol, pets, pony)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:51:02 +09:00
shenleiandClaude Opus 5.5 2217205ad4 quest zh: translate chunks 41-46 (Dark Dragon Rock main quests lv84-lv98, map_warp)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:57:41 +09:00
shenleiandClaude Opus 5.5 2578e1b150 quest zh: translate chunks 37-40 (main quests lv40-lv84, blacksmith/fisherman)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:34:01 +09:00
shenleiandClaude Opus 5.5 ca7b47c4f0 quest zh: translate chunks 31-36 (stash, new year, flame main quest, early main quests)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:27:41 +09:00
shenleiandClaude Opus 5.5 85cd541560 quest zh: translate chunks 25-30 (old pirate, questscroll, quiz, skill groups); keep [TAG] whole when wrapping
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:19:29 +09:00
shenleiandClaude Opus 5.5 69d214ba20 quest zh: translate chunks 11-24 of translate.lua (3056/8477 strings)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:11:06 +09:00
shenleiandClaude Opus 5.5 c5ace7b848 quest zh: translate chunks 5-10 (1425 of 8477 strings)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:00:41 +09:00
shenleiandClaude Opus 5.5 f4995b9a73 zh quest text: biologist and Seon-Pyeong quests, couple ring, catacomb entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:53:19 +09:00
shenleiandClaude Opus 5.5 671155eecc zh quests: translate.lua builder + first 100 quest strings
40250 quests say gameforge.<quest>.<key>, loaded by game from
share/locale/<locale>/translate.lua at start. build_zh_translate_lua.py
lays the reviewed data/zh_40250/quest_translate_zh.tsv over the English
file line by line (nested tables kept), re-wraps at the quest window
width, and writes GBK with 0x5C trail bytes doubled. Deployed on 203;
blacksmith dialog shows Chinese.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:46:52 +09:00
shenleiandClaude Opus 5.5 3ae77c3530 zh locale: take ui/windows images from Longju
The character window's tabs and stat labels (VIT/INT/Character Status,
Status/Abilities/...) are baked into locale/<xx>/ui/windows/windows.dds;
the zh build only overlaid text keys, so they stayed English. The folder
is now replaced as a whole (its .sub files index its own atlas).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:38:37 +09:00
shenleiandClaude Opus 5.5 54fa2c0fc3 npc-shops: generic NPC shop installer + mount shop 15 on NPC 20368
tools/server/item-mall-shop becomes tools/server/npc-shops with one
directory per shop (shop.conf + items.tsv) and install.sh <shop dir>.
New mount shop: 35 ride tickets on NPC 20368 (renamed 坐骑商人 via
NPC_NAME -> mob_names.txt) beside the stable boy in a1/b1/c1. Verified
on 203: 35 slots at the drafted prices, bought + used 71114 -> mounted.
zh overlay: 71118 虎坐骑券(黄), 20368 坐骑商人.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:38:37 +09:00
shenleiandClaude Opus 5.5 4bfc4244bd 商城按钮改为提示去找百店老板娘
203 没有网页商城,端口也没有网页窗口,系统菜单的商城按钮打开的是空窗口。
新 PORT 模块 mt_mallhint 替换 SystemDialog 的商城按钮和 GameWindow 的 mall 命令处理,
弹出提示框(并在聊天栏提示):商城物品请到各村杂货店旁的百店老板娘处购买。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:17:28 +09:00
shenleiandClaude Opus 5.5 cc18db5dd1 商城 NPC 商店:9010 百店老板娘在三个村卖商城物品(服务端安装脚本)
203 没有网页商城,系统菜单的商城窗口是空的。把 40 件商城物品放进商店 14,
挂在 a1/b1/c1 杂货店旁的 NPC 9010 上,按 item_proto gold 金币出售(红龙/蓝龙 1 金币)。
9010 的 mob_proto on_click 原为 2(无处理),改为 1(ON_CLICK_SHOP)才能打开商店。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:37:15 +09:00
shenleiandClaude Opus 5.5 71d8f8c6e7 移动端界面大小设置:默认 600 逻辑高,系统选项可选 600/700/800
Android 上 40250 界面原先固定按 800 逻辑像素高排版,弹窗文字在手机上只有约 1 mm 高。
- UIScaleMode.h + host ui_scale.cpp:逻辑高度来自保存的设置(默认 600),ui_height.cfg 保存,下次启动生效;
  桌面可用 MT_UI_HEIGHT 测试
- app.GetUIHeight/GetAppliedUIHeight/SetUIHeight
- mt_uiscale PORT 模块:系统选项对话框加高一行,"界面大小 大/中/小",修改后聊天提示重启生效

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:10:51 +09:00
shenleiandClaude Opus 5.5 e33e41c12b 背包扩展到 5 页:服务端补丁 + DB 迁移 + 客户端 mt_inventory
- GameType.h: c_Inventory_Page_Count 2 -> 5; SQuickSlot.Position BYTE -> WORD
- quickslot 包/接口 pos 改为 WORD(CG/GC 5 字节),wire_classic 同步
- mt_inventory PORT 模块:inventorywindow.py 装备格 90 -> EQUIPMENT_SLOT_START 重映射、5 个小页签、
  自动药水高亮与 SelectItemWindow 扫描全部 5 页;40250 脚本保持不变
- tools/server/inventory-5-pages: server.patch(格子布局 +135、quickslot WORD)、migrate_db.py、README

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 22:37:44 +09:00
shenleiandClaude Opus 5.5 22d534c5eb Split vulkan_window.cpp by responsibility and render() into phases
VulkanWindow's 3000-line TU becomes sdl_window.cpp (window, events,
cursor, screenshot BMP), vk_device.cpp (device, swapchain, MSAA,
framebuffers), vk_pipelines.cpp (render passes, pipelines),
vk_resources.cpp (buffers, render targets, geometry), vk_textures.cpp
(textures, samplers, descriptors), vk_frame.cpp (render) and
ui_batches.cpp; vulkan_window.cpp keeps construction and timing stats.
Function bodies move verbatim.

render() now reads fence/acquire -> prepare_draws -> prepare_ui ->
write_draw_states -> record_passes -> record_readbacks -> submit ->
finish_readbacks -> present, with FrameDraws / Readback carrying the
locals that used to live across 500 lines.

Verified: login-screen screenshot byte-identical to HEAD; game-world
draw/vertex/index/UI counts identical; ctest, port_gate macos+android,
Android build pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:54:36 +09:00
shenleiandClaude Opus 5.5 eab5938072 host: cross-platform audio decode (Android has sound)
Replace the macOS-only AudioToolbox decoder with mt_host::decode_audio: a
RIFF/WAVE PCM parser plus vendored dr_mp3, resampled/remixed to 44.1 kHz
stereo float with SDL_ConvertAudioSamples. macOS and Android now share one
path; the AudioToolbox link is gone.

BGM is no longer cached in clips_ (a 5-minute track is ~100 MB of float):
only the playing track is kept, and a new one decodes on a worker thread
(the pack read stays on the main thread) so map changes do not stall.

host.audio_decode test: synthetic wav layouts + all 1578 pack .wav, 9 pack
.mp3 and 25 Client/BGM .mp3 decode (7060 s of audio in ~3.6 s on M2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:22:11 +09:00
shenleiandClaude Opus 5.5 75d2dd8545 host: split src/host/main.cpp into translation units
main.cpp (4.5k lines) -> main.cpp (entry, args, synthetic benchmark) plus
vulkan_window, live_client, frame_policy, native_audio, texture_decode,
render_state, input_keymap, host_util. Bodies are moved verbatim; multi-line
VulkanWindow / NativeAudioEngine / FrameRatePolicy members are defined out of
line; one-line accessors stay inline. Anonymous namespace -> mt_host.

No behavior change: ctest 15/15, port_gate macos+android PASS, desktop
--live-client login screen and synthetic --draws runs unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:30:44 +09:00
shenleiandClaude Opus 5.5 a46093104c layout: restructure into src/ tests/ android/ scripts/ tools/
- extension/src/{port,platform,codepage} -> src/; native_render -> src/host
  (+ dxt, shaders/); libgr2 -> src/gr2; extension/third_party -> third_party
- extension/tests -> tests/port, libgr2/tests -> tests/gr2
- android-native -> android (build.sh, push-client.sh moved in)
- script -> scripts; tools/40250 -> tools/server; oracle -> tools/granny-oracle;
  perf tools -> tools/perf
- all build trees under build/ (native, release, android, port-gate)
- xrender:: CMake aliases -> mt::; port-map ledger impl paths rewritten

No code changes. ctest 15/15, port_gate macos+android PASS, port_map check 0 errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:08:19 +09:00
shenleiandClaude Opus 5.5 70710477cf cleanup: remove Godot-era test data, formats/, dead proto reader and duplicates
- test/: bgfx/Godot render goldens and compare shots nothing reads any more;
  the Granny oracle result m2-numeric.json moves to oracle/
- formats/: only the .spt sniffer was still linked; it moves into
  platform/SpeedTreeLib, the rest and tools/map_probe go
- bgm/ duplicated Client/BGM byte for byte; tools/root archived root scripts
  that root.epk already holds; extension/src/proto had no build reference
- GEMINI.md duplicated AGENTS.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:43:19 +09:00
shenleiandClaude Opus 5.5 0137f852d3 docs: rewrite PORT-PLAN for the native SDL3 architecture
Godot-era batch records move verbatim to docs/archive/PORT-HISTORY.md.
README and THIRD-PARTY no longer mention submodules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:26:54 +09:00
shenleiandClaude Opus 5.5 f970f95800 cleanup: drop Godot-era build trees, m2dev net/pack layers and stale docs
- Untrack build-debug/ and build-asan/ (CMake trees committed by mistake in
  c9389431) and ignore them.
- Remove extension/src/net and extension/src/pack (m2dev protocol and XChaCha
  pack format, superseded by the ported 40250 code), their 18 unregistered tests
  and the net/pack tools, the MT_BUILD_NET_TOOLS probe, and the libsodium and zstd
  submodules they alone used.
- The fake login server's classic cipher, sequence table and wire layouts move to
  extension/tests/classic/ (still used by port.login_flow, port.packet and the
  native client's offline mode).
- Archive Godot/m2dev-era plans under docs/archive/; THIRD-PARTY.md updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:17:25 +09:00
shenleiandClaude Opus 5.5 82503315c6 native: frame-rate setting, idle frame rate and battery power telemetry
- MtFrameRate setting (30 / 60 default / display max) as app.Get/SetFrameRateMode,
  with a "画面帧率" row injected into the system option dialog (mt_framerate); saved
  in the SDL pref path.
- FrameRatePolicy in the live loop: 30 fps after 15 s without input (not while auto
  hunting), display switched to 60 Hz unless the highest mode, ADPF
  setPreferPowerEfficiency, vsync pacing when the display already runs at the target.
  --fps-mode / --idle-fps / --idle-after; --fps-cap / --refresh-rate still pin a test run.
- Perf log: battery current/voltage/power, plugged, fps_mode, idle columns;
  perf_summary groups power by mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:14:19 +09:00
shenleiandClaude Opus 5.5 c2cc093ed0 native: perf telemetry, 2 frames in flight, 120 Hz pacing, GPU shadow map
- --perf-log CSV + logcat telemetry (perf_log.h, EterBase/PerfCounters.h),
  incl. display refresh rate / app vsync rate, thermal, CPU clocks;
  tools/pull_perf_logs.sh + tools/perf_summary.py
- Vulkan renderer: two frames in flight, in-frame texture uploads (no
  vkQueueWaitIdle), --fps-cap / --refresh-rate / --frames-in-flight
- Android: ANativeWindow_setFrameRate, ADPF performance hint,
  appCategory=game (ColorOS no longer drops to 60 Hz when idle)
- Character shadow map rendered on the GPU into an offscreen render target
  instead of CPU rasterization + per-frame 1 MB upload; --cpu-shadow keeps
  the old path. Device (120 Hz, 32 mobs): 75 -> ~115 fps, script thread
  8.9 -> 3.4 ms. draw_capture format v10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 17:59:23 +09:00
shenleiandClaude Opus 5.5 3e3708ef06 android-native: auto hunt, in-client account registration, mobile UI polish
- Auto hunt (client-only): PythonPlayerAutoHunt.cpp + AutoHuntScript.inc as the
  embedded mt_autohunt module, AUTO touch button, F9/F8.
- Account registration: tools/40250/register_server.py (rc.d mt_register, :11080)
  inserts into account.account; net.RegisterAccount/GetRegisterAccountResult
  (PythonAccountRegister.cpp) and the mt_register login-window dialog
  (RegisterScript.inc).
- --py-exec also runs in --login-screen mode for scripted login-screen tests.
- Touch controller, window manager and render command updates for the
  Android native client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:15:04 +09:00
shenleiandClaude Opus 5.5 53d06c3c26 android-native: real-server login by default, readable CJK text, 16 KB pages
- FreeType: add the cff/psaux/pshinter modules (from the pinned 2.13.3
  tarball, same sha256). Android's only CJK font is the CFF2
  NotoSansCJK-Regular.ttc, which the TrueType-only build could not open,
  so every Chinese glyph drew as a box.
- Font oversample rounds the UI density up: Android's 1760x800 UI on a
  2376x1080 screen is 1.35, which rounded to 1x bilevel glyphs stretched
  1.35x. Now 2x anti-aliased glyphs are scaled down. macOS 2.0 unchanged.
- MainActivity: a launcher start (no intent args) opens the login screen
  against 192.168.21.203 instead of auto-logging into the in-process fake
  server; explicit args still select the fake-server smoke flow.
- build-android-native.sh: ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON for SDL3
  and libmain (LOAD alignment 0x1000 -> 0x4000), with a stamp that
  rebuilds a cached pre-flag SDL3. Clears Android's 16 KB compat warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:16:38 +09: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 07c101fdc8 Merge native HiDPI rendering and shop item layout fix
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:56:52 +09:00
shenleiandClaude Opus 5.5 52ccb80d01 native_render: HiDPI glyph pages, sharp UI upscaling, 4x MSAA
- CGraphicFontTexture rasterises glyph pages at the swapchain density
  (UISetFontOversample, MT_FONT_OVERSAMPLE) with anti-aliased coverage;
  metrics, packing and UVs stay the 40250 1x values. Default 1 keeps the
  verbatim bilevel path (Godot unchanged).
- native.frag: sharp-bilinear sampling for magnified UI textures.
- Multisampled colour/depth with a resolve into the swapchain (MT_MSAA,
  default 4); stats line reports msaa=N.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:56:36 +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
shenleiandClaude Opus 5.5 b776fd071f gitignore: ignore the build-native/ CMake tree
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:56:58 +09:00
shenleiandClaude Opus 5.5 9c6e3d6d9e render parity: close SpeedTree .spt 0x4E25 follow-up (billboard rect, not leaf texcoords)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:33:22 +09:00
shenleiandClaude Opus 5.5 d2356d59c3 render parity unit K: 40250 DDS mip levels
DXT DDS textures upload the file's own mip levels like 40250
CGraphicImageTexture::CreateDDSTexture (max(1, dwMipMapCount), level i read
at sum(dwLinearSize>>2k), Copy of dwLinearSize>>2i bytes) instead of a
regenerated chain. Non-DDS images keep the D3DX_DEFAULT full chain and mem:
textures get one level. The invented is_ui_tex no-mip rule (icon/, ui/,
locale/, <=128px) is deleted. dxt_decode_test is registered in ctest with
mip-level cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:29:30 +09:00
shenleiandClaude Opus 5.5 dda885a17a render parity unit J: 40250 automatic sight range in CPythonApplication::Process
Process now runs 40250's render-time / face-count block and sets view
distance set 0 each frame (25600 under 5000 faces, else scaled by render
time, or the forced range). SetForceSightRange and SkipRenderBuffering are
ported from stubs; the invented SetCursorPosition in UpdateGame is removed.
Port-map boilerplate notes replaced; Destroy recorded as DIVERGENT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:22:41 +09: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 d3fd5f8613 test: login_flow waits a fixed frame count between mouse move and click
The 0.1 s wall-clock waits could fit a single frame under ctest -j3, so the
shopkeeper pick missed about one run in four.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:17:26 +09:00
shenleiandClaude Opus 5.5 3e270dccc1 render parity unit H2: verbatim 40250 water
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:03:12 +09:00
shenleiandClaude Opus 5.5 6dffd1572a render parity unit H1: verbatim 40250 HTP terrain
MapOutdoorRenderHTP.cpp is the full 40250 source behind the native-terrain
gate: no invented texture-0 fallback, first-splat stage-1 ALPHAOP DISABLE,
GetNumTextures() bound, 40250 shadow-pass states (FOGCOLOR white, CLAMP,
TEXTURE1 m_matDynamicShadow). Fixes the white far-terrain band.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:57:55 +09:00
shenleiandClaude Opus 5.5 863f3771af render parity unit G: 40250 tiling selection + verbatim STP terrain
- PythonApplication::Create mirrors 40250 :1196-1251 (SOFTWARE_TILING cfg,
  auto tiling IsFastTNL ? HTP : STP, MinLOD on !IsFastTNL)
- RecordingDevice caps: VertexShaderVersion 1.1 + CLIPTLVERTS (fast T&L -> HTP)
- MapOutdoorRenderSTP.cpp replaced by the full 40250 source (native gate only)
- native_render XYZRHW: fix inverted screen->NDC Y, negative rhw clip,
  no texture transform on TL vertices, specular-alpha vertex fog (capture v9)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:54:11 +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
shenleiandClaude Opus 5.5 5285ca85fd native render: transliterate D3D8 fixed-function pipeline (unit A)
- Texture coordinates: TEXCOORDINDEX generation (camera-space normal /
  position / reflection vector, LOCALVIEWER) and D3DTS_TEXTUREn under
  TEXTURETRANSFORMFLAGS (incl. PROJECTED) now run in native.vert; the
  RecordingDevice CPU uv baking and the sphere-map / multiplicative-shadow
  shader hacks are removed. Godot consumer uses Render3DStageTexcoords.
- Lighting: 8 D3D lights in camera space, 1/(a0+a1d+a2d^2) without clamp,
  spot cone theta/2 phi/2 with falloff, diffuse/ambient/emissive material
  sources, NORMALIZENORMALS, inverse-transpose normal matrix.
- Alpha test compares 8-bit alpha against ALPHAREF with ALPHAFUNC.
- Back-buffer Clear() is recorded in draw order and executed with
  vkCmdClearAttachments; render pass clears to 0xff000000.
- D3DVIEWPORT8 (incl. MinZ/MaxZ) is dynamic per-draw state.
- Missing vertex diffuse is opaque white; alpha blend mirrors SRC/DESTBLEND.
- CScreen::ms_clearDepth / ms_diffuseColor initialised to 40250's
  1.0f / 0xffffffff (were zero; exposed once clears were executed).
- Capture format v8; --screenshot-out FILE.bmp swapchain readback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:54:13 +09: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 85e176bdd5 Batch 4-b: verify combat on the port route
The fake server spawns a stray dog outside the village's BANPK safe disc
and answers CG_TARGET/CG_ATTACK with GC_TARGET/GC_DAMAGE_INFO/GC_DEAD.
port.login_flow and python_game_render_test hold the left button on it
(MBF_SMART -> __OnPressActor) until it dies. Adds the host/test helper
PythonBoot::Evaluate / Metin2PythonHost.evaluate.

python_3d_surface: emission is now multiplied by the texture, like
D3D's emissive-then-MODULATE, which removes the grey click-glow quad and
the grey wash on characters. Damage numbers wait on CPythonSystem (4-g).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 09:13:20 +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 1bda4390d6 docs: the sword by the actor is the fake server's ground item, not a weapon-attach bug
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 07:37:20 +09:00
shenleiandClaude Opus 5.5 a49942a1a1 client_main: default route switches to port (MT_PORT_PATH)
Without MT_PORT_PATH the app runs 40250 system.py on the Python UI and
3D surfaces; MT_PORT_PATH=legacy keeps the GDScript AppFlow. The
smoke/playable live tests stay on legacy, MT_TEST_MODE=python_ui remains
a port alias, and an unset switch falls back to legacy (with a warning)
when the Python host or the 40250 pack is missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:51:55 +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 be5a68ff35 port-map: mark 28 verified units already in port/ as PORTED
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>
2026-09-24 00:13:32 +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 05de621199 port: mark PythonCharacterManager + InstanceBaseMovement PORTED (batch 2 P0)
Both units were copied verbatim in 2V2-b and are on the running path since
2V3; diffed against 40250 (only include case, comment encoding and two
PORT edits) and no duplicate definitions outside port/. P0 queue is empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 00:02:17 +09:00
shenleiandClaude Opus 5.5 8b4700f008 2V3-b: click on the ground to walk; read the terrain attribute map
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>
2026-09-23 23:57:34 +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
shenleiandClaude Opus 5.5 157f7c3bb4 2V2-e.5c: live smoke on c1, show the map behind the actor
The live run passed its checks, but the screenshot showed wolves floating over a
ground that ended at the actor's feet. Native heights were right (every actor
meets sample_height); two Metin2World settings written for metre units culled
the terrain in this cm-scaled scene: the .msenv depth fog (120-520) and the
terrain patch visibility_range_end (3500). The 3D surface now turns the legacy
fog off (fog belongs to the recorded D3DRS_FOG* state, off until
SetEnvironmentData is ported) and builds one mesh per tile.

The render test checks that every actor (draws grouped by world matrix) stands
on the map and that the map behind the actor shows texture. mouse.cfg, written
by 40250 uitaskbar.py at runtime, is ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 23:18:20 +09:00
shenlei 5a1df57e69 2V2-e.5b: feed native map height and light into game render 2026-09-23 22:10:29 +09:00
shenlei 702fef7b47 2V2-e.5a: restore 40250 min-max helpers for camera update 2026-09-23 22:05:24 +09:00
shenlei cb43091f79 2V2-e.4: render 40250 pack terrain with map lighting 2026-09-23 21:19:14 +09:00
shenleiandClaude Opus 5.5 ac4c2aa4e0 2V2-e.3: live smoke of the Godot render adapter
Fix the material cache key: bools given to %d failed to format, so every
draw shared the first material (the face texture). The render test now
checks one texture per texture name. Offline and live (192.168.21.203)
show the dressed main character; live also shows the nearby mobs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 20:42: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