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)