class_name EventInstance extends RefCounted enum State { QUEUED, RUNNING, WAITING_CHOICE, COMPLETED, CANCELLED, EXPIRED, ERROR, INTERRUPTED, } var event_instance_id: StringName = &"" var source_event_id: StringName = &"" var resolved_event_id: StringName = &"" var actor_ids: Array[StringName] = [] var priority := 0 var created_at := 0 var expires_at := -1 var foreground := true var state: State = State.QUEUED var deduplication_key: StringName = &"" var context: Dictionary = {} var presentation_mode: StringName = &"FULL" var choice_instance_id: StringName = &"" var selected_choice_id: StringName = &"" var reserved_costs: Dictionary = {} var failure_reason := "" var retry_count := 0 func configure( p_instance_id: StringName, p_source_event_id: StringName, p_resolved_event_id: StringName, p_actor_ids: Array, p_priority: int, p_created_at: int, p_expires_at: int, p_foreground: bool, p_deduplication_key: StringName, p_context: Dictionary = {}, presentation: StringName = &"FULL" ) -> EventInstance: event_instance_id = p_instance_id source_event_id = p_source_event_id resolved_event_id = p_resolved_event_id actor_ids = _sorted_unique_names(p_actor_ids) priority = p_priority created_at = maxi(p_created_at, 0) expires_at = p_expires_at foreground = p_foreground deduplication_key = p_deduplication_key context = p_context.duplicate(true) presentation_mode = presentation return self func is_valid() -> bool: if event_instance_id.is_empty() or source_event_id.is_empty() or resolved_event_id.is_empty(): return false if created_at < 0 or (expires_at >= 0 and expires_at < created_at): return false if state < State.QUEUED or state > State.INTERRUPTED: return false return true func is_terminal() -> bool: return state in [State.COMPLETED, State.CANCELLED, State.EXPIRED, State.ERROR] func create_snapshot() -> Dictionary: return { &"event_instance_id": String(event_instance_id), &"source_event_id": String(source_event_id), &"resolved_event_id": String(resolved_event_id), &"actor_ids": _names_to_strings(actor_ids), &"priority": priority, &"created_at": created_at, &"expires_at": expires_at, &"foreground": foreground, &"state": State.keys()[state], &"deduplication_key": String(deduplication_key), &"context": context.duplicate(true), &"presentation_mode": String(presentation_mode), &"choice_instance_id": String(choice_instance_id), &"selected_choice_id": String(selected_choice_id), &"reserved_costs": reserved_costs.duplicate(true), &"failure_reason": failure_reason, &"retry_count": retry_count, } static func from_snapshot(snapshot: Dictionary) -> EventInstance: var instance := EventInstance.new().configure( StringName(_value(snapshot, &"event_instance_id", &"")), StringName(_value(snapshot, &"source_event_id", &"")), StringName(_value(snapshot, &"resolved_event_id", &"")), _array(_value(snapshot, &"actor_ids", [])), int(_value(snapshot, &"priority", 0)), int(_value(snapshot, &"created_at", 0)), int(_value(snapshot, &"expires_at", -1)), bool(_value(snapshot, &"foreground", true)), StringName(_value(snapshot, &"deduplication_key", &"")), _dictionary(_value(snapshot, &"context", {})), StringName(_value(snapshot, &"presentation_mode", &"FULL")) ) var state_name := String(_value(snapshot, &"state", "QUEUED")).to_upper() var state_index := State.keys().find(state_name) instance.state = (state_index if state_index >= 0 else State.ERROR) as State instance.choice_instance_id = StringName(_value(snapshot, &"choice_instance_id", &"")) instance.selected_choice_id = StringName(_value(snapshot, &"selected_choice_id", &"")) instance.reserved_costs = _dictionary(_value(snapshot, &"reserved_costs", {})).duplicate(true) instance.failure_reason = String(_value(snapshot, &"failure_reason", "")) instance.retry_count = maxi(int(_value(snapshot, &"retry_count", 0)), 0) return instance static func _sorted_unique_names(raw_value: Variant) -> Array[StringName]: var result: Array[StringName] = [] if raw_value is Array: for raw_entry: Variant in raw_value: var entry := StringName(raw_entry) if not entry.is_empty() and not result.has(entry): result.append(entry) result.sort_custom(func(a: StringName, b: StringName) -> bool: return String(a) < String(b)) return result static func _names_to_strings(values: Array[StringName]) -> Array[String]: var result: Array[String] = [] for value: StringName in values: result.append(String(value)) return result static func _value(source: Dictionary, key: StringName, fallback: Variant) -> Variant: if source.has(key): return source[key] return source.get(String(key), fallback) static func _array(value: Variant) -> Array: return value if value is Array else [] static func _dictionary(value: Variant) -> Dictionary: return value if value is Dictionary else {}