106 lines
3.1 KiB
GDScript
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()
|