feat: unify authored activity commands

This commit is contained in:
Rijad Zuzo
2026-08-13 00:08:30 +02:00
parent e5aecee0de
commit b3b98c6456
36 changed files with 3013 additions and 96 deletions
+78 -1
View File
@@ -1,5 +1,6 @@
class_name ContentCatalog
extends RefCounted
# gdlint: disable=max-file-lines
const CORE_PACK_PATH := "res://simulation/definitions/packs/core.tres"
const DEFAULT_SITUATION_EVENT_PREDICATE_IDS: Array[StringName] = [
@@ -11,6 +12,7 @@ const DEFAULT_SITUATION_STATE_PREDICATE_IDS: Array[StringName] = [
const DEFAULT_SITUATION_EXPIRY_PREDICATE_IDS: Array[StringName] = [
&"state_number_gt", &"age_reached"
]
const BUILTIN_HANDLER_IDS: Array[StringName] = [SimulationIds.ACTION_HANDLER_ACTIVITY_METRIC_DELTA]
var _valid := false
var _errors: Array[String] = []
@@ -81,11 +83,14 @@ func rebuild(
var pack_list := content_packs.duplicate()
pack_list.sort_custom(_sort_packs)
var supported_handlers := {}
for handler_id in BUILTIN_HANDLER_IDS:
supported_handlers[handler_id] = true
for handler_id in supported_handler_ids:
if handler_id.is_empty():
errors.append("Supported handler ID is empty")
elif supported_handlers.has(handler_id):
errors.append("Duplicate supported handler '%s'" % handler_id)
if handler_id not in BUILTIN_HANDLER_IDS:
errors.append("Duplicate supported handler '%s'" % handler_id)
else:
supported_handlers[handler_id] = true
var cue_ids := (
@@ -202,7 +207,9 @@ func rebuild(
actions_by_id,
professions_by_id,
items_by_id,
storages_by_id,
capability_tags_by_id,
event_types_by_id,
supported_handlers,
supported_cues,
errors
@@ -670,7 +677,9 @@ static func _validate_action_references(
actions_by_id: Dictionary,
professions_by_id: Dictionary,
items_by_id: Dictionary,
storages_by_id: Dictionary,
capability_tags_by_id: Dictionary,
event_types_by_id: Dictionary,
supported_handlers: Dictionary,
supported_cues: Dictionary,
errors: Array[String]
@@ -696,6 +705,16 @@ static func _validate_action_references(
supported_cues,
errors
)
if (
not definition.event_type_id.is_empty()
and not event_types_by_id.has(definition.event_type_id)
):
errors.append(
(
"Action '%s' references unknown event type '%s'"
% [definition.action_id, definition.event_type_id]
)
)
for handler_field in [
["selection policy", definition.selection_policy_id],
["target policy", definition.target_policy_id],
@@ -769,6 +788,64 @@ static func _validate_action_references(
% [definition.action_id, scheduled_action_id]
)
)
_validate_builtin_action_handler_contract(definition, items_by_id, storages_by_id, errors)
static func _validate_builtin_action_handler_contract(
definition: ActionDefinition,
items_by_id: Dictionary,
storages_by_id: Dictionary,
errors: Array[String]
) -> void:
if definition.completion_handler_id != SimulationIds.ACTION_HANDLER_ACTIVITY_METRIC_DELTA:
return
var label := "Action '%s' activity_metric_delta" % definition.action_id
if definition.target_type != SimulationIds.TARGET_ACTIVITY:
errors.append("%s handler requires an activity target" % label)
if definition.effects.size() != 1:
errors.append("%s handler requires exactly one effect" % label)
return
var effect := definition.effects[0] as ActionEffect
if effect == null or effect.effect_kind != ActionEffect.KIND_METRIC_DELTA:
errors.append("%s handler requires one metric_delta effect" % label)
return
if effect.subject_key not in [&"safety", &"knowledge"]:
errors.append("%s metric must be safety or knowledge" % label)
if not is_finite(effect.value) or effect.value <= 0.0:
errors.append("%s effect value must be finite and positive" % label)
var allowed_parameters := {"player_multiplier": true, "npc_productivity": true}
for raw_key in effect.parameters:
var key := String(raw_key)
if not allowed_parameters.has(key):
errors.append("%s has unsupported effect parameter '%s'" % [label, key])
var player_multiplier: Variant = effect.parameters.get("player_multiplier", 1.0)
if player_multiplier is not int and player_multiplier is not float:
errors.append("%s player_multiplier must be numeric" % label)
elif not is_finite(float(player_multiplier)) or float(player_multiplier) <= 0.0:
errors.append("%s player_multiplier must be finite and positive" % label)
var npc_productivity: Variant = effect.parameters.get("npc_productivity", false)
if npc_productivity is not bool:
errors.append("%s npc_productivity must be a bool" % label)
if definition.event_type_id.is_empty():
errors.append("%s handler requires a nonempty event_type_id" % label)
if not definition.has_completion_cost():
return
var cost_item := items_by_id.get(definition.completion_cost_resource_id) as ItemDefinition
if cost_item == null:
return
var has_storage_route := false
for storage_value in storages_by_id.values():
var storage := storage_value as StorageDefinition
if storage != null and storage.accepts_item(cost_item):
has_storage_route = true
break
if not has_storage_route:
errors.append(
(
"%s completion cost item '%s' has no authored storage route"
% [label, definition.completion_cost_resource_id]
)
)
static func _validate_item_references(