更新godot ai 到最新版本

This commit is contained in:
2026-09-22 16:07:50 +08:00
parent 9dc02dbb31
commit 020ab88606
46 changed files with 5816 additions and 400 deletions
@@ -352,6 +352,15 @@ static func coerce_with_context(value: Variant, ctx: Dictionary) -> Dictionary:
return coerce_for_type(value, ctx.prop_type, ctx.prop_name)
## A rotation slerp can consume: all components finite and unit length within
## float32 precision. Guards the normalization path against a scaled result
## that is zero, infinite, or NaN.
static func _is_usable_rotation(quat: Quaternion) -> bool:
if not is_finite(quat.x) or not is_finite(quat.y) or not is_finite(quat.z) or not is_finite(quat.w):
return false
return absf(quat.length() - 1.0) <= 0.001
## Coerce a single value to the given Godot variant type. Returns
## {"ok": coerced} or {"error": msg}. Unknown types pass through.
static func coerce_for_type(value: Variant, prop_type: int, prop_name: String) -> Dictionary:
@@ -386,6 +395,65 @@ static func coerce_for_type(value: Variant, prop_type: int, prop_name: String) -
TYPE_BOOL:
if value is int or value is float or value is bool:
return {"ok": bool(value)}
TYPE_VECTOR3I:
var v3i = McpJsonValues.parse_vector3i(value)
if v3i != null:
return {"ok": v3i}
return {"error": "Cannot coerce value to Vector3i for property '%s' (expected {x,y,z}, [x,y,z], or Vector3i; components must be finite and within int32 range)" % prop_name}
TYPE_QUATERNION:
var quat = McpJsonValues.parse_quaternion(value)
if quat == null:
return {"error": "Cannot coerce value to Quaternion for property '%s' (expected {x,y,z,w}, [x,y,z,w], or Quaternion; components must be finite)" % prop_name}
## Rotation contract at the animation boundary: AnimationPlayer
## slerps quaternions, and a non-unit one makes
## value_track_interpolate emit a normalization error and return
## identity. Normalize valid nonzero rotations so stored tracks are
## usable; only an exactly zero-length quaternion is refused.
## Scale by the largest component before measuring: components are
## float32, so squaring one near the type's maximum overflows to
## INF (normalized() then returns (0,0,0,0)), while squaring a tiny
## nonzero one underflows to zero and misreads as zero-length.
var largest := maxf(maxf(absf(quat.x), absf(quat.y)), maxf(absf(quat.z), absf(quat.w)))
if largest == 0.0:
return {"error": "Cannot coerce value to Quaternion for property '%s': zero-length quaternion is not a rotation" % prop_name}
var normalized := Quaternion(
quat.x / largest, quat.y / largest, quat.z / largest, quat.w / largest
).normalized()
## Validate the result instead of trusting the arithmetic: an
## unusable rotation must fail here, not reach slerp as zero.
if not _is_usable_rotation(normalized):
return {"error": "Cannot coerce value to Quaternion for property '%s': components cannot be normalized to a usable rotation" % prop_name}
return {"ok": normalized}
TYPE_BASIS:
var basis = McpJsonValues.parse_basis(value)
if basis != null:
return {"ok": basis}
return {"error": "Cannot coerce value to Basis for property '%s' (expected {x,y,z} axis vectors, a 3x3 nested array, or Basis)" % prop_name}
TYPE_TRANSFORM3D:
var xform = McpJsonValues.parse_transform3d(value)
if xform != null:
return {"ok": xform}
return {"error": "Cannot coerce value to Transform3D for property '%s' (expected {basis,origin}, {position,rotation_degrees?,scale?}, or Transform3D)" % prop_name}
TYPE_RECT2:
var rect = McpJsonValues.parse_rect2(value)
if rect != null:
return {"ok": rect}
return {"error": "Cannot coerce value to Rect2 for property '%s' (expected {position,size}, [x,y,w,h], or Rect2)" % prop_name}
TYPE_AABB:
var aabb = McpJsonValues.parse_aabb(value)
if aabb != null:
return {"ok": aabb}
return {"error": "Cannot coerce value to AABB for property '%s' (expected {position,size}, [x,y,z,w,h,d], or AABB)" % prop_name}
TYPE_NODE_PATH:
var node_path = McpJsonValues.parse_node_path(value)
if node_path != null:
return {"ok": node_path}
return {"error": "Cannot coerce value to NodePath for property '%s' (expected a string path)" % prop_name}
TYPE_STRING_NAME:
var string_name = McpJsonValues.parse_string_name(value)
if string_name != null:
return {"ok": string_name}
return {"error": "Cannot coerce value to StringName for property '%s' (expected a string)" % prop_name}
return {"ok": value}