Last active
November 9, 2025 19:36
-
-
Save bruchmann/b1e9bd8d9ff0416d0c6bc1a8cf9e0e9f to your computer and use it in GitHub Desktop.
Intent system for Godot. (WIP)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class_name IdleIntent | |
| extends Intent |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class_name Intent | |
| extends RefCounted | |
| enum Priority { | |
| LOW, | |
| MEDIUM, | |
| HIGH, | |
| CRITICAL, | |
| } | |
| const COMMITMENT_MIN: float = 0.0 | |
| const COMMITMENT_MAX: float = 1.0 | |
| var accessor: String: | |
| get = get_accessor, set = set_accessor | |
| var commitment: float = COMMITMENT_MIN: | |
| set = set_commitment | |
| var priority: Priority = Priority.LOW | |
| var _accessor_override: String = "" | |
| var _derived_accessor: String = "" | |
| func _to_string() -> String: | |
| var script: Script = get_script() | |
| var cls_name: String = str(script.get_global_name()) | |
| assert(!cls_name.is_empty(), "Intent must not be anonymous. Define a class name.") | |
| var data: Dictionary = _serialize() | |
| var stringified_data: String = "" | |
| if !data.is_empty(): | |
| stringified_data = "#" + JSON.stringify(data) | |
| return "<%s%s %d>" % [ | |
| cls_name, | |
| stringified_data, | |
| get_instance_id(), | |
| ] | |
| func get_accessor() -> String: | |
| if !_accessor_override.is_empty(): | |
| return _accessor_override | |
| if _derived_accessor.is_empty(): | |
| _derived_accessor = _derive_accessor() | |
| return _derived_accessor | |
| func set_accessor(value: String) -> void: | |
| _accessor_override = value | |
| func set_commitment(value: float) -> void: | |
| commitment = clampf(value, COMMITMENT_MIN, COMMITMENT_MAX) | |
| func _derive_accessor() -> String: | |
| var script: Script = get_script() | |
| var cls_name: String = str(script.get_global_name()) | |
| assert(!cls_name.is_empty(), "Intent must not be anonymous. Define a class name.") | |
| if !cls_name.ends_with("2D") and !cls_name.ends_with("Intent"): | |
| assert(false, "Invalid intent name \"%s\". Must end with Intent or Intent2D." % cls_name) | |
| var raw_name: String = cls_name.trim_suffix("2D").trim_suffix("Intent") | |
| return raw_name.to_snake_case() | |
| func _serialize() -> Dictionary: | |
| var data: Dictionary = { } | |
| for property: Dictionary in get_property_list(): | |
| if property.name == "priority": | |
| data["priority"] = Intent.Priority.keys()[priority].to_lower() | |
| continue | |
| if property.usage != PropertyUsageFlags.PROPERTY_USAGE_SCRIPT_VARIABLE: | |
| continue | |
| if property.name.begins_with("_") or property.name == "accessor": | |
| continue | |
| data[property.name] = self[property.name] | |
| return data |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class_name IntentMap | |
| extends RefCounted | |
| var _intents: Dictionary[String, Intent] = { } | |
| static func singleton(intent: Intent) -> IntentMap: | |
| var map: IntentMap = IntentMap.new() | |
| map.add(intent) | |
| return map | |
| func _get(property: StringName) -> Variant: | |
| return _intents.get(property) | |
| @warning_ignore("unused_parameter") | |
| func _set(property: StringName, value: Variant) -> bool: | |
| assert(false, "IntentMap is read only. Use IntentMap.add to add a new intent.") | |
| return false | |
| func _to_string() -> String: | |
| var stringified_keys: String = "" | |
| if !is_empty(): | |
| stringified_keys = " [" | |
| for intent: Intent in values(): | |
| stringified_keys += str(intent) | |
| stringified_keys += "] " | |
| return "<IntentMap%s%d>" % [stringified_keys, get_instance_id()] | |
| func add(intent: Intent, force_override: bool = false) -> bool: | |
| if has(intent.accessor) and !force_override and !_can_override_intent(intent): | |
| return false | |
| _intents[intent.accessor] = intent | |
| return true | |
| func clear() -> void: | |
| _intents.clear() | |
| func has(intent: Variant) -> bool: | |
| if typeof(intent) == TYPE_STRING: | |
| return _intents.has(intent) | |
| assert(typeof(intent) == TYPE_OBJECT, "intent must be an object.") | |
| if is_empty(): | |
| return false | |
| for value: Variant in values(): | |
| if is_instance_of(value, intent): | |
| return true | |
| return false | |
| func is_empty() -> bool: | |
| return _intents.is_empty() | |
| func keys() -> Array: | |
| return _intents.keys() | |
| func values() -> Array: | |
| return _intents.values() | |
| func with_default(default_intent: Intent) -> IntentMap: | |
| if !is_empty(): | |
| return self | |
| return IntentMap.singleton(default_intent) | |
| func _can_override_intent(new_intent: Intent) -> bool: | |
| var old_intent: Intent = _intents[new_intent.accessor] | |
| if new_intent.priority > old_intent.priority: | |
| return true | |
| return new_intent.priority == old_intent.priority and new_intent.commitment > old_intent.commitment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class_name MovementIntent2D | |
| extends Intent | |
| var direction: Vector2 | |
| @warning_ignore("shadowed_variable") | |
| func _init(direction: Vector2) -> void: | |
| self.direction = direction |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment