将原 claude-dev-stack 目录拆分为独立的 Windows 和 WSL 部署栈,便于分别维护和使用。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
204 lines
5.2 KiB
GDScript
204 lines
5.2 KiB
GDScript
@tool
|
|
extends RefCounted
|
|
|
|
## Parse a string value into the appropriate Godot type
|
|
static func parse_value(value: Variant, target_type: int = TYPE_NIL) -> Variant:
|
|
if value == null:
|
|
return null
|
|
|
|
# If already the correct type, return as-is
|
|
if target_type == TYPE_NIL:
|
|
return _auto_parse(value)
|
|
|
|
match target_type:
|
|
TYPE_BOOL:
|
|
if value is bool: return value
|
|
if value is String: return value.to_lower() in ["true", "1", "yes"]
|
|
return bool(value)
|
|
TYPE_INT:
|
|
return int(value)
|
|
TYPE_FLOAT:
|
|
return float(value)
|
|
TYPE_STRING:
|
|
return str(value)
|
|
TYPE_VECTOR2:
|
|
return _parse_vector2(value)
|
|
TYPE_VECTOR2I:
|
|
return _parse_vector2i(value)
|
|
TYPE_VECTOR3:
|
|
return _parse_vector3(value)
|
|
TYPE_VECTOR3I:
|
|
return _parse_vector3i(value)
|
|
TYPE_RECT2:
|
|
return _parse_rect2(value)
|
|
TYPE_COLOR:
|
|
return _parse_color(value)
|
|
TYPE_NODE_PATH:
|
|
return NodePath(str(value))
|
|
TYPE_ARRAY:
|
|
if value is Array: return value
|
|
return [value]
|
|
TYPE_DICTIONARY:
|
|
if value is Dictionary: return value
|
|
return {}
|
|
_:
|
|
return value
|
|
|
|
|
|
static func _auto_parse(value: Variant) -> Variant:
|
|
if not value is String:
|
|
return value
|
|
|
|
var s: String = value
|
|
|
|
# Boolean
|
|
if s == "true": return true
|
|
if s == "false": return false
|
|
|
|
# Integer
|
|
if s.is_valid_int(): return s.to_int()
|
|
|
|
# Float
|
|
if s.is_valid_float(): return s.to_float()
|
|
|
|
# Vector2: "Vector2(x, y)" or "(x, y)" or "x, y"
|
|
if s.begins_with("Vector2(") or s.begins_with("Vector2i("):
|
|
return _parse_vector2(s)
|
|
|
|
# Vector3
|
|
if s.begins_with("Vector3(") or s.begins_with("Vector3i("):
|
|
return _parse_vector3(s)
|
|
|
|
# Color
|
|
if s.begins_with("Color(") or s.begins_with("#"):
|
|
return _parse_color(s)
|
|
|
|
# Rect2
|
|
if s.begins_with("Rect2("):
|
|
return _parse_rect2(s)
|
|
|
|
return s
|
|
|
|
|
|
static func _extract_numbers(s: String) -> PackedFloat64Array:
|
|
# Remove type prefix and parentheses
|
|
var cleaned := s
|
|
for prefix in ["Vector3i(", "Vector3(", "Vector2i(", "Vector2(", "Rect2(", "Color(", "("]:
|
|
if cleaned.begins_with(prefix):
|
|
cleaned = cleaned.substr(prefix.length())
|
|
break
|
|
cleaned = cleaned.trim_suffix(")")
|
|
cleaned = cleaned.strip_edges()
|
|
|
|
var parts := cleaned.split(",")
|
|
var numbers: PackedFloat64Array = []
|
|
for part in parts:
|
|
numbers.append(part.strip_edges().to_float())
|
|
return numbers
|
|
|
|
|
|
static func _parse_vector2(value: Variant) -> Vector2:
|
|
if value is Vector2: return value
|
|
if value is Dictionary:
|
|
return Vector2(float(value.get("x", 0)), float(value.get("y", 0)))
|
|
var nums := _extract_numbers(str(value))
|
|
if nums.size() >= 2:
|
|
return Vector2(nums[0], nums[1])
|
|
return Vector2.ZERO
|
|
|
|
|
|
static func _parse_vector2i(value: Variant) -> Vector2i:
|
|
var v := _parse_vector2(value)
|
|
return Vector2i(int(v.x), int(v.y))
|
|
|
|
|
|
static func _parse_vector3(value: Variant) -> Vector3:
|
|
if value is Vector3: return value
|
|
if value is Dictionary:
|
|
return Vector3(float(value.get("x", 0)), float(value.get("y", 0)), float(value.get("z", 0)))
|
|
var nums := _extract_numbers(str(value))
|
|
if nums.size() >= 3:
|
|
return Vector3(nums[0], nums[1], nums[2])
|
|
return Vector3.ZERO
|
|
|
|
|
|
static func _parse_vector3i(value: Variant) -> Vector3i:
|
|
var v := _parse_vector3(value)
|
|
return Vector3i(int(v.x), int(v.y), int(v.z))
|
|
|
|
|
|
static func _parse_rect2(value: Variant) -> Rect2:
|
|
if value is Rect2: return value
|
|
if value is Dictionary:
|
|
return Rect2(
|
|
float(value.get("x", 0)), float(value.get("y", 0)),
|
|
float(value.get("w", value.get("width", 0))),
|
|
float(value.get("h", value.get("height", 0)))
|
|
)
|
|
var nums := _extract_numbers(str(value))
|
|
if nums.size() >= 4:
|
|
return Rect2(nums[0], nums[1], nums[2], nums[3])
|
|
return Rect2()
|
|
|
|
|
|
static func _parse_color(value: Variant) -> Color:
|
|
if value is Color: return value
|
|
var s := str(value)
|
|
if s.begins_with("#"):
|
|
return Color.html(s)
|
|
if s.begins_with("Color("):
|
|
var nums := _extract_numbers(s)
|
|
match nums.size():
|
|
3: return Color(nums[0], nums[1], nums[2])
|
|
4: return Color(nums[0], nums[1], nums[2], nums[3])
|
|
# Try named color
|
|
if Color.html_is_valid(s):
|
|
return Color.html(s)
|
|
return Color.WHITE
|
|
|
|
|
|
## Serialize a Variant to JSON-safe representation
|
|
static func serialize_value(value: Variant) -> Variant:
|
|
if value == null:
|
|
return null
|
|
match typeof(value):
|
|
TYPE_VECTOR2:
|
|
var v: Vector2 = value
|
|
return {"x": v.x, "y": v.y}
|
|
TYPE_VECTOR2I:
|
|
var v: Vector2i = value
|
|
return {"x": v.x, "y": v.y}
|
|
TYPE_VECTOR3:
|
|
var v: Vector3 = value
|
|
return {"x": v.x, "y": v.y, "z": v.z}
|
|
TYPE_VECTOR3I:
|
|
var v: Vector3i = value
|
|
return {"x": v.x, "y": v.y, "z": v.z}
|
|
TYPE_RECT2:
|
|
var r: Rect2 = value
|
|
return {"x": r.position.x, "y": r.position.y, "width": r.size.x, "height": r.size.y}
|
|
TYPE_COLOR:
|
|
var c: Color = value
|
|
return {"r": c.r, "g": c.g, "b": c.b, "a": c.a, "html": "#" + c.to_html()}
|
|
TYPE_NODE_PATH:
|
|
return str(value)
|
|
TYPE_OBJECT:
|
|
if value is Resource:
|
|
var res: Resource = value
|
|
return {"type": res.get_class(), "path": res.resource_path}
|
|
return str(value)
|
|
TYPE_ARRAY:
|
|
var arr: Array = value
|
|
var result: Array = []
|
|
for item in arr:
|
|
result.append(serialize_value(item))
|
|
return result
|
|
TYPE_DICTIONARY:
|
|
var dict: Dictionary = value
|
|
var result: Dictionary = {}
|
|
for key in dict:
|
|
result[str(key)] = serialize_value(dict[key])
|
|
return result
|
|
_:
|
|
return value
|