Files
aetherbound-guild/runtime/p9_9/profile_state.gd
T

224 lines
7.9 KiB
GDScript

class_name P99ProfileState
extends RefCounted
const P98State = preload("res://p9_8/contract_state.gd")
const Content = preload("res://content/p9_9_content.gd")
const CLEAR_ID := "CLEAR-RG01-C01"
const RECORD_ID := "RECORD-RG01-C01"
const RECONCILIATION_ID := "P99-RENOWN-RG01-C01"
const CANONICAL_RENOWN := 14
var revision := 0
var p99_activated := false
var content_revision := ""
var content_hash := ""
var persistent_renown := 0
var contract_clear_ids: Array[String] = []
var discovery_ids: Array[String] = []
var company_records: Array[Dictionary] = []
var renown_reconciliation_receipts: Array[Dictionary] = []
var charter_claim_ids: Array[String] = []
var charter_claim_receipts: Array[Dictionary] = []
var selected_charter_claim_id := ""
var active_region_id := "RG-01"
var operation_receipts: Dictionary = {}
func initialize_from_p98(raw: Dictionary) -> bool:
var prior = P98State.new()
if not prior.restore_snapshot(raw):
return false
if not prior.p98_activated or not prior.run_closed or int(prior.contract_phase) != P98State.ContractPhase.RUN_CLOSED:
return false
if CLEAR_ID not in prior.contract_clear_ids or prior.company_records.is_empty():
return false
var record: Dictionary = prior.company_records[-1]
if String(record.get("id", "")) != RECORD_ID or String(record.get("clear_id", "")) != CLEAR_ID:
return false
var content: Dictionary = Content.snapshot()
if not Content.validate(content).ok:
return false
revision = int(prior.revision) + 1
p99_activated = true
content_revision = String(content.revision)
content_hash = String(content.content_hash)
persistent_renown = int(prior.persistent_renown)
contract_clear_ids.assign(prior.contract_clear_ids)
discovery_ids.assign(prior.discovery_ids)
company_records.assign(prior.company_records)
renown_reconciliation_receipts.clear()
if persistent_renown == 3:
renown_reconciliation_receipts.append({
"id": RECONCILIATION_ID,
"source_clear_id": CLEAR_ID,
"renown_before": 3,
"renown_delta": 11,
"renown_after": CANONICAL_RENOWN,
})
persistent_renown = CANONICAL_RENOWN
elif persistent_renown != CANONICAL_RENOWN:
_reset()
return false
charter_claim_ids.clear()
charter_claim_receipts.clear()
selected_charter_claim_id = ""
active_region_id = "RG-01"
operation_receipts.clear()
return invariants_hold()
func snapshot() -> Dictionary:
return {
"revision": revision,
"p99_activated": p99_activated,
"content_revision": content_revision,
"content_hash": content_hash,
"persistent_renown": persistent_renown,
"contract_clear_ids": contract_clear_ids.duplicate(),
"discovery_ids": discovery_ids.duplicate(),
"company_records": company_records.duplicate(true),
"renown_reconciliation_receipts": renown_reconciliation_receipts.duplicate(true),
"charter_claim_ids": charter_claim_ids.duplicate(),
"charter_claim_receipts": charter_claim_receipts.duplicate(true),
"selected_charter_claim_id": selected_charter_claim_id,
"active_region_id": active_region_id,
"operation_receipts": operation_receipts.duplicate(true),
}.duplicate(true)
func restore_snapshot(raw: Dictionary) -> bool:
var normalized_value = JSON.parse_string(JSON.stringify(raw))
if not normalized_value is Dictionary:
return false
var normalized: Dictionary = _normalize_serialized(normalized_value)
var required := [
"revision", "p99_activated", "content_revision", "content_hash",
"persistent_renown", "contract_clear_ids", "discovery_ids",
"company_records", "renown_reconciliation_receipts",
"charter_claim_ids", "charter_claim_receipts",
"selected_charter_claim_id", "active_region_id", "operation_receipts",
]
for key in required:
if not normalized.has(key):
return false
var before := snapshot()
if not _assign(normalized) or not invariants_hold():
_assign(before)
return false
return true
func _normalize_serialized(value: Variant) -> Variant:
if value is float:
return int(value) if is_finite(value) and value == floor(value) else value
if value is Array:
var normalized_array: Array = []
for item in value:
normalized_array.append(_normalize_serialized(item))
return normalized_array
if value is Dictionary:
var normalized_dictionary := {}
for key in value:
normalized_dictionary[key] = _normalize_serialized(value[key])
return normalized_dictionary
return value
func invariants_hold() -> bool:
if not p99_activated or revision < 0 or active_region_id != "RG-01":
return false
var content: Dictionary = Content.snapshot()
if content_revision != String(content.revision) or content_hash != String(content.content_hash):
return false
if CLEAR_ID not in contract_clear_ids or not _unique(contract_clear_ids) or not _unique(discovery_ids):
return false
if company_records.is_empty() or String(company_records[-1].get("id", "")) != RECORD_ID:
return false
if renown_reconciliation_receipts.size() > 1 or charter_claim_ids.size() > 1 or charter_claim_receipts.size() > 1:
return false
if not renown_reconciliation_receipts.is_empty():
var reconciliation: Dictionary = renown_reconciliation_receipts[0]
if String(reconciliation.get("id", "")) != RECONCILIATION_ID:
return false
if String(reconciliation.get("source_clear_id", "")) != CLEAR_ID:
return false
if int(reconciliation.get("renown_before", -1)) != 3 or int(reconciliation.get("renown_delta", -1)) != 11:
return false
if int(reconciliation.get("renown_after", -1)) != CANONICAL_RENOWN:
return false
var spent := 0
for claim_id in charter_claim_ids:
if not content.charter_claims.has(claim_id):
return false
spent += int(content.charter_claims[claim_id].renown_cost)
if persistent_renown != CANONICAL_RENOWN - spent:
return false
if charter_claim_ids.is_empty():
if not selected_charter_claim_id.is_empty() or not charter_claim_receipts.is_empty():
return false
else:
if selected_charter_claim_id != charter_claim_ids[0] or charter_claim_receipts.size() != 1:
return false
var receipt: Dictionary = charter_claim_receipts[0]
if String(receipt.get("claim_id", "")) != selected_charter_claim_id:
return false
if int(receipt.get("renown_after", -1)) != persistent_renown:
return false
for operation_id in operation_receipts:
var operation = operation_receipts[operation_id]
if String(operation_id).is_empty() or not operation is Dictionary:
return false
if String(operation.get("intent_hash", "")).length() != 64 or not operation.get("result", {}) is Dictionary:
return false
return true
func _assign(raw: Dictionary) -> bool:
for key in ["contract_clear_ids", "discovery_ids", "company_records", "renown_reconciliation_receipts", "charter_claim_ids", "charter_claim_receipts"]:
if not raw.get(key) is Array:
return false
if not raw.get("operation_receipts") is Dictionary:
return false
revision = int(raw.revision)
p99_activated = bool(raw.p99_activated)
content_revision = String(raw.content_revision)
content_hash = String(raw.content_hash)
persistent_renown = int(raw.persistent_renown)
contract_clear_ids.assign(raw.contract_clear_ids)
discovery_ids.assign(raw.discovery_ids)
company_records.assign(raw.company_records)
renown_reconciliation_receipts.assign(raw.renown_reconciliation_receipts)
charter_claim_ids.assign(raw.charter_claim_ids)
charter_claim_receipts.assign(raw.charter_claim_receipts)
selected_charter_claim_id = String(raw.selected_charter_claim_id)
active_region_id = String(raw.active_region_id)
operation_receipts = Dictionary(raw.operation_receipts).duplicate(true)
return true
func _reset() -> void:
revision = 0
p99_activated = false
content_revision = ""
content_hash = ""
persistent_renown = 0
contract_clear_ids.clear()
discovery_ids.clear()
company_records.clear()
renown_reconciliation_receipts.clear()
charter_claim_ids.clear()
charter_claim_receipts.clear()
selected_charter_claim_id = ""
active_region_id = "RG-01"
operation_receipts.clear()
func _unique(values: Array[String]) -> bool:
var seen := {}
for value in values:
if value.is_empty() or seen.has(value):
return false
seen[value] = true
return true