144 lines
4.7 KiB
GDScript
144 lines
4.7 KiB
GDScript
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)
|