Files
server-deploy/claude-dev-stack/godot-mcp-pro-v1.14.1/addons/godot_mcp/commands/resource_commands.gd

202 lines
6.2 KiB
GDScript

@tool
extends "res://addons/godot_mcp/commands/base_command.gd"
const PropertyParser := preload("res://addons/godot_mcp/utils/property_parser.gd")
func get_commands() -> Dictionary:
return {
"read_resource": _read_resource,
"edit_resource": _edit_resource,
"create_resource": _create_resource,
"get_resource_preview": _get_resource_preview,
}
func _read_resource(params: Dictionary) -> Dictionary:
var result := require_string(params, "path")
if result[1] != null:
return result[1]
var path: String = result[0]
if not FileAccess.file_exists(path):
return error_not_found("Resource '%s'" % path)
var guard := guard_offline_scene_save(path)
if not guard.is_empty():
return guard
var resource: Resource = ResourceLoader.load(path)
if resource == null:
return error_internal("Failed to load resource: %s" % path)
var props: Dictionary = {}
for prop_info in resource.get_property_list():
var prop_name: String = prop_info["name"]
var usage: int = prop_info["usage"]
if not (usage & PROPERTY_USAGE_EDITOR):
continue
if prop_name.begins_with("_") or prop_name == "script" or prop_name == "resource_local_to_scene" or prop_name == "resource_name" or prop_name == "resource_path":
continue
props[prop_name] = PropertyParser.serialize_value(resource.get(prop_name))
return success({
"path": path,
"type": resource.get_class(),
"resource_name": resource.resource_name,
"properties": props,
})
func _edit_resource(params: Dictionary) -> Dictionary:
var result := require_string(params, "path")
if result[1] != null:
return result[1]
var path: String = result[0]
if not params.has("properties") or not params["properties"] is Dictionary:
return error_invalid_params("'properties' dictionary is required")
var new_props: Dictionary = params["properties"]
if not FileAccess.file_exists(path):
return error_not_found("Resource '%s'" % path)
var guard := guard_offline_scene_save(path)
if not guard.is_empty():
return guard
var resource: Resource = ResourceLoader.load(path)
if resource == null:
return error_internal("Failed to load resource: %s" % path)
var changed: Dictionary = {}
for prop_name: String in new_props:
if not prop_name in resource:
continue
var old_value: Variant = resource.get(prop_name)
var target_type := typeof(old_value)
var new_value: Variant = PropertyParser.parse_value(new_props[prop_name], target_type)
resource.set(prop_name, new_value)
changed[prop_name] = {
"old": PropertyParser.serialize_value(old_value),
"new": PropertyParser.serialize_value(resource.get(prop_name)),
}
if changed.is_empty():
return success({"path": path, "changed": {}, "message": "No properties were changed"})
var err := ResourceSaver.save(resource, path)
if err != OK:
return error_internal("Failed to save resource: %s" % error_string(err))
return success({
"path": path,
"type": resource.get_class(),
"changed": changed,
})
func _create_resource(params: Dictionary) -> Dictionary:
var result := require_string(params, "path")
if result[1] != null:
return result[1]
var path: String = result[0]
var result2 := require_string(params, "type")
if result2[1] != null:
return result2[1]
var resource_type: String = result2[0]
if not ClassDB.class_exists(resource_type):
return error_invalid_params("Unknown resource type: %s" % resource_type)
if not ClassDB.is_parent_class(resource_type, "Resource"):
return error_invalid_params("'%s' is not a Resource type" % resource_type)
var overwrite: bool = optional_bool(params, "overwrite", false)
if FileAccess.file_exists(path) and not overwrite:
return error(-32000, "Resource already exists: %s" % path, {"suggestion": "Set overwrite=true to replace"})
var guard := guard_offline_scene_save(path)
if not guard.is_empty():
return guard
var resource: Resource = ClassDB.instantiate(resource_type)
if resource == null:
return error_internal("Failed to instantiate: %s" % resource_type)
# Apply properties
var properties: Dictionary = params.get("properties", {})
for prop_name: String in properties:
if prop_name in resource:
var current: Variant = resource.get(prop_name)
resource.set(prop_name, PropertyParser.parse_value(properties[prop_name], typeof(current)))
var err := ResourceSaver.save(resource, path)
if err != OK:
return error_internal("Failed to save resource: %s" % error_string(err))
# Rescan filesystem
EditorInterface.get_resource_filesystem().scan()
return success({
"path": path,
"type": resource_type,
"properties_set": properties.keys(),
})
func _get_resource_preview(params: Dictionary) -> Dictionary:
var result := require_string(params, "path")
if result[1] != null:
return result[1]
var path: String = result[0]
if not FileAccess.file_exists(path):
return error_not_found("Resource '%s'" % path)
var max_size: int = optional_int(params, "max_size", 256)
var image: Image = null
# Try loading as image file directly
var ext := path.get_extension().to_lower()
if ext in ["png", "jpg", "jpeg", "bmp", "webp", "svg"]:
image = Image.new()
var err := image.load(path)
if err != OK:
return error_internal("Failed to load image: %s" % error_string(err))
else:
# Try loading as resource and extracting image
var resource: Resource = ResourceLoader.load(path)
if resource == null:
return error_internal("Failed to load resource: %s" % path)
if resource is Texture2D:
image = (resource as Texture2D).get_image()
elif resource is Image:
image = resource as Image
else:
return error_invalid_params("Resource type '%s' does not have an image preview" % resource.get_class())
if image == null:
return error_internal("Could not extract image from resource")
# Resize if needed
if image.get_width() > max_size or image.get_height() > max_size:
var scale_x := float(max_size) / float(image.get_width())
var scale_y := float(max_size) / float(image.get_height())
var scale := minf(scale_x, scale_y)
var new_w := int(image.get_width() * scale)
var new_h := int(image.get_height() * scale)
image.resize(new_w, new_h, Image.INTERPOLATE_LANCZOS)
var png_buffer := image.save_png_to_buffer()
var base64 := Marshalls.raw_to_base64(png_buffer)
return success({
"image_base64": base64,
"width": image.get_width(),
"height": image.get_height(),
"format": "png",
"path": path,
})