feat: complete native client rendering parity updates

This commit is contained in:
shen
2026-09-27 19:44:41 -07:00
parent 9a9dc6d224
commit 25dd65f2ce
99 changed files with 21121 additions and 921 deletions
+143
View File
@@ -0,0 +1,143 @@
extends SceneTree
const PythonUISurface = preload("res://python_ui_surface.gd")
const Python3DSurface = preload("res://python_3d_surface.gd")
var ui: Control
var world: Node3D
func _initialize() -> void:
call_deferred("run")
func _py(source: String) -> bool:
return Metin2PythonHost.run_line(source) == ""
func _key(keycode: Key, unicode: int, pressed: bool) -> void:
var event := InputEventKey.new()
event.keycode = keycode
event.physical_keycode = keycode
event.unicode = unicode
event.pressed = pressed
root.push_input(event)
func _press(keycode: Key) -> void:
_key(keycode, 0, true)
_key(keycode, 0, false)
func _type(text: String) -> void:
for i in text.length():
var ch := text.unicode_at(i)
var keycode := OS.find_keycode_from_string(text[i].to_upper())
_key(keycode, ch, true)
_key(keycode, ch, false)
func _pump_until(seconds: float, condition: Callable) -> bool:
var deadline := Time.get_ticks_msec() + int(seconds * 1000.0)
while Time.get_ticks_msec() < deadline:
if condition.call():
return true
await process_frame
return condition.call()
func run() -> void:
root.size = Vector2i(1024, 768)
world = Python3DSurface.new()
world.name = "Python3DSurface"
ui = PythonUISurface.new()
ui.name = "PythonUISurface"
root.add_child(ui)
root.add_child(world)
var err: String = ui.run_app()
if err != "":
print("ERROR: run_app failed: ", err)
quit(1)
return
await _pump_until(15, func(): return _py(
"import __main__, os, networkModule, introLogin, introSelect, game, player, background, chr, chrmgr\n"
+ "__main__._stream = [o for o in __import__('gc').get_objects() if isinstance(o, networkModule.MainStream)][0]"
))
await _pump_until(20, func(): return _py(
"assert isinstance(_stream.curPhaseWindow, introLogin.LoginWindow)"
))
_py(
"_env = os.environ\n"
+ "_slot = int(_env.get('MT_LIVE_SLOT', '0'))\n"
+ "_stream.SetConnectInfo(_env['MT_LIVE_HOST'], int(_env.get('MT_LIVE_GAME_PORT', '13000')), "
+ "_env['MT_LIVE_HOST'], int(_env.get('MT_LIVE_AUTH_PORT', '11000')))\n"
+ "_w = _stream.curPhaseWindow\n"
+ "_w._LoginWindow__OpenLoginBoard()\n"
+ "_w.idEditLine.SetText('')\n"
+ "_w.pwdEditLine.SetText('')\n"
+ "_w.idEditLine.SetFocus()"
)
_type(OS.get_environment("MT_LIVE_LOGIN"))
_press(KEY_TAB)
_type(OS.get_environment("MT_LIVE_PASSWORD"))
_py("del _env, _w")
_press(KEY_ENTER)
await _pump_until(30, func(): return _py(
"assert isinstance(_stream.curPhaseWindow, introSelect.SelectCharacterWindow)"
))
_py("_stream.curPhaseWindow.SelectSlot(_slot)\n_stream.curPhaseWindow.StartGame()")
await _pump_until(30, func(): return _py(
"assert isinstance(_stream.curPhaseWindow, game.GameWindow) and _stream.curPhaseWindow.IsShow()"
))
for i in 30:
await process_frame
print("=== DEBUG HEIGHT REPORT ===")
var test_points = [
Vector2(59700, 68200),
Vector2(59700, 66400),
Vector2(60100, 66400),
Vector2(50000, 50000),
Vector2(30000, 30000),
Vector2(70000, 70000),
]
for pt in test_points:
var bg_h = Metin2PythonHost.evaluate("str(background.GetHeight(%f, %f))" % [pt.x, pt.y])
var tm_h = float(world.terrain.call("sample_height", pt.x / 100.0, pt.y / 100.0)) * 100.0 if world.terrain else 0.0
print("Point (%.0f, %.0f): 40250_bg_h=%s, Metin2World_h=%.1f, diff=%.1f" % [
pt.x, pt.y, bg_h, tm_h, float(bg_h) - tm_h
])
# Inspect terrain mesh triangles around dog
print("=== TERRAIN MESH VERTICES AROUND DOG (59700, -66400) ===")
# In camera space (since Camera3D is at origin):
# Dog world pos in 40250: (59700, -66400, 19851.5)
# What is dog in camera space?
var draws = Metin2PythonHost.render3d_draws()
for i in draws.size():
var d = draws[i]
var tex: String = d.get("texture0", "")
if tex.contains("stray_dog"):
var wm: PackedFloat32Array = d.get("world", PackedFloat32Array())
var vm: PackedFloat32Array = d.get("view", PackedFloat32Array())
var xform: Transform3D = Python3DSurface.d3d_transform(Python3DSurface.multiply(wm, vm))
print("DOG camera-space transform origin: ", xform.origin)
# Now let's check terrain mesh global transform and vertices:
for child in world.terrain.find_children("*", "MeshInstance3D", true, false):
var mi := child as MeshInstance3D
if mi.mesh is ArrayMesh:
var am := mi.mesh as ArrayMesh
var arrays := am.surface_get_arrays(0)
var verts: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX]
for v in verts:
var gv: Vector3 = mi.global_transform * v
# Dog in camera space is around xform.origin. Let's find terrain vertices within 200cm:
if abs(gv.x - xform.origin.x) < 200.0 and abs(gv.z - xform.origin.z) < 200.0:
print("Terrain vertex near dog in camera-space: ", gv, " dog origin: ", xform.origin, " diff_y (height in cam space): ", gv.y - xform.origin.y)
break
break
quit(0)