Files
modbison/scripts/smoke_test_studio_playtest.gd

106 lines
3.1 KiB
GDScript

extends SceneTree
## Headless smoke test for Studio simulation harness, playtest transition,
## avatar spawn, and clean edit mode restoration (Task f77bf388e8b4).
var _failures: int = 0
var _checks: int = 0
const StudioSimulationManagerClass = preload("res://scripts/studio/studio_simulation_manager.gd")
const ObjectMotionComponentClass = preload("res://scripts/components/object_motion_component.gd")
func _init() -> void:
print("--- Running Smoke Test: Studio Simulation Harness & Playtest ---")
test_playtest_lifecycle()
test_state_rollback_on_stop()
if _failures == 0:
print("--- PASS: All %d studio playtest checks passed! ---" % _checks)
quit(0)
else:
printerr("--- FAIL: %d failures out of %d checks ---" % [_failures, _checks])
quit(1)
func _check(desc: String, cond: bool) -> void:
_checks += 1
if cond:
print(" ✓ %s" % desc)
else:
_failures += 1
printerr(" ✗ FAIL: %s" % desc)
func _make_mock_core() -> EditorCore:
var payload := ChunkDataDecoder.ChunkPayload.new()
var layer := ChunkDataDecoder.TileLayerData.new()
layer.name = "ground"
layer.layer_id = 0
layer.width = 16
layer.height = 16
layer.depth = 1
layer.tiles = PackedInt32Array()
layer.tiles.resize(16 * 16)
payload.tile_layers.append(layer)
var model := ChunkEditorModel.new(payload)
var catalog := EditorObjectCatalog.new()
catalog.load_catalog()
return EditorCore.new(model, catalog)
func test_playtest_lifecycle() -> void:
print("Testing Simulation transition (Edit -> Play -> Stop)...")
var core := _make_mock_core()
var world := Node3D.new()
root.add_child(world)
var sim := StudioSimulationManagerClass.new()
world.add_child(sim)
sim.setup(core, world)
_check("Initial state is EDIT mode", sim.is_editing())
_check("is_playing returns false", not sim.is_playing())
# Start Play
sim.start_play(true)
_check("State transitioned to PLAYING", sim.is_playing())
_check("Test avatar spawned in world", sim._spawned_avatar != null)
# Stop Play
sim.stop_simulation()
_check("State restored to EDIT mode", sim.is_editing())
_check("Test avatar despawned cleanly", sim._spawned_avatar == null)
world.queue_free()
func test_state_rollback_on_stop() -> void:
print("Testing world object transform snapshot and clean rollback...")
var core := _make_mock_core()
var world := Node3D.new()
root.add_child(world)
# Place an initial object at (5, 5, 0)
var obj_id := core.place_object("crate_small", Vector3(5, 5, 0))
_check("Placed initial crate at (5, 5, 0)", obj_id != "")
var sim := StudioSimulationManagerClass.new()
world.add_child(sim)
sim.setup(core, world)
# Start Play (takes snapshot of (5, 5, 0))
sim.start_play(false)
# Simulate movement during gameplay (e.g. physics push or script motion to (20, 30, 10))
var obj = core.model.find_object(obj_id)
obj.position = Vector3(20, 30, 10)
_check("Object moved during gameplay to (20, 30, 10)", obj.position.is_equal_approx(Vector3(20, 30, 10)))
# Stop Play -> triggers snapshot rollback
sim.stop_simulation()
_check("Object restored exactly to pre-play position (5, 5, 0)",
obj.position.is_equal_approx(Vector3(5, 5, 0)))
world.queue_free()