Files
TheTree_mock/scripts/facility/service_instance.gd

233 lines
7.1 KiB
GDScript

class_name ServiceInstance
extends RefCounted
enum State {
ACTIVE,
PAUSED,
WAITING_FOR_STAFF,
COMPLETED,
FAILED,
CANCELLED,
}
const NO_DEADLINE := -1
var service_id: StringName = &""
var request_id: StringName = &""
var facility_id: StringName = &""
var started_at := 0
var finish_at := 1
var guest_ids: Array[StringName] = []
var staff_ids: Array[StringName] = []
var quality_snapshot := 0
var price_snapshot := 0
var policy_snapshot: Dictionary = {}
var inventory_reservations: Array[StringName] = []
var interruption_policy: Dictionary = {}
var duration_minutes := 1
var elapsed_minutes := 0
var state: State = State.ACTIVE
var interruption_reason: StringName = &""
var interrupted_at := -1
var staff_grace_deadline := NO_DEADLINE
var completed_at := -1
var failure_reason: StringName = &""
func configure(
p_service_id: StringName,
p_request_id: StringName,
p_facility_id: StringName,
p_started_at: int,
p_duration_minutes: int,
p_guest_ids: Array[StringName],
p_staff_ids: Array[StringName],
options: Dictionary = {}
) -> ServiceInstance:
service_id = p_service_id
request_id = p_request_id
facility_id = p_facility_id
started_at = maxi(p_started_at, 0)
duration_minutes = maxi(p_duration_minutes, 1)
finish_at = started_at + duration_minutes
guest_ids.assign(p_guest_ids)
staff_ids.assign(p_staff_ids)
quality_snapshot = int(_value(options, &"quality_snapshot", 0))
price_snapshot = maxi(int(_value(options, &"price_snapshot", 0)), 0)
policy_snapshot = _dictionary_copy(_value(options, &"policy_snapshot", {}))
inventory_reservations = _string_name_array(
_value(options, &"inventory_reservations", [])
)
interruption_policy = _dictionary_copy(_value(options, &"interruption_policy", {}))
return self
func is_valid() -> bool:
return not service_id.is_empty() \
and not request_id.is_empty() \
and not facility_id.is_empty() \
and not guest_ids.is_empty() \
and duration_minutes > 0 \
and elapsed_minutes >= 0 \
and elapsed_minutes <= duration_minutes
func is_terminal() -> bool:
return state in [State.COMPLETED, State.FAILED, State.CANCELLED]
func can_progress() -> bool:
return state == State.ACTIVE and elapsed_minutes < duration_minutes
func advance_one_minute() -> bool:
if not can_progress():
return false
elapsed_minutes = mini(elapsed_minutes + 1, duration_minutes)
return elapsed_minutes >= duration_minutes
func pause(reason: StringName, absolute_minute: int) -> bool:
if state != State.ACTIVE:
return false
state = State.PAUSED
interruption_reason = reason
interrupted_at = absolute_minute
return true
func wait_for_staff(reason: StringName, absolute_minute: int, grace_minutes := 5) -> bool:
if state not in [State.ACTIVE, State.PAUSED]:
return false
state = State.WAITING_FOR_STAFF
interruption_reason = reason
interrupted_at = absolute_minute
staff_grace_deadline = absolute_minute + maxi(grace_minutes, 0)
return true
func resume() -> bool:
if state not in [State.PAUSED, State.WAITING_FOR_STAFF]:
return false
state = State.ACTIVE
interruption_reason = &""
interrupted_at = -1
staff_grace_deadline = NO_DEADLINE
return true
func mark_completed(absolute_minute: int) -> void:
elapsed_minutes = duration_minutes
state = State.COMPLETED
completed_at = absolute_minute
interruption_reason = &""
failure_reason = &""
staff_grace_deadline = NO_DEADLINE
func mark_failed(reason: StringName, absolute_minute: int) -> void:
state = State.FAILED
failure_reason = reason
completed_at = absolute_minute
staff_grace_deadline = NO_DEADLINE
func mark_cancelled(reason: StringName, absolute_minute: int) -> void:
state = State.CANCELLED
failure_reason = reason
completed_at = absolute_minute
staff_grace_deadline = NO_DEADLINE
func remaining_minutes() -> int:
return maxi(duration_minutes - elapsed_minutes, 0)
func create_snapshot() -> Dictionary:
return {
&"service_id": String(service_id),
&"request_id": String(request_id),
&"facility_id": String(facility_id),
&"started_at": started_at,
&"finish_at": finish_at,
&"guest_ids": _names_to_strings(guest_ids),
&"staff_ids": _names_to_strings(staff_ids),
&"quality_snapshot": quality_snapshot,
&"price_snapshot": price_snapshot,
&"policy_snapshot": policy_snapshot.duplicate(true),
&"inventory_reservations": _names_to_strings(inventory_reservations),
&"interruption_policy": interruption_policy.duplicate(true),
&"duration_minutes": duration_minutes,
&"elapsed_minutes": elapsed_minutes,
&"state": State.keys()[state],
&"interruption_reason": String(interruption_reason),
&"interrupted_at": interrupted_at,
&"staff_grace_deadline": staff_grace_deadline,
&"completed_at": completed_at,
&"failure_reason": String(failure_reason),
}
static func from_snapshot(snapshot: Dictionary) -> ServiceInstance:
if not snapshot.get(&"guest_ids", null) is Array:
return null
if not snapshot.get(&"staff_ids", null) is Array:
return null
if not snapshot.get(&"policy_snapshot", null) is Dictionary:
return null
if not snapshot.get(&"inventory_reservations", null) is Array:
return null
if not snapshot.get(&"interruption_policy", null) is Dictionary:
return null
var service := ServiceInstance.new().configure(
StringName(snapshot.get(&"service_id", "")),
StringName(snapshot.get(&"request_id", "")),
StringName(snapshot.get(&"facility_id", "")),
int(snapshot.get(&"started_at", 0)),
int(snapshot.get(&"duration_minutes", 1)),
_string_name_array(snapshot.get(&"guest_ids", [])),
_string_name_array(snapshot.get(&"staff_ids", [])),
{
&"quality_snapshot": snapshot.get(&"quality_snapshot", 0),
&"price_snapshot": snapshot.get(&"price_snapshot", 0),
&"policy_snapshot": snapshot.get(&"policy_snapshot", {}),
&"inventory_reservations": snapshot.get(&"inventory_reservations", []),
&"interruption_policy": snapshot.get(&"interruption_policy", {}),
}
)
var state_index := State.keys().find(String(snapshot.get(&"state", "ACTIVE")))
if state_index < 0:
return null
service.state = state_index as State
service.finish_at = int(snapshot.get(&"finish_at", service.started_at + service.duration_minutes))
service.elapsed_minutes = int(snapshot.get(&"elapsed_minutes", 0))
service.interruption_reason = StringName(snapshot.get(&"interruption_reason", ""))
service.interrupted_at = int(snapshot.get(&"interrupted_at", -1))
service.staff_grace_deadline = int(snapshot.get(&"staff_grace_deadline", NO_DEADLINE))
service.completed_at = int(snapshot.get(&"completed_at", -1))
service.failure_reason = StringName(snapshot.get(&"failure_reason", ""))
return service if service.is_valid() else null
static func _value(source: Dictionary, key: StringName, fallback: Variant) -> Variant:
return source.get(key, source.get(String(key), fallback))
static func _dictionary_copy(source: Variant) -> Dictionary:
return source.duplicate(true) if source is Dictionary else {}
static func _string_name_array(source: Variant) -> Array[StringName]:
var values: Array[StringName] = []
if source is Array:
for value: Variant in source:
values.append(StringName(value))
return values
static func _names_to_strings(source: Array[StringName]) -> Array[String]:
var values: Array[String] = []
for value: StringName in source:
values.append(String(value))
return values