P24-03: 選択と保存の受入
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
extends SceneTree
|
||||
|
||||
## Passive observer: no selection, save/load, command or engine input injection.
|
||||
## Runner launches separate owned processes with private user-data directories.
|
||||
var _main: Control
|
||||
var _elapsed := 0.0
|
||||
var _last := ""
|
||||
var _sequence := 0
|
||||
var _output := ""
|
||||
var _source_map: Dictionary = {}
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_start")
|
||||
|
||||
func _start() -> void:
|
||||
_output = OS.get_environment("P24_OBSERVER_OUTPUT")
|
||||
var pins := OS.get_environment("P24_OBSERVER_SOURCE_MAP")
|
||||
if not _output.is_absolute_path() or not DirAccess.dir_exists_absolute(_output) or not pins.is_absolute_path():
|
||||
push_error("P24 observer requires existing absolute output directory and source-map JSON")
|
||||
quit(1)
|
||||
return
|
||||
var parsed: Variant = JSON.parse_string(FileAccess.get_file_as_string(pins))
|
||||
if not parsed is Dictionary or parsed.is_empty():
|
||||
push_error("P24 observer source map missing")
|
||||
quit(1)
|
||||
return
|
||||
_source_map = parsed
|
||||
root.size = Vector2i(1440, 810)
|
||||
_main = load("res://scenes/main/main.tscn").instantiate()
|
||||
root.add_child(_main)
|
||||
print("P24_PROCESS pid=%d scene=res://scenes/main/main.tscn" % OS.get_process_id())
|
||||
# Use the ordinary Main pause control through OS input when a frozen state
|
||||
# is needed. The observer itself never changes Runtime or Clock.
|
||||
|
||||
func _process(delta: float) -> bool:
|
||||
_elapsed += delta
|
||||
if _elapsed >= 1.0 and is_instance_valid(_main):
|
||||
_elapsed = 0.0
|
||||
_capture()
|
||||
return false
|
||||
|
||||
func _capture() -> void:
|
||||
var runtime: Variant = root.get_node("SimulationRuntime")
|
||||
var selection: Dictionary = _main.call("_capture_interface_selection")
|
||||
var facility_id := StringName(selection.get("id", ""))
|
||||
var facility: Variant = runtime.facility_service.get_instance(facility_id)
|
||||
var guest_panel: GuestObservationPanel
|
||||
var dialog: Variant = _main.get("guest_observer")
|
||||
if dialog != null:
|
||||
guest_panel = dialog.find_child("GuestObservationPanel", true, false) as GuestObservationPanel
|
||||
var staff_panel: StaffManagementPanel = _main.get("staff_management_panel")
|
||||
var staff_model: Dictionary = {}
|
||||
for row: Dictionary in runtime.get_staff_management_report().get(&"staff", []):
|
||||
if String(row.get(&"staff_id", "")) == String(selection.get("staff_id", "")):
|
||||
staff_model = row.duplicate(true)
|
||||
var needs: Dictionary = {}
|
||||
if guest_panel != null:
|
||||
for need: StringName in guest_panel.bars:
|
||||
needs[need] = guest_panel.bars[need].value
|
||||
var observation := {
|
||||
"interface_selection": selection,
|
||||
"layer": root.get_node("GameState").get("active_layer"),
|
||||
"facility": {"id": String(facility_id), "model_snapshot": facility.create_snapshot() if facility != null else {},
|
||||
"heading_text": _main.get("selected_heading_label").text,
|
||||
"detail_text": _main.get("selected_detail_label").text,
|
||||
"highlight_id": String(_main.get("world_preview").get("selected_entity_id"))},
|
||||
"guest": {"id": selection.get("guest_id", ""),
|
||||
"model_report": runtime.guest_service.get_observation(StringName(selection.get("guest_id", ""))),
|
||||
"detail_text": guest_panel.details.text if guest_panel != null else "",
|
||||
"priority_text": guest_panel.priority_label.text if guest_panel != null else "",
|
||||
"decision_text": guest_panel.decision_label.text if guest_panel != null else "", "need_bars": needs},
|
||||
"staff": {"id": selection.get("staff_id", ""), "model_report": staff_model,
|
||||
"detail_text": staff_panel.staff_detail_label.text,
|
||||
"editor_visible": staff_panel.editor_panel.is_visible_in_tree()},
|
||||
}
|
||||
var encoded := JSON.stringify(observation, "", true)
|
||||
if encoded == _last:
|
||||
return
|
||||
_sequence += 1
|
||||
var stem := "process-%d-observation-%d" % [OS.get_process_id(), _sequence]
|
||||
var report_path := _output.path_join(stem + ".json")
|
||||
var frame_path := _output.path_join(stem + ".png")
|
||||
if FileAccess.file_exists(report_path) or FileAccess.file_exists(frame_path):
|
||||
push_error("P24 observer refuses artifact overwrite")
|
||||
return
|
||||
var image := root.get_texture().get_image()
|
||||
if image.save_png(frame_path) != OK:
|
||||
push_error("P24 observer frame capture failed")
|
||||
return
|
||||
var file := FileAccess.open(report_path, FileAccess.WRITE)
|
||||
if file == null:
|
||||
push_error("P24 observer report write failed")
|
||||
return
|
||||
file.store_string(JSON.stringify({"pid": OS.get_process_id(), "source_map": _source_map,
|
||||
"scene": "res://scenes/main/main.tscn", "ticks_usec": Time.get_ticks_usec(),
|
||||
"raw_observation": observation, "screenshot": stem + ".png",
|
||||
"formal_acceptance": false}, "\t", true) + "\n")
|
||||
file.close()
|
||||
_last = encoded
|
||||
print("P24_RAW_OBSERVATION " + encoded)
|
||||
@@ -0,0 +1 @@
|
||||
uid://d24crossproc
|
||||
@@ -27,6 +27,22 @@ func _run() -> void:
|
||||
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
|
||||
await process_frame
|
||||
await process_frame
|
||||
# Build before intentionally preserving departed payroll debt.
|
||||
var build_result: Variant = runtime.submit_command(&"build_facility", {&"definition_id": &"reception", &"origin": Vector3i(-8, 0, 0)})
|
||||
_expect(build_result.is_success(), "real facility construction starts: " + str(build_result.to_dictionary()))
|
||||
clock.advance_minutes(120)
|
||||
var facilities: Array = runtime.construction_service.get_facilities()
|
||||
_expect(not facilities.is_empty(), "real facility construction completes")
|
||||
if not facilities.is_empty():
|
||||
var facility_id := StringName(facilities[0][&"instance_id"])
|
||||
main.call("_on_facility_selected", facility_id)
|
||||
main.get("world_preview").set("selected_entity_id", facility_id)
|
||||
var previous_detail: String = main.get("selected_detail_label").text
|
||||
_expect(main.get("_selected_entity_id") == facility_id, "select existing built facility")
|
||||
_expect(runtime.submit_command(&"demolish_facility", {&"instance_id": facility_id}).is_success(), "real facility demolition commits")
|
||||
main.call("_refresh_selected_entity")
|
||||
_expect(main.get("_selected_entity_id") == &"" and main.get("_selected_entity_kind") == &"" and main.get("world_preview").get("selected_entity_id") == &"", "actual demolition clears ID kind and map highlight")
|
||||
_expect(main.get("selected_entity_icon").texture == null and main.get("selected_detail_label").text != previous_detail, "actual demolition clears icon and stale detail")
|
||||
var guest: GuestObservationPanel = main.call("_ensure_guest_observer")
|
||||
var definition: GuestDefinition = runtime.guest_service.get_definitions()[0]
|
||||
_expect(runtime.submit_command(&"spawn_guest", {&"guest_id": &"departure_guest", &"guest_type_id": definition.guest_type_id, &"gold": 731, &"options": {&"planned_exit_at": clock.absolute_minute + 1000}}).is_success(), "spawn actual guest")
|
||||
@@ -75,21 +91,6 @@ func _run() -> void:
|
||||
for version: Variant in [true, 1.5, "1", 0, 2]:
|
||||
main.call("_restore_actor_interface_selection", {"interface_selection": {"version": version, "staff_id": "departure_unique", "staff_open": true}})
|
||||
_expect(staff.selected_staff_id.is_empty() and not staff.visible, "wrong/old metadata version is ignored: " + str(version))
|
||||
var build_result: Variant = runtime.submit_command(&"build_facility", {&"definition_id": &"reception", &"origin": Vector3i(-8, 0, 0)})
|
||||
_expect(build_result.is_success(), "real facility construction starts: " + str(build_result))
|
||||
clock.advance_minutes(120)
|
||||
var facilities: Array = runtime.construction_service.get_facilities()
|
||||
_expect(not facilities.is_empty(), "real facility construction completes")
|
||||
if not facilities.is_empty():
|
||||
var facility_id := StringName(facilities[0][&"instance_id"])
|
||||
main.call("_on_facility_selected", facility_id)
|
||||
main.get("world_preview").set("selected_entity_id", facility_id)
|
||||
var previous_detail: String = main.get("selected_detail_label").text
|
||||
_expect(main.get("_selected_entity_id") == facility_id, "select existing built facility")
|
||||
_expect(runtime.submit_command(&"demolish_facility", {&"instance_id": facility_id}).is_success(), "real facility demolition commits")
|
||||
main.call("_refresh_selected_entity")
|
||||
_expect(main.get("_selected_entity_id") == &"" and main.get("_selected_entity_kind") == &"" and main.get("world_preview").get("selected_entity_id") == &"", "actual demolition clears ID kind and map highlight")
|
||||
_expect(main.get("selected_entity_icon").texture == null and main.get("selected_detail_label").text != previous_detail, "actual demolition clears icon and stale detail")
|
||||
var original: String = OS.get_environment("THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF")
|
||||
if original.is_empty() or not original.is_absolute_path():
|
||||
_expect(false, "Runner must provide fresh absolute ordinary control proof")
|
||||
|
||||
Reference in New Issue
Block a user