224 lines
7.9 KiB
GDScript
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
|