class_name SimulationStateRecord extends RefCounted const SCHEMA_NAME := "the_steward.simulation" const SCHEMA_VERSION := 1 var simulation: Dictionary var village: VillageStateRecord var npcs: Array[NPCStateRecord] = [] var resources: Array[ResourceStateRecord] = [] func to_dictionary() -> Dictionary: var npc_data: Array[Dictionary] = [] for npc_record in npcs: npc_data.append(npc_record.to_dictionary()) var resource_data: Array[Dictionary] = [] for resource_record in resources: resource_data.append(resource_record.to_dictionary()) return { "schema": SCHEMA_NAME, "schema_version": SCHEMA_VERSION, "simulation": simulation.duplicate(true), "village": village.to_dictionary(), "npcs": npc_data, "resources": resource_data } func to_json() -> String: return JSON.stringify(to_dictionary()) static func from_json(json_text: String) -> SimulationStateRecord: var parsed = JSON.parse_string(json_text) if not parsed is Dictionary: return null return from_dictionary(parsed) static func from_dictionary(record_data: Dictionary) -> SimulationStateRecord: if record_data.get("schema", "") != SCHEMA_NAME: return null if int(record_data.get("schema_version", -1)) != SCHEMA_VERSION: return null if not record_data.has_all([ "simulation", "village", "npcs", "resources" ]): return null var simulation_data = record_data["simulation"] if not simulation_data is Dictionary: return null if not simulation_data.has_all([ "seed", "tick_interval", "tick_count", "clock_accumulator", "clock_elapsed_ticks", "wander_random_streams" ]): return null var wander_streams = simulation_data["wander_random_streams"] if not wander_streams is Array: return null for stream_data in wander_streams: if not stream_data is Dictionary: return null if not stream_data.has_all(["npc_id", "seed", "state"]): return null var village_data = record_data["village"] if not village_data is Dictionary: return null var village_record := VillageStateRecord.from_dictionary(village_data) if village_record == null: return null var npc_data = record_data["npcs"] var resource_data = record_data["resources"] if not npc_data is Array or not resource_data is Array: return null var record := SimulationStateRecord.new() record.simulation = simulation_data.duplicate(true) record.village = village_record var npc_ids := {} for item in npc_data: if not item is Dictionary: return null var npc_record := NPCStateRecord.from_dictionary(item) if npc_record == null: return null var npc_id := int(npc_record.data["id"]) if npc_ids.has(npc_id): return null npc_ids[npc_id] = true record.npcs.append(npc_record) var resource_ids := {} for item in resource_data: if not item is Dictionary: return null var resource_record := ResourceStateRecord.from_dictionary(item) if resource_record == null: return null var resource_id := String(resource_record.data["node_id"]) if resource_ids.has(resource_id): return null resource_ids[resource_id] = true record.resources.append(resource_record) return record