90 lines
2.9 KiB
GDScript
90 lines
2.9 KiB
GDScript
class_name PresentationCueDefinition
|
|
extends Resource
|
|
|
|
const ALLOWED_PARAMETER_KEYS := {
|
|
"visual_scale": true,
|
|
"body_scale": true,
|
|
"fluff_scale": true,
|
|
"show_horns": true,
|
|
"show_beard": true,
|
|
}
|
|
|
|
@export var cue_id: StringName
|
|
@export_file("*.tscn") var scene_path: String
|
|
@export_file var icon_path: String
|
|
@export_file var material_path: String
|
|
@export var animation_hook_id: StringName
|
|
@export var parameters: Dictionary = {}
|
|
|
|
|
|
func validate_metadata() -> Array[String]:
|
|
var errors: Array[String] = []
|
|
if not AnimalDefinition.is_valid_stable_id(cue_id):
|
|
errors.append("cue_id is invalid")
|
|
_validate_optional_path(scene_path, "scene_path", ["tscn", "scn"], errors)
|
|
_validate_optional_path(icon_path, "icon_path", ["png", "svg", "webp"], errors)
|
|
_validate_optional_path(material_path, "material_path", ["tres", "res", "material"], errors)
|
|
if (
|
|
not animation_hook_id.is_empty()
|
|
and not AnimalDefinition.is_valid_stable_id(animation_hook_id)
|
|
):
|
|
errors.append("animation_hook_id is invalid for '%s'" % cue_id)
|
|
_validate_parameters(errors)
|
|
return errors
|
|
|
|
|
|
func validate_assets() -> Array[String]:
|
|
var errors := validate_metadata()
|
|
if not errors.is_empty():
|
|
return errors
|
|
for path_field in [
|
|
["scene_path", scene_path, "PackedScene"],
|
|
["icon_path", icon_path, "Texture2D"],
|
|
["material_path", material_path, "Material"],
|
|
]:
|
|
var path: String = path_field[1]
|
|
if not path.is_empty() and not ResourceLoader.exists(path, path_field[2]):
|
|
errors.append("%s does not resolve for '%s'" % [path_field[0], cue_id])
|
|
return errors
|
|
|
|
|
|
func get_parameters() -> Dictionary:
|
|
return parameters.duplicate(true)
|
|
|
|
|
|
func instantiate_scene() -> Node:
|
|
if scene_path.is_empty():
|
|
return null
|
|
var scene := load(scene_path) as PackedScene
|
|
return scene.instantiate() if scene != null else null
|
|
|
|
|
|
func _validate_parameters(errors: Array[String]) -> void:
|
|
for raw_key in parameters:
|
|
if raw_key is not String and raw_key is not StringName:
|
|
errors.append("parameter key must be a string for '%s'" % cue_id)
|
|
continue
|
|
var key := String(raw_key)
|
|
if not ALLOWED_PARAMETER_KEYS.has(key):
|
|
errors.append("unsupported parameter '%s' for '%s'" % [key, cue_id])
|
|
continue
|
|
var value: Variant = parameters[raw_key]
|
|
if key.ends_with("_scale"):
|
|
if value is not Vector3 or not _is_positive_vector(value):
|
|
errors.append("parameter '%s' must be a positive Vector3 for '%s'" % [key, cue_id])
|
|
elif value is not bool:
|
|
errors.append("parameter '%s' must be bool for '%s'" % [key, cue_id])
|
|
|
|
|
|
func _validate_optional_path(
|
|
path: String, field: String, extensions: Array[String], errors: Array[String]
|
|
) -> void:
|
|
if path.is_empty():
|
|
return
|
|
if not path.begins_with("res://") or path.get_extension().to_lower() not in extensions:
|
|
errors.append("%s is invalid for '%s'" % [field, cue_id])
|
|
|
|
|
|
func _is_positive_vector(value: Vector3) -> bool:
|
|
return value.is_finite() and value.x > 0.0 and value.y > 0.0 and value.z > 0.0
|