Implement playable Mac client and rendering validation
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
extends SceneTree
|
||||
|
||||
const EffectPlayer = preload("res://fx/effect_player.gd")
|
||||
var failures := 0
|
||||
|
||||
func check(ok: bool, label: String) -> void:
|
||||
if not ok:
|
||||
failures += 1
|
||||
printerr("FAIL: " + label)
|
||||
|
||||
func _init() -> void:
|
||||
call_deferred("run")
|
||||
|
||||
func fixture():
|
||||
var fx := EffectPlayer.new()
|
||||
fx.build({"particles": [{"start_time": 0.2,
|
||||
"emitter": {"CycleLength": 1.0, "CycleLoopEnable": 1}}],
|
||||
"lights": [{"duration": 0.8, "diffuse": [1.0, 0.5, 0.2, 1.0]}]})
|
||||
# A synthetic two-frame mesh isolates playback from MDE asset decoding.
|
||||
var host := Node3D.new()
|
||||
var mesh := MeshInstance3D.new()
|
||||
mesh.material_override = StandardMaterial3D.new()
|
||||
host.add_child(mesh)
|
||||
fx.add_child(host)
|
||||
fx._mesh_nodes.append(host)
|
||||
fx._mesh_states.append({"node": host, "clock": 0.0, "start_time": 0.0,
|
||||
"frame_delay": 0.5, "duration": 1.0, "children": [{"node": mesh,
|
||||
"frames": [{"visibility": 1.0}, {"visibility": 0.5}],
|
||||
"meshes": [ArrayMesh.new(), ArrayMesh.new()], "frame": -1}]})
|
||||
root.add_child(fx)
|
||||
fx.set_process(false) # Advance deterministically; SceneTree timers still run.
|
||||
return fx
|
||||
|
||||
func run() -> void:
|
||||
var fx = fixture()
|
||||
var emitter: GPUParticles3D = fx._emitters[0]
|
||||
check(not emitter.emitting, "build does not emit before play")
|
||||
fx.play(true)
|
||||
check(not emitter.emitting, "play respects delay immediately")
|
||||
fx._process(0.25)
|
||||
check(emitter.emitting, "particle starts on playback clock")
|
||||
fx._process(0.35)
|
||||
check(fx._mesh_states[0].children[0].frame == 1, "mesh reached second frame")
|
||||
fx.stop()
|
||||
fx._process(0.01)
|
||||
check(not fx._lights[0].visible, "stopped light stays hidden")
|
||||
check(not fx._mesh_nodes[0].visible, "stopped mesh stays hidden")
|
||||
check(is_equal_approx(fx._light_states[0].clock, 0.6), "stop freezes CPU clock")
|
||||
await create_timer(0.3).timeout
|
||||
check(not emitter.emitting, "old delayed start cannot revive stopped emitter")
|
||||
fx.play(false)
|
||||
check(not emitter.one_shot, "normal replay restores source loop mode")
|
||||
check(is_zero_approx(fx._mesh_states[0].clock), "mesh replay resets clock")
|
||||
check(is_zero_approx(fx._light_states[0].clock), "light replay resets clock")
|
||||
check(fx._mesh_states[0].children[0].frame == 0, "mesh replay restores first frame")
|
||||
check(fx._lights[0].visible, "light replay restores visibility")
|
||||
fx._process(0.1)
|
||||
check(not emitter.emitting, "replay uses new start delay")
|
||||
fx._process(0.1)
|
||||
check(emitter.emitting, "replay starts at delay boundary")
|
||||
# Old forced-one-shot cleanup must not delete a later persistent playback.
|
||||
await create_timer(2.5).timeout
|
||||
check(is_instance_valid(fx), "old auto-free cannot delete replay")
|
||||
if is_instance_valid(fx):
|
||||
fx.free()
|
||||
var once = fixture()
|
||||
once.play(true)
|
||||
once._process(once._longest_life() + 0.6)
|
||||
check(once.is_queued_for_deletion(), "current one-shot still cleans up")
|
||||
if not once.is_queued_for_deletion():
|
||||
once.free()
|
||||
await process_frame
|
||||
# Exercise the actual SceneTree process path, not just manual clock updates.
|
||||
var live = fixture()
|
||||
live.set_process(true)
|
||||
live.play()
|
||||
await create_timer(0.35).timeout
|
||||
check(live._emitters[0].emitting, "SceneTree starts delayed emission")
|
||||
live.stop()
|
||||
var stopped_clock: float = live._particle_states[0].clock
|
||||
await create_timer(0.1).timeout
|
||||
check(not live._emitters[0].emitting and not live._lights[0].visible,
|
||||
"SceneTree does not reactivate stopped effect")
|
||||
check(is_equal_approx(live._particle_states[0].clock, stopped_clock),
|
||||
"SceneTree leaves stopped clock unchanged")
|
||||
live.free()
|
||||
print("effect_playback_test: failures=%d" % failures)
|
||||
quit(1 if failures else 0)
|
||||
Reference in New Issue
Block a user