feat: define authoritative action effects
This commit is contained in:
@@ -2,33 +2,38 @@ class_name ActionCommand
|
||||
extends RefCounted
|
||||
|
||||
var _command_id: StringName
|
||||
var _actor_id: StringName
|
||||
var _actor: WorldEntityRef
|
||||
var _action_id: StringName
|
||||
var _target: WorldTargetHandle
|
||||
var _parameters: Dictionary
|
||||
var _expected_state_revision: int
|
||||
|
||||
|
||||
func _init(
|
||||
command_id: StringName = &"",
|
||||
actor_id: StringName = &"",
|
||||
actor: Variant = null,
|
||||
action_id: StringName = &"",
|
||||
target: WorldTargetHandle = null,
|
||||
parameters: Dictionary = {}
|
||||
parameters: Dictionary = {},
|
||||
expected_state_revision: int = -1
|
||||
) -> void:
|
||||
_command_id = command_id
|
||||
_actor_id = actor_id
|
||||
_actor = _normalize_actor(actor)
|
||||
_action_id = action_id
|
||||
_target = target
|
||||
_parameters = parameters.duplicate(true)
|
||||
_expected_state_revision = expected_state_revision
|
||||
|
||||
|
||||
func is_valid() -> bool:
|
||||
return (
|
||||
not _command_id.is_empty()
|
||||
and not _actor_id.is_empty()
|
||||
and _actor != null
|
||||
and _actor.is_valid()
|
||||
and not _action_id.is_empty()
|
||||
and _target != null
|
||||
and _target.is_well_formed()
|
||||
and _expected_state_revision >= -1
|
||||
and not WorldTargetCapability._contains_object(_parameters)
|
||||
)
|
||||
|
||||
@@ -38,7 +43,11 @@ func get_command_id() -> StringName:
|
||||
|
||||
|
||||
func get_actor_id() -> StringName:
|
||||
return _actor_id
|
||||
return _actor.get_entity_id() if _actor != null else &""
|
||||
|
||||
|
||||
func get_actor() -> WorldEntityRef:
|
||||
return _actor.duplicate_ref() if _actor != null else null
|
||||
|
||||
|
||||
func get_action_id() -> StringName:
|
||||
@@ -51,3 +60,15 @@ func get_target() -> WorldTargetHandle:
|
||||
|
||||
func get_parameters() -> Dictionary:
|
||||
return _parameters.duplicate(true)
|
||||
|
||||
|
||||
func get_expected_state_revision() -> int:
|
||||
return _expected_state_revision
|
||||
|
||||
|
||||
static func _normalize_actor(actor: Variant) -> WorldEntityRef:
|
||||
if actor is WorldEntityRef:
|
||||
return (actor as WorldEntityRef).duplicate_ref()
|
||||
if actor is StringName or actor is String:
|
||||
return WorldEntityRef.create(SimulationIds.ENTITY_PERSON, StringName(actor))
|
||||
return null
|
||||
|
||||
@@ -6,5 +6,9 @@ signal command_resolved(result: ActionResult)
|
||||
|
||||
# Implementations must resolve the transient target handle and revalidate every
|
||||
# precondition. An earlier ActionOffer never grants authority by itself.
|
||||
func submit_command(_command: ActionCommand) -> ActionResult:
|
||||
func try_execute(_command: ActionCommand) -> ActionResult:
|
||||
return null
|
||||
|
||||
|
||||
func submit_command(command: ActionCommand) -> ActionResult:
|
||||
return try_execute(command)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
class_name ActionEffect
|
||||
extends Resource
|
||||
|
||||
const KIND_METRIC_DELTA := &"metric_delta"
|
||||
const KIND_NEED_DELTA := &"need_delta"
|
||||
const KIND_INVENTORY_TRANSFER := &"inventory_transfer"
|
||||
const KIND_DAMAGE := &"damage"
|
||||
const KIND_HEALING := &"healing"
|
||||
const KIND_RELATIONSHIP_DELTA := &"relationship_delta"
|
||||
const KIND_SCHEDULE_ACTION := &"schedule_action"
|
||||
const KIND_SITE_CONDITION := &"site_condition"
|
||||
const VALID_KINDS := [
|
||||
KIND_METRIC_DELTA,
|
||||
KIND_NEED_DELTA,
|
||||
KIND_INVENTORY_TRANSFER,
|
||||
KIND_DAMAGE,
|
||||
KIND_HEALING,
|
||||
KIND_RELATIONSHIP_DELTA,
|
||||
KIND_SCHEDULE_ACTION,
|
||||
KIND_SITE_CONDITION,
|
||||
]
|
||||
|
||||
@export var effect_id: StringName
|
||||
@export var effect_kind: StringName
|
||||
@export var subject_key: StringName
|
||||
@export var value := 0.0
|
||||
@export var item_id: StringName
|
||||
@export var amount := 0.0
|
||||
@export var source_role: StringName
|
||||
@export var destination_role: StringName
|
||||
@export var scheduled_action_id: StringName
|
||||
@export var parameters: Dictionary = {}
|
||||
|
||||
|
||||
func validate() -> Array[String]:
|
||||
var errors: Array[String] = []
|
||||
if effect_id.is_empty():
|
||||
errors.append("effect_id is empty")
|
||||
if effect_kind not in VALID_KINDS:
|
||||
errors.append("effect_kind '%s' is invalid for '%s'" % [effect_kind, effect_id])
|
||||
if not is_finite(value) or not is_finite(amount):
|
||||
errors.append("numeric values must be finite for '%s'" % effect_id)
|
||||
match effect_kind:
|
||||
KIND_METRIC_DELTA, KIND_NEED_DELTA, KIND_RELATIONSHIP_DELTA, KIND_SITE_CONDITION:
|
||||
if subject_key.is_empty():
|
||||
errors.append("subject_key is empty for '%s'" % effect_id)
|
||||
KIND_INVENTORY_TRANSFER:
|
||||
if item_id.is_empty() or amount <= 0.0:
|
||||
errors.append(
|
||||
"inventory transfer '%s' needs an item and positive amount" % effect_id
|
||||
)
|
||||
if source_role.is_empty() or destination_role.is_empty():
|
||||
errors.append("inventory transfer '%s' needs source/destination roles" % effect_id)
|
||||
KIND_DAMAGE, KIND_HEALING:
|
||||
if amount <= 0.0:
|
||||
errors.append("effect '%s' needs a positive amount" % effect_id)
|
||||
KIND_SCHEDULE_ACTION:
|
||||
if scheduled_action_id.is_empty():
|
||||
errors.append("scheduled action is empty for '%s'" % effect_id)
|
||||
if WorldTargetCapability._contains_object(parameters):
|
||||
errors.append("parameters contain a runtime object for '%s'" % effect_id)
|
||||
return errors
|
||||
@@ -0,0 +1 @@
|
||||
uid://c7wc7p30s3fsw
|
||||
@@ -4,5 +4,9 @@ extends RefCounted
|
||||
|
||||
# Offers are advisory presentation values. Implementations must not mutate
|
||||
# authoritative state while answering this query.
|
||||
func get_action_offers(_actor_id: StringName, _target: WorldTargetHandle) -> Array[ActionOffer]:
|
||||
func get_offers(_actor: WorldEntityRef, _target: WorldTargetHandle) -> Array[ActionOffer]:
|
||||
return []
|
||||
|
||||
|
||||
func get_action_offers(actor_id: StringName, target: WorldTargetHandle) -> Array[ActionOffer]:
|
||||
return get_offers(WorldEntityRef.create(SimulationIds.ENTITY_PERSON, actor_id), target)
|
||||
|
||||
Reference in New Issue
Block a user