fix(rendering): checkpoint main-character recovery and visual regression work
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.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user