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 _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: ", err) quit(1) return await _pump_until(15, func(): return _py( "import __main__, os, networkModule, introLogin, introSelect, game, player, background, chr, chrmgr, app\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)" )) var host = OS.get_environment("MT_LIVE_HOST") var login = OS.get_environment("MT_LIVE_LOGIN") var pwd = OS.get_environment("MT_LIVE_PASSWORD") var auth_port = int(OS.get_environment("MT_LIVE_AUTH_PORT")) var game_port = int(OS.get_environment("MT_LIVE_GAME_PORT")) _py("_stream.SetConnectInfo('%s', %d, '%s', %d)\n" % [host, game_port, host, auth_port] + "_stream.curPhaseWindow.Connect('%s', '%s')" % [login, pwd]) await _pump_until(30, func(): return _py( "assert isinstance(_stream.curPhaseWindow, introSelect.SelectCharacterWindow)" )) _py("_stream.curPhaseWindow.SelectSlot(0)\n_stream.curPhaseWindow.StartGame()") await _pump_until(30, func(): return _py( "assert isinstance(_stream.curPhaseWindow, game.GameWindow) and _stream.curPhaseWindow.IsShow()" )) print("=== IN-GAME LOADED ===") for i in 10: await process_frame print("--- EQUIPPING WEAPON 10 ---") _py("chr.SelectInstance(player.GetMainCharacterIndex())\nchr.SetWeapon(10)") for i in 10: await process_frame var check_draws = func(label: String): var draws: Array = Metin2PythonHost.render3d_draws() var body_draw = null var weapon_draws = [] for d in draws: var tex: String = d.get("texture0", "").to_lower() if tex.contains("warrior") and not tex.contains("hair"): body_draw = d elif tex.contains("weapon") or tex.contains("sword") or tex.contains("00010") or tex.contains("00040"): weapon_draws.append(d) print("[%s] Total draws=%d, weapon_draws=%d" % [label, draws.size(), weapon_draws.size()]) var b_xf: Transform3D = Transform3D() if body_draw != null: var wm: PackedFloat32Array = body_draw["world"] b_xf = Python3DSurface.d3d_transform(wm) print(" Body origin: ", b_xf.origin, " tex=", body_draw.get("texture0", "")) else: print(" Body draw not found!") for w in weapon_draws: var wm: PackedFloat32Array = w["world"] var xf: Transform3D = Python3DSurface.d3d_transform(wm) var dist := xf.origin.distance_to(b_xf.origin) if body_draw != null else 0.0 print(" Weapon origin: ", xf.origin, " dist_to_body=%.2f cm tex=%s" % [dist, w.get("texture0", "")]) check_draws.call("IDLE_FRAME_0") # Start moving! print("--- STARTING MOVEMENT (DIK_UP) ---") _py("player.SetSingleDIKKeyState(app.DIK_UP, True)") for frame in range(1, 40): await process_frame if frame % 5 == 0: check_draws.call("MOVING_FRAME_%d" % frame) _py("player.SetSingleDIKKeyState(app.DIK_UP, False)") for frame in range(1, 15): await process_frame check_draws.call("STOPPED") quit(0)