Replace dasher-pack with unified animation-pack using original Blender bone names
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
@tool
|
||||
extends RefCounted
|
||||
|
||||
## Value coercion helpers for camera authoring.
|
||||
##
|
||||
## Handles:
|
||||
## - enum-by-name (keep_aspect="keep_height" -> Camera3D.KEEP_HEIGHT)
|
||||
## - {x, y} dict -> Vector2 (zoom, offset, drag_*_offset)
|
||||
## - serialization back to JSON-friendly shapes
|
||||
|
||||
|
||||
const _ENUM_TABLES := {
|
||||
"projection": {
|
||||
"perspective": Camera3D.PROJECTION_PERSPECTIVE,
|
||||
"orthogonal": Camera3D.PROJECTION_ORTHOGONAL,
|
||||
"frustum": Camera3D.PROJECTION_FRUSTUM,
|
||||
},
|
||||
"keep_aspect": {
|
||||
"keep_width": Camera3D.KEEP_WIDTH,
|
||||
"keep_height": Camera3D.KEEP_HEIGHT,
|
||||
},
|
||||
"anchor_mode": {
|
||||
"fixed_top_left": Camera2D.ANCHOR_MODE_FIXED_TOP_LEFT,
|
||||
"drag_center": Camera2D.ANCHOR_MODE_DRAG_CENTER,
|
||||
},
|
||||
"doppler_tracking": {
|
||||
"disabled": Camera3D.DOPPLER_TRACKING_DISABLED,
|
||||
"idle_step": Camera3D.DOPPLER_TRACKING_IDLE_STEP,
|
||||
"physics_step": Camera3D.DOPPLER_TRACKING_PHYSICS_STEP,
|
||||
},
|
||||
"process_callback": {
|
||||
"physics": Camera2D.CAMERA2D_PROCESS_PHYSICS,
|
||||
"idle": Camera2D.CAMERA2D_PROCESS_IDLE,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
## Return the enum int for (property, string_name), or null if not a known enum string.
|
||||
static func resolve_enum(property: String, value: Variant) -> Variant:
|
||||
if not (value is String):
|
||||
return null
|
||||
if not _ENUM_TABLES.has(property):
|
||||
return null
|
||||
var table: Dictionary = _ENUM_TABLES[property]
|
||||
var key: String = String(value).to_lower()
|
||||
if table.has(key):
|
||||
return table[key]
|
||||
return null
|
||||
|
||||
|
||||
## Valid enum names for a property, for error messages.
|
||||
static func enum_keys(property: String) -> Array:
|
||||
if not _ENUM_TABLES.has(property):
|
||||
return []
|
||||
return (_ENUM_TABLES[property] as Dictionary).keys()
|
||||
|
||||
|
||||
static func parse_vector2(value: Variant) -> Variant:
|
||||
if value is Vector2:
|
||||
return value
|
||||
if value is Dictionary:
|
||||
var d: Dictionary = value
|
||||
return Vector2(float(d.get("x", 0)), float(d.get("y", 0)))
|
||||
if value is Array and value.size() >= 2:
|
||||
return Vector2(float(value[0]), float(value[1]))
|
||||
if value is int or value is float:
|
||||
return Vector2(float(value), float(value))
|
||||
return null
|
||||
|
||||
|
||||
static func parse_vector3(value: Variant) -> Variant:
|
||||
if value is Vector3:
|
||||
return value
|
||||
if value is Dictionary:
|
||||
var d: Dictionary = value
|
||||
return Vector3(float(d.get("x", 0)), float(d.get("y", 0)), float(d.get("z", 0)))
|
||||
if value is Array and value.size() >= 3:
|
||||
return Vector3(float(value[0]), float(value[1]), float(value[2]))
|
||||
return null
|
||||
|
||||
|
||||
## Coerce a JSON-shaped value for a camera property against the declared type.
|
||||
## Returns {ok: true, value: ...} or {ok: false, error: "..."}.
|
||||
static func coerce(property: String, value: Variant, target_type: int) -> Dictionary:
|
||||
# Enum-by-name: must match before generic TYPE_INT coercion.
|
||||
if _ENUM_TABLES.has(property):
|
||||
if value is String:
|
||||
var enum_val = resolve_enum(property, value)
|
||||
if enum_val == null:
|
||||
return {
|
||||
"ok": false,
|
||||
"error": "Invalid %s value: '%s'. Valid: %s" % [
|
||||
property, value, ", ".join(enum_keys(property))
|
||||
],
|
||||
}
|
||||
return {"ok": true, "value": int(enum_val)}
|
||||
if value is int or value is float:
|
||||
return {"ok": true, "value": int(value)}
|
||||
|
||||
match target_type:
|
||||
TYPE_VECTOR2:
|
||||
var v2 = parse_vector2(value)
|
||||
if v2 == null:
|
||||
return {"ok": false, "error": "Invalid vector2 for %s: %s" % [property, value]}
|
||||
return {"ok": true, "value": v2}
|
||||
TYPE_VECTOR3:
|
||||
var v3 = parse_vector3(value)
|
||||
if v3 == null:
|
||||
return {"ok": false, "error": "Invalid vector3 for %s: %s" % [property, value]}
|
||||
return {"ok": true, "value": v3}
|
||||
TYPE_BOOL:
|
||||
if value is bool:
|
||||
return {"ok": true, "value": value}
|
||||
if value is int or value is float:
|
||||
return {"ok": true, "value": bool(value)}
|
||||
return {"ok": false, "error": "Expected bool for %s" % property}
|
||||
TYPE_INT:
|
||||
if value is int:
|
||||
return {"ok": true, "value": value}
|
||||
if value is float:
|
||||
return {"ok": true, "value": int(value)}
|
||||
return {"ok": false, "error": "Expected int for %s" % property}
|
||||
TYPE_FLOAT:
|
||||
if value is float:
|
||||
return {"ok": true, "value": value}
|
||||
if value is int:
|
||||
return {"ok": true, "value": float(value)}
|
||||
return {"ok": false, "error": "Expected number for %s" % property}
|
||||
TYPE_STRING:
|
||||
return {"ok": true, "value": String(value)}
|
||||
|
||||
return {"ok": true, "value": value}
|
||||
|
||||
|
||||
## Serialize a Variant into a JSON-friendly shape for responses.
|
||||
static func serialize(value: Variant) -> Variant:
|
||||
if value == null:
|
||||
return null
|
||||
if value is Vector2:
|
||||
return {"x": value.x, "y": value.y}
|
||||
if value is Vector3:
|
||||
return {"x": value.x, "y": value.y, "z": value.z}
|
||||
return value
|
||||
Reference in New Issue
Block a user