feat: complete native client rendering parity updates
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user