P08-03: 配置の通常操作受入

This commit is contained in:
Agent Control Runner
2026-10-14 03:52:45 +09:00
parent 7dd450c64c
commit c2b59f04f9
13 changed files with 409 additions and 53 deletions
+74 -4
View File
@@ -18,6 +18,9 @@ var target := Vector3i(-8, 0, 0)
var budget: Dictionary = {}
var input_method := "handler"
var observed_cell: Variant = null
var save_serial := 0
var save_records: Array = []
const INITIAL_SAVE := "user://saves/p08_initial"
func annotate(row: Dictionary) -> void:
row["input_method"] = input_method
@@ -69,6 +72,8 @@ func button(node: BaseButton) -> void:
expect(node != null and not node.disabled, "available production button")
if node == null or node.disabled:
return
if node.toggle_mode:
node.button_pressed = not node.button_pressed
node.pressed.emit()
await frames()
@@ -77,7 +82,9 @@ func choose(id: StringName) -> void:
await button(main.palette_toggle_button)
var node: Button = main.build_buttons[id]
await reveal(node)
await button(node)
if not node.button_pressed:
await button(node)
expect(node.button_pressed and main._selected_definition_id == id, "chosen production definition")
func click(cell: Vector3i) -> Dictionary:
var view: WorldPreview = main.world_preview
@@ -253,6 +260,7 @@ func run(p_tree: SceneTree, output: String, requested_role: String) -> Dictionar
expect(DirAccess.make_dir_recursive_absolute(directory) == OK, "diagnostic directory")
runtime = tree.root.get_node("SimulationRuntime")
clock = tree.root.get_node("GameClock")
runtime.save_operation_completed.connect(record_save_operation)
await setup()
runtime.command_completed.connect(observe)
main.world_preview.cell_clicked.connect(selected_cell)
@@ -265,10 +273,12 @@ func run(p_tree: SceneTree, output: String, requested_role: String) -> Dictionar
if requested_role == "standalone":
role = "reader"
actions = []
save_records = []
await reader(false)
json_file(role + "-actions.json", {"setup": "diagnostic", "input_method": input_method, "actions": actions})
finish_observations()
runtime.command_completed.disconnect(observe)
runtime.save_operation_completed.disconnect(record_save_operation)
var cleanup: Dictionary = await Cleanup.free_owner_and_wait(tree, main)
expect(cleanup.get(&"passed", false), "ordinary Main/audio cleanup")
json_file(role + "-process.json", {"pid": OS.get_process_id(), "engine": Engine.get_version_info(), "checks": checks, "failures": failures, "role": requested_role, "setup": "diagnostic"})
@@ -296,18 +306,78 @@ func setup() -> void:
clock.set_paused(true)
tree.root.size = Vector2i(1440, 810)
main = load("res://scenes/main/main.tscn").instantiate()
main.manual_save_path = directory.path_join("formal")
main.manual_save_path = "user://saves/manual_ui"
if role == "reader":
import_package(directory.path_join("formal"), String(main.manual_save_path))
tree.root.add_child(main)
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
func save_initial_fixture() -> void:
# Explicit diagnostic input, not an OS action or natural-play save.
var saved: Dictionary = SaveService.save_snapshot(directory.path_join("initial-formal"), runtime.create_snapshot())
var saved: Dictionary = SaveService.save_snapshot(INITIAL_SAVE, runtime.create_snapshot())
record_save_result("initial_save", INITIAL_SAVE, saved)
expect(bool(saved.get("ok", false)), "diagnostic initial formal save")
export_package(INITIAL_SAVE, "initial-formal")
# Seed the private normal slot, so its later normal save produces a backup.
import_package(ProjectSettings.globalize_path(INITIAL_SAVE), String(main.manual_save_path))
json_file("diagnostic-budget.json", budget)
func archive_formal() -> void:
pass
export_package(String(main.manual_save_path), "formal")
func record_save_operation(result: Dictionary) -> void:
record_save_result("runtime_operation", String(main.manual_save_path), result)
func record_save_result(operation: String, path: String, result: Dictionary) -> void:
save_serial += 1
var stem := "%s-save-result-%04d" % [role, save_serial]
var raw := FileAccess.open(directory.path_join(stem + ".var"), FileAccess.WRITE)
expect(raw != null, "raw save result")
if raw != null:
raw.store_buffer(var_to_bytes(result))
raw.close()
json_file(stem + ".json", {"pid": OS.get_process_id(), "operation": operation,
"requested_path": path, "absolute_path": ProjectSettings.globalize_path(path),
"user_data_dir": OS.get_user_data_dir(), "result": Codec.new().typed(result),
"raw_sha256": FileAccess.get_sha256(directory.path_join(stem + ".var"))})
save_records.append(stem)
json_file(role + "-save-results.json", {"pid": OS.get_process_id(), "records": save_records})
func import_package(source: String, destination: String) -> void:
var absolute := ProjectSettings.globalize_path(destination)
expect(DirAccess.make_dir_recursive_absolute(absolute) == OK, "private save directory")
for member: String in MEMBERS:
var origin := source.path_join(member)
var copy := absolute.path_join(member)
expect(DirAccess.copy_absolute(origin, copy) == OK, "private save input " + member)
expect(FileAccess.get_sha256(origin) == FileAccess.get_sha256(copy), "private save input SHA " + member)
func export_package(path: String, name: String) -> void:
var absolute := ProjectSettings.globalize_path(path)
var pins := {}
for suffix: String in ["", ".bak"]:
var source := absolute + suffix
var present := DirAccess.dir_exists_absolute(source)
pins[name + suffix] = {"source_path": source, "present": present, "members": {}}
if not present:
expect(not suffix.is_empty(), "formal package exists")
continue
var destination := directory.path_join(name + suffix)
expect(DirAccess.make_dir_recursive_absolute(destination) == OK, "export directory")
for member: String in MEMBERS:
var origin := source.path_join(member)
var copy := destination.path_join(member)
expect(DirAccess.copy_absolute(origin, copy) == OK, "export " + member)
var digest := FileAccess.get_sha256(origin)
expect(not digest.is_empty() and digest == FileAccess.get_sha256(copy), "export SHA " + member)
pins[name + suffix]["members"][member] = {"sha256": digest, "bytes": FileAccess.get_file_as_bytes(copy).size()}
# Slot metadata lives in the existing manifest; copy it verbatim.
var metadata := absolute.path_join("manifest.json")
var metadata_copy := directory.path_join(name + "-slot-metadata.json")
expect(DirAccess.copy_absolute(metadata, metadata_copy) == OK, "slot metadata export")
json_file(name + "-export.json", {"pid": OS.get_process_id(), "requested_path": path,
"absolute_path": absolute, "user_data_dir": OS.get_user_data_dir(), "packages": pins,
"slot_metadata": {"file": name + "-slot-metadata.json", "sha256": FileAccess.get_sha256(metadata_copy)}})
func finish_observations() -> void:
pass