Handle late main-character data, guarded model construction, bounded retries and map correction. Validate player model sources and add lifecycle and real-asset visual regressions. Include pending material and character-selection changes, updated A1 screenshot, and the detailed rendering repair plan. Hair occlusion, full UI parity and final macOS package acceptance remain unfinished.
73 lines
3.5 KiB
GDScript
73 lines
3.5 KiB
GDScript
# Real GameScene/assets, delayed authoritative row, no network or account writes.
|
|
extends SceneTree
|
|
|
|
const GameScene = preload("res://game_scene.gd")
|
|
const Fixtures = preload("res://gamescene_test.gd")
|
|
var failed := false
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run")
|
|
|
|
func run() -> void:
|
|
root.size = Vector2i(1280, 720)
|
|
var output := OS.get_environment("MT_RENDER_OUTPUT")
|
|
if output.is_empty():
|
|
output = ProjectSettings.globalize_path("res://../build/rendering/gamescene-%d" % Time.get_unix_time_from_system())
|
|
DirAccess.make_dir_recursive_absolute(output)
|
|
var fc := Fixtures.FakeClient.new()
|
|
root.add_child(fc)
|
|
var scene := GameScene.new()
|
|
root.add_child(scene)
|
|
await scene.setup(fc, AssetRoot.path(), "OutdoorA1/metin2_map_a1")
|
|
# Choose C1 to exercise late map correction too (setup initially had no VID).
|
|
var use_c1 := "--c1" in OS.get_cmdline_user_args()
|
|
var server := Vector2(959109, 269267) if use_c1 else Vector2(454600, 934000)
|
|
fc.main = 1000
|
|
fc.ents[1000] = {"vid": 1000, "name": "RenderTest", "race": 0,
|
|
"pos": Vector3(server.x * 0.01, 0, -server.y * 0.01),
|
|
"pos_cm": server, "is_main": true, "angle_deg": 0.0,
|
|
"func": 0, "moving": false, "hp": 100, "max_hp": 100, "dead": false}
|
|
for i in 30: await process_frame
|
|
var expected := MapCoord.to_world(fc.ents[1000].pos)
|
|
expected.y = scene.world.sample_height(expected.x, expected.z)
|
|
failed = not scene._model_built or scene.player.position.distance_to(expected) > 0.02
|
|
if use_c1: failed = failed or scene.map_path != "OutdoorC1/metin2_map_c1"
|
|
var surfaces := 0
|
|
for mi in scene.player.find_children("*", "MeshInstance3D", true, false):
|
|
if mi.mesh: surfaces += mi.mesh.get_surface_count()
|
|
failed = failed or surfaces == 0 or not scene._map_loaded()
|
|
if scene._model_built and scene.player.anim:
|
|
scene.player.anim.set_time(0.5)
|
|
scene.player.anim.set_process(false)
|
|
scene.cam.snap_to_target()
|
|
if DisplayServer.get_name() != "headless":
|
|
await RenderingServer.frame_post_draw
|
|
failed = failed or root.get_texture().get_image().save_png(output.path_join("game.png")) != OK
|
|
var report := {"passed": not failed, "map": scene.map_path, "server_cm": str(server),
|
|
"world_position": str(scene.player.position), "expected": str(expected),
|
|
"surfaces": surfaces, "map_report": scene.world.get_load_report(),
|
|
"engine": Engine.get_version_info(), "viewport": str(root.size),
|
|
"camera_transform": str(scene.cam.global_transform), "fov": scene.cam.fov,
|
|
"assets": AssetRoot.path(), "headless": DisplayServer.get_name() == "headless",
|
|
"scope": "real GameScene, delayed main row, no main signal; no server/40250 parity"}
|
|
var hashes := {}
|
|
for path in ["res://game_scene.gd", "res://ui/player_view.gd", "res://net/mapcoord.gd",
|
|
"res://gamescene_visual_test.gd", "res://bin/libmtgodot.macos.template_debug.dylib"]:
|
|
hashes[path] = FileAccess.get_sha256(path)
|
|
if scene._model_built:
|
|
for property in ["gr2_path", "hair_gr2", "hair_skin"]:
|
|
var path := String(scene.player.model.get(property))
|
|
if not path.is_empty(): hashes[path] = FileAccess.get_sha256(path)
|
|
var motion := String(scene.player.anim.get("anim_path")) if scene.player.anim else ""
|
|
if not motion.is_empty(): hashes[motion] = FileAccess.get_sha256(motion)
|
|
report["sha256"] = hashes
|
|
report["animation_sample_seconds"] = 0.5
|
|
var file := FileAccess.open(output.path_join("report.json"), FileAccess.WRITE)
|
|
file.store_string(JSON.stringify(report, "\t"))
|
|
file.close()
|
|
print("GAMESCENE_VISUAL: ", JSON.stringify(report))
|
|
scene.queue_free()
|
|
fc.queue_free()
|
|
await process_frame
|
|
quit(1 if failed else 0)
|