106 lines
4.3 KiB
GDScript
106 lines
4.3 KiB
GDScript
extends RefCounted
|
|
|
|
## P07-01 F7: the fixture and minute script shared by the restart writer
|
|
## (tests/environment/test_p07_weather_restart_1_write.gd) and reader
|
|
## (tests/environment/test_p07_weather_restart_2_read.gd), which run as separate
|
|
## engine processes. Seed 1106 opens day 0 with rain 06:00-12:00 (A13), a guest
|
|
## due at 06:02 is held to 10:02, production arrivals run, and day 1 draws at 06:00.
|
|
const HANDOFF_PATH := "res://artifacts/p07-01/restart-handoff.json"
|
|
const HANDOFF_SCHEMA := "p07-01-restart-handoff-v1"
|
|
const WRITER_SOURCE := "res://tests/environment/test_p07_weather_restart_1_write.gd"
|
|
const WRITER_SAVE := "user://p07_restart_write/minute_%d"
|
|
const READER_SAVE := "user://p07_restart_read/minute_%d"
|
|
const SEED := 1106
|
|
const FIRST_MINUTE := 360
|
|
# Mid-rain, just before and just after the rain end, just before and just after the day 1 draw.
|
|
const SAVE_MINUTES: Array[int] = [500, 719, 720, 1799, 1800]
|
|
const LAST_MINUTE := 1830
|
|
const DRAW_MINUTES: Array[int] = [1800]
|
|
const HELD_GUEST := &"p07_restart_guest"
|
|
|
|
var _expect: Callable
|
|
|
|
|
|
func _init(expect: Callable) -> void:
|
|
_expect = expect
|
|
|
|
|
|
func new_fixture(with_guest := true) -> Dictionary:
|
|
var clock: Variant = load("res://autoload/game_clock.gd").new()
|
|
var state: Variant = load("res://autoload/game_state.gd").new()
|
|
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
|
|
clock.reset(1, 6, 0)
|
|
state.reset()
|
|
_expect.call(bool(runtime.initialize(clock, state, SEED).get(&"valid", false)), "fixture Runtime initializes")
|
|
clock.set_paused(true)
|
|
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
|
|
_expect.call(bool(runtime.enable_production_operations().get(&"ok", false)), "fixture enables production Operations")
|
|
var fixture := {&"clock": clock, &"state": state, &"runtime": runtime, &"draws": {&"count": 0}}
|
|
if with_guest:
|
|
var result: CommandResult = runtime.submit_command(&"spawn_guest", {
|
|
&"guest_id": HELD_GUEST,
|
|
&"guest_type_id": &"traveler",
|
|
&"gold": 100,
|
|
&"options": {
|
|
&"current_cell": Vector3i(0, 0, WorldService.LAYER_FRONT),
|
|
&"needs": {&"hunger": 10, &"sleep": 10, &"hygiene": 10, &"medical": 0, &"leisure": 10, &"intimacy": 0},
|
|
&"planned_exit_at": 362,
|
|
},
|
|
}, &"world", HELD_GUEST, 10, -1, &"p07.restart.guest")
|
|
_expect.call(result.is_success(), "fixture spawns the guest due at 06:02")
|
|
watch_draws(fixture)
|
|
return fixture
|
|
|
|
|
|
func watch_draws(fixture: Dictionary) -> void:
|
|
var draws: Dictionary = fixture[&"draws"]
|
|
fixture[&"runtime"].domain_events.subscribe(&"WEATHER_FORECAST_DRAWN", &"p07_restart",
|
|
func(_event: SimulationDomainEvent) -> void: draws[&"count"] += 1)
|
|
|
|
|
|
func free_fixture(fixture: Dictionary) -> void:
|
|
for key: StringName in [&"runtime", &"clock", &"state"]:
|
|
if fixture.get(key) != null and is_instance_valid(fixture[key]):
|
|
fixture[key].free()
|
|
|
|
|
|
## Advances one minute at a time after `after_minute` through `through_minute`
|
|
## and calls `on_minute` after each minute (the writer saves there).
|
|
func play(fixture: Dictionary, after_minute: int, through_minute: int, on_minute: Callable) -> void:
|
|
var clock: Variant = fixture[&"clock"]
|
|
_expect.call(clock.absolute_minute == after_minute, "play starts at minute %d" % after_minute)
|
|
for minute: int in range(after_minute + 1, through_minute + 1):
|
|
clock.advance_minutes(1)
|
|
if on_minute.is_valid():
|
|
on_minute.call(minute)
|
|
|
|
|
|
## The weather-facing state compared across processes: weather and its stream,
|
|
## guest plans, the reserve flow and the arrival totals.
|
|
func state_value(runtime: Variant) -> Dictionary:
|
|
var plans := {}
|
|
for guest: GuestRuntime in runtime.guest_service.get_guests():
|
|
plans[String(guest.guest_id)] = guest.planned_exit_at
|
|
var arrivals := 0
|
|
for report: Dictionary in runtime.operations_coordinator.get_arrival_reports():
|
|
arrivals += int(report[&"total_count"])
|
|
return {
|
|
"minute": runtime.weather.get_minute(),
|
|
"weather": runtime.weather.create_snapshot(),
|
|
"stream": runtime.get_rng_stream(&"weather").snapshot(),
|
|
"plans": plans,
|
|
"reserve_flow": runtime.mana_reserve.get_last_flow(),
|
|
"arrivals": arrivals,
|
|
}
|
|
|
|
|
|
func state_bytes(runtime: Variant) -> PackedByteArray:
|
|
return var_to_bytes(state_value(runtime))
|
|
|
|
|
|
static func sha256(bytes: PackedByteArray) -> String:
|
|
var context := HashingContext.new()
|
|
context.start(HashingContext.HASH_SHA256)
|
|
context.update(bytes)
|
|
return context.finish().hex_encode()
|