117 lines
3.6 KiB
GDScript
117 lines
3.6 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 _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()
|
|
ui = PythonUISurface.new()
|
|
root.add_child(ui)
|
|
root.add_child(world)
|
|
|
|
ui.run_app()
|
|
|
|
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)"
|
|
))
|
|
|
|
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()"
|
|
))
|
|
|
|
for i in 60:
|
|
await process_frame
|
|
|
|
print("=== INVESTIGATING ALL 518 ACTORS ===")
|
|
var draws: Array = Metin2PythonHost.render3d_draws()
|
|
var actor_draws := {}
|
|
for d in draws:
|
|
var wm: PackedFloat32Array = d["world"]
|
|
var key := "%.1f,%.1f,%.1f" % [wm[12], wm[13], wm[14]]
|
|
if not actor_draws.has(key):
|
|
actor_draws[key] = []
|
|
actor_draws[key].append(d)
|
|
|
|
print("Unique actor positions: ", actor_draws.size())
|
|
|
|
var anomalies := []
|
|
for key in actor_draws:
|
|
var ds: Array = actor_draws[key]
|
|
var wm: PackedFloat32Array = ds[0]["world"]
|
|
var map_x := wm[12]
|
|
var map_y := -wm[13]
|
|
var actor_z := wm[14]
|
|
|
|
var bg_h = float(Metin2PythonHost.evaluate("str(background.GetHeight(%f, %f))" % [map_x, map_y]))
|
|
var terrain_h = float(world.terrain.call("sample_height", map_x / 100.0, map_y / 100.0)) * 100.0 if world.terrain else 0.0
|
|
|
|
var diff_bg = actor_z - bg_h
|
|
var diff_terrain = actor_z - terrain_h
|
|
|
|
# Find textures
|
|
var texs := []
|
|
var min_vert_z := 1e9
|
|
for d in ds:
|
|
var t: String = d.get("texture0", "")
|
|
if not t.is_empty():
|
|
texs.append(t.get_file())
|
|
for p in d["positions"]:
|
|
min_vert_z = minf(min_vert_z, actor_z + p.z)
|
|
|
|
if absf(diff_bg) > 5.0 or absf(diff_terrain) > 5.0:
|
|
anomalies.append({
|
|
"pos": [map_x, map_y, actor_z],
|
|
"bg_h": bg_h,
|
|
"terrain_h": terrain_h,
|
|
"diff_bg": diff_bg,
|
|
"diff_terrain": diff_terrain,
|
|
"vert_min_diff": min_vert_z - bg_h,
|
|
"textures": texs
|
|
})
|
|
|
|
print("Found %d anomalies with gap > 5cm!" % anomalies.size())
|
|
for a in anomalies.slice(0, 30):
|
|
print("Anomaly: pos=(%.1f, %.1f, %.1f), bg_h=%.1f, terrain_h=%.1f, diff_bg=%.1f, diff_terrain=%.1f, vert_min_diff=%.1f, tex=%s" % [
|
|
a["pos"][0], a["pos"][1], a["pos"][2], a["bg_h"], a["terrain_h"], a["diff_bg"], a["diff_terrain"], a["vert_min_diff"], a["textures"]
|
|
])
|
|
|
|
quit(0)
|