P07-01-WX: 仕上がった天候の機能の受入:自然天候・雨・嵐・世界樹と成人客のマナ霧・上部の表示と予報・保存と移行(マナ炉の産出 120 を除く。P07-01 の補助の作業。原単位への加算 0)

This commit is contained in:
Agent Control Runner
2026-10-24 08:59:36 +09:00
parent f99c881bca
commit db87270972
9 changed files with 108 additions and 16 deletions
@@ -26,15 +26,23 @@ func _run() -> void:
var straight := fixtures.new_fixture()
var straight_runtime: Variant = straight[&"runtime"]
var held_guest: Variant = straight_runtime.guest_service.get_guest(Fixture.HELD_GUEST)
var held := {"hold": {}, "reason": &""}
fixtures.play(straight, Fixture.FIRST_MINUTE, Fixture.LAST_MINUTE, func(_minute: int) -> void:
var held := {"hold": {}, "reason": &"", "after": {}}
fixtures.play(straight, Fixture.FIRST_MINUTE, Fixture.LAST_MINUTE, func(minute: int) -> void:
if (held["hold"] as Dictionary).is_empty():
held["hold"] = straight_runtime.weather.get_rain_hold(Fixture.HELD_GUEST)
if StringName(held["reason"]).is_empty():
held["reason"] = held_guest.exit_reason)
held["reason"] = held_guest.exit_reason
if minute == 363:
_expect(straight_runtime.guest_service.get_guest(Fixture.HELD_GUEST) != null and held_guest.state == GuestRuntime.State.LEAVING
and straight_runtime.weather.get_rain_hold(Fixture.HELD_GUEST) == Fixture.HOLD, "at 06:03 the held guest is still present and leaving with its hold")
if minute == 364:
_expect(straight_runtime.guest_service.get_guest(Fixture.HELD_GUEST) == null and straight_runtime.weather.get_rain_holds().is_empty(),
"at 06:04 the held guest is gone and its hold left with it")
if minute - 1 in Fixture.SAVE_MINUTES:
held["after"][minute] = fixtures.state_bytes(straight_runtime))
# The hold only moves the planned exit; every other current rule still applies,
# so in this world without facilities the guest leaves for lack of one.
_expect(held["hold"] == {"original_exit": 362, "extended_to": 602} and held_guest.planned_exit_at == 602 and held["reason"] == &"NO_SUITABLE_FACILITY",
_expect(held["hold"] == Fixture.HOLD and held_guest.planned_exit_at == 602 and held["reason"] == &"NO_SUITABLE_FACILITY",
"the guest due at 06:02 was held to 10:02 and still left by the current rules (%s)" % String(held["reason"]))
_expect(straight[&"draws"][&"count"] == Fixture.DRAW_MINUTES.size() and straight_runtime.weather.get_last_draw_day() == 1, "the uninterrupted script draws day 1 once")
var saving := fixtures.new_fixture()
@@ -43,16 +51,39 @@ func _run() -> void:
var saved_paths := {}
fixtures.play(saving, Fixture.FIRST_MINUTE, Fixture.LAST_MINUTE, func(minute: int) -> void:
if minute in Fixture.SAVE_MINUTES:
if minute == 363:
_expect(saving_runtime.guest_service.get_guest(Fixture.HELD_GUEST) != null and saving_runtime.weather.get_rain_holds() == {String(Fixture.HELD_GUEST): Fixture.HOLD}
and saving_runtime.guest_service.get_guest(Fixture.HELD_GUEST).planned_exit_at == 602, "minute 363 saves the hold of the present held guest")
if minute == 364:
_expect(saving_runtime.guest_service.get_guest(Fixture.HELD_GUEST) == null and saving_runtime.weather.get_rain_holds().is_empty(), "minute 364 saves just after the held guest left, without its hold")
if minute == 500:
var held_present: bool = saving_runtime.guest_service.get_guest(Fixture.HELD_GUEST) != null
_expect(saving_runtime.weather.get_kind() == &"rain" and (not held_present or not saving_runtime.weather.get_rain_hold(Fixture.HELD_GUEST).is_empty()), "minute 500 saves mid-rain with the hold of a present guest")
_expect(saving_runtime.weather.get_kind() == &"rain", "minute 500 saves mid-rain")
var path := Fixture.WRITER_SAVE % minute
saved_states[minute] = fixtures.state_bytes(saving_runtime)
_expect(bool(saving_runtime.save_to_path(path).get(&"ok", false)), "save file at minute %d" % minute)
saved_paths[minute] = path)
_expect(fixtures.state_bytes(saving_runtime) == fixtures.state_bytes(straight_runtime), "writing the save files leaves the weather state as without saving")
var saves := _packages(Fixture.SAVE_MINUTES, saved_paths, saved_states, Fixture.WRITER_SAVE)
var final_state := fixtures.state_bytes(straight_runtime)
for minute: int in Fixture.SAVE_MINUTES:
var reload := fixtures.new_fixture(false)
var reload_runtime: Variant = reload[&"runtime"]
_expect(bool(reload_runtime.load_from_path(str(saved_paths.get(minute, Fixture.WRITER_SAVE % minute))).get(&"ok", false))
and fixtures.state_bytes(reload_runtime) == saved_states.get(minute, PackedByteArray()) and reload[&"clock"].absolute_minute == minute,
"this process reloads the save file of minute %d exactly" % minute)
if minute == 363:
_expect(reload_runtime.weather.get_rain_holds() == {String(Fixture.HELD_GUEST): Fixture.HOLD} and reload_runtime.guest_service.get_guest(Fixture.HELD_GUEST).planned_exit_at == 602,
"the reloaded minute 363 save keeps the one hold and the extended plan")
fixtures.play(reload, minute, minute + 1, Callable())
_expect(fixtures.state_bytes(reload_runtime) == held["after"].get(minute + 1, PackedByteArray()),
"one minute after the minute %d reload equals the uninterrupted run (no second extension)" % minute)
fixtures.play(reload, minute + 1, Fixture.LAST_MINUTE, Callable())
_expect(fixtures.state_bytes(reload_runtime) == final_state, "the minute %d reload continues to the uninterrupted final state" % minute)
fixtures.free_fixture(reload)
var saves := _packages(Fixture.SAVE_MINUTES, saved_paths, saved_states, Fixture.WRITER_SAVE)
var after := {}
for minute: int in held["after"]:
var bytes: PackedByteArray = held["after"][minute]
after[str(minute)] = {"sha256": Fixture.sha256(bytes), "base64": Marshalls.raw_to_base64(bytes)}
var fog := _fog_scene(fixtures)
var handoff := {
"schema": Fixture.HANDOFF_SCHEMA,
@@ -62,6 +93,7 @@ func _run() -> void:
"last_minute": Fixture.LAST_MINUTE,
"straight_final_state_sha256": Fixture.sha256(final_state),
"straight_final_state_base64": Marshalls.raw_to_base64(final_state),
"after_states": after,
"saves": saves,
"fog": fog,
}
@@ -55,19 +55,28 @@ func _check_restarts(handoff: Dictionary) -> void:
_expect(Fixture.sha256(final_state) == str(handoff.get("straight_final_state_sha256", "")), "the writer's final state arrived intact")
var saves: Array = handoff.get("saves", [])
_expect(saves.size() == Fixture.SAVE_MINUTES.size(), "every save package was handed off")
var after: Dictionary = handoff.get("after_states", {})
for save: Variant in saves:
var minute := int((save as Dictionary).get("minute", -1))
var path := Fixture.READER_SAVE % minute
_expect(_write_package(save, path), "save package at minute %d arrived byte-exact" % minute)
var expected_state := Marshalls.base64_to_raw(str((save as Dictionary).get("state_base64", "")))
var next_row: Dictionary = after.get(str(minute + 1), {})
var next_state := Marshalls.base64_to_raw(str(next_row.get("base64", "")))
_expect(not next_state.is_empty() and Fixture.sha256(next_state) == str(next_row.get("sha256", "")), "the writer's state one minute after %d arrived intact" % minute)
var fixture := fixtures.new_fixture(false)
var runtime: Variant = fixture[&"runtime"]
_expect(bool(runtime.load_from_path(path).get(&"ok", false)), "the reader loads the minute %d save" % minute)
_expect(fixtures.state_bytes(runtime) == expected_state and fixture[&"clock"].absolute_minute == minute, "the minute %d save resumes the writer's weather, holds, stream and plans" % minute)
if minute == 363:
_expect(runtime.weather.get_rain_holds() == {String(Fixture.HELD_GUEST): Fixture.HOLD} and runtime.guest_service.get_guest(Fixture.HELD_GUEST) != null
and runtime.guest_service.get_guest(Fixture.HELD_GUEST).planned_exit_at == 602, "the reader resumes the one hold of the present held guest and its extended plan")
# Loading replaces the event stream, so the draw counter subscribes again.
fixture[&"draws"][&"count"] = 0
fixtures.watch_draws(fixture)
fixtures.play(fixture, minute, Fixture.LAST_MINUTE, Callable())
fixtures.play(fixture, minute, minute + 1, Callable())
_expect(fixtures.state_bytes(runtime) == next_state, "one minute after the minute %d save the reader equals the writer (no second extension)" % minute)
fixtures.play(fixture, minute + 1, Fixture.LAST_MINUTE, Callable())
var expected_draws := 0
for draw_minute: int in Fixture.DRAW_MINUTES:
if draw_minute > minute:
@@ -238,6 +238,16 @@ func _test_rain_stay_and_saves() -> void:
## itself runs at the extended time: it is not held again and begins leaving
## with the ordinary PLANNED_EXIT.
func _test_rain_hold_exit() -> void:
var natural := _new_runtime(SEED_RAIN)
var natural_runtime: Variant = natural[&"runtime"]
var departing: Variant = _spawn(natural_runtime, &"p07_departing_guest", &"traveler", 362)
natural[&"clock"].advance_minutes(3)
_expect(natural_runtime.weather.get_rain_hold(&"p07_departing_guest") == {"original_exit": 362, "extended_to": 602} and departing.state == GuestRuntime.State.LEAVING
and departing.exit_reason == &"NO_SUITABLE_FACILITY", "in ordinary minutes the held guest still leaves by the current rules")
natural[&"clock"].advance_minutes(1)
var departed: Dictionary = natural_runtime.create_snapshot()
_expect(natural_runtime.guest_service.get_guest(&"p07_departing_guest") == null and natural_runtime.weather.get_rain_holds().is_empty()
and natural_runtime.restore_snapshot(departed) and natural_runtime.create_snapshot() == departed, "the hold leaves with the guest, so the minute it left restores")
var rainy := _new_runtime(SEED_RAIN)
var runtime: Variant = rainy[&"runtime"]
var guest: Variant = _spawn(runtime, &"p07_exit_guest", &"traveler", 362)
+6 -2
View File
@@ -5,6 +5,8 @@ extends RefCounted
## (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.
## With no facility in this world the held guest starts leaving at 06:03 (still
## present with its hold) and is gone at 06:04 (its hold leaves with it).
## The fog scene (WX7): seed 1592 opens day 0 with mana fog 06:00-10:00, two
## adult-verified guests arrive at 06:58 and 09:58 (with no facility in this
## world a guest leaves after a few minutes, so each one is present at its
@@ -16,8 +18,10 @@ 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]
# The held guest present with its hold, the minute it left, mid-rain, just before and
# just after the rain end, just before and just after the day 1 draw.
const SAVE_MINUTES: Array[int] = [363, 364, 500, 719, 720, 1799, 1800]
const HOLD := {"original_exit": 362, "extended_to": 602}
const LAST_MINUTE := 1830
const DRAW_MINUTES: Array[int] = [1800]
const HELD_GUEST := &"p07_restart_guest"