Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
527 changes: 527 additions & 0 deletions UnityMcpBridge/Editor/Helpers/GameObjectSerializer.cs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions UnityMcpBridge/Editor/Helpers/GameObjectSerializer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

981 changes: 431 additions & 550 deletions UnityMcpBridge/Editor/Tools/ManageGameObject.cs

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions UnityMcpBridge/Editor/UnityMcpBridge.Editor.asmdef
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "UnityMcpBridge.Editor",
"rootNamespace": "UnityMcpBridge.Editor",
"references": [
"UnityMcpBridge.Runtime",
"GUID:560b04d1a97f54a46a2660c3cc343a6f"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
7 changes: 7 additions & 0 deletions UnityMcpBridge/Editor/UnityMcpBridge.Editor.asmdef.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions UnityMcpBridge/Editor/UnityMcpBridge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ private static void ProcessCommands()

// Normal JSON command processing
Command command = JsonConvert.DeserializeObject<Command>(commandText);

if (command == null)
{
var nullCommandResponse = new
Expand Down
8 changes: 8 additions & 0 deletions UnityMcpBridge/Runtime.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions UnityMcpBridge/Runtime/Serialization.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

266 changes: 266 additions & 0 deletions UnityMcpBridge/Runtime/Serialization/UnityTypeConverters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor; // Required for AssetDatabase and EditorUtility
#endif

namespace UnityMcpBridge.Runtime.Serialization
{
public class Vector3Converter : JsonConverter<Vector3>
{
public override void WriteJson(JsonWriter writer, Vector3 value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("x");
writer.WriteValue(value.x);
writer.WritePropertyName("y");
writer.WriteValue(value.y);
writer.WritePropertyName("z");
writer.WriteValue(value.z);
writer.WriteEndObject();
}

public override Vector3 ReadJson(JsonReader reader, Type objectType, Vector3 existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
return new Vector3(
(float)jo["x"],
(float)jo["y"],
(float)jo["z"]
);
}
}

public class Vector2Converter : JsonConverter<Vector2>
{
public override void WriteJson(JsonWriter writer, Vector2 value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("x");
writer.WriteValue(value.x);
writer.WritePropertyName("y");
writer.WriteValue(value.y);
writer.WriteEndObject();
}

public override Vector2 ReadJson(JsonReader reader, Type objectType, Vector2 existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
return new Vector2(
(float)jo["x"],
(float)jo["y"]
);
}
}

public class QuaternionConverter : JsonConverter<Quaternion>
{
public override void WriteJson(JsonWriter writer, Quaternion value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("x");
writer.WriteValue(value.x);
writer.WritePropertyName("y");
writer.WriteValue(value.y);
writer.WritePropertyName("z");
writer.WriteValue(value.z);
writer.WritePropertyName("w");
writer.WriteValue(value.w);
writer.WriteEndObject();
}

public override Quaternion ReadJson(JsonReader reader, Type objectType, Quaternion existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
return new Quaternion(
(float)jo["x"],
(float)jo["y"],
(float)jo["z"],
(float)jo["w"]
);
}
}

public class ColorConverter : JsonConverter<Color>
{
public override void WriteJson(JsonWriter writer, Color value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("r");
writer.WriteValue(value.r);
writer.WritePropertyName("g");
writer.WriteValue(value.g);
writer.WritePropertyName("b");
writer.WriteValue(value.b);
writer.WritePropertyName("a");
writer.WriteValue(value.a);
writer.WriteEndObject();
}

public override Color ReadJson(JsonReader reader, Type objectType, Color existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
return new Color(
(float)jo["r"],
(float)jo["g"],
(float)jo["b"],
(float)jo["a"]
);
}
}

public class RectConverter : JsonConverter<Rect>
{
public override void WriteJson(JsonWriter writer, Rect value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("x");
writer.WriteValue(value.x);
writer.WritePropertyName("y");
writer.WriteValue(value.y);
writer.WritePropertyName("width");
writer.WriteValue(value.width);
writer.WritePropertyName("height");
writer.WriteValue(value.height);
writer.WriteEndObject();
}

public override Rect ReadJson(JsonReader reader, Type objectType, Rect existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
return new Rect(
(float)jo["x"],
(float)jo["y"],
(float)jo["width"],
(float)jo["height"]
);
}
}

public class BoundsConverter : JsonConverter<Bounds>
{
public override void WriteJson(JsonWriter writer, Bounds value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("center");
serializer.Serialize(writer, value.center); // Use serializer to handle nested Vector3
writer.WritePropertyName("size");
serializer.Serialize(writer, value.size); // Use serializer to handle nested Vector3
writer.WriteEndObject();
}

public override Bounds ReadJson(JsonReader reader, Type objectType, Bounds existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
Vector3 center = jo["center"].ToObject<Vector3>(serializer); // Use serializer to handle nested Vector3
Vector3 size = jo["size"].ToObject<Vector3>(serializer); // Use serializer to handle nested Vector3
return new Bounds(center, size);
}
}

// Converter for UnityEngine.Object references (GameObjects, Components, Materials, Textures, etc.)
public class UnityEngineObjectConverter : JsonConverter<UnityEngine.Object>
{
public override bool CanRead => true; // We need to implement ReadJson
public override bool CanWrite => true;

public override void WriteJson(JsonWriter writer, UnityEngine.Object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}

#if UNITY_EDITOR // AssetDatabase and EditorUtility are Editor-only
if (UnityEditor.AssetDatabase.Contains(value))
{
// It's an asset (Material, Texture, Prefab, etc.)
string path = UnityEditor.AssetDatabase.GetAssetPath(value);
if (!string.IsNullOrEmpty(path))
{
writer.WriteValue(path);
}
else
{
// Asset exists but path couldn't be found? Write minimal info.
writer.WriteStartObject();
writer.WritePropertyName("name");
writer.WriteValue(value.name);
writer.WritePropertyName("instanceID");
writer.WriteValue(value.GetInstanceID());
writer.WritePropertyName("isAssetWithoutPath");
writer.WriteValue(true);
writer.WriteEndObject();
}
}
else
{
// It's a scene object (GameObject, Component, etc.)
writer.WriteStartObject();
writer.WritePropertyName("name");
writer.WriteValue(value.name);
writer.WritePropertyName("instanceID");
writer.WriteValue(value.GetInstanceID());
writer.WriteEndObject();
}
#else
// Runtime fallback: Write basic info without AssetDatabase
writer.WriteStartObject();
writer.WritePropertyName("name");
writer.WriteValue(value.name);
writer.WritePropertyName("instanceID");
writer.WriteValue(value.GetInstanceID());
writer.WritePropertyName("warning");
writer.WriteValue("UnityEngineObjectConverter running in non-Editor mode, asset path unavailable.");
writer.WriteEndObject();
#endif
}

public override UnityEngine.Object ReadJson(JsonReader reader, Type objectType, UnityEngine.Object existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}

#if UNITY_EDITOR
if (reader.TokenType == JsonToken.String)
{
// Assume it's an asset path
string path = reader.Value.ToString();
return UnityEditor.AssetDatabase.LoadAssetAtPath(path, objectType);
}

if (reader.TokenType == JsonToken.StartObject)
{
JObject jo = JObject.Load(reader);
if (jo.TryGetValue("instanceID", out JToken idToken) && idToken.Type == JTokenType.Integer)
{
int instanceId = idToken.ToObject<int>();
UnityEngine.Object obj = UnityEditor.EditorUtility.InstanceIDToObject(instanceId);
if (obj != null && objectType.IsAssignableFrom(obj.GetType()))
{
return obj;
}
}
// Could potentially try finding by name as a fallback if ID lookup fails/isn't present
// but that's less reliable.
}
#else
// Runtime deserialization is tricky without AssetDatabase/EditorUtility
// Maybe log a warning and return null or existingValue?
Debug.LogWarning("UnityEngineObjectConverter cannot deserialize complex objects in non-Editor mode.");
// Skip the token to avoid breaking the reader
if (reader.TokenType == JsonToken.StartObject) JObject.Load(reader);
else if (reader.TokenType == JsonToken.String) reader.ReadAsString();
// Return null or existing value, depending on desired behavior
return existingValue;
#endif

throw new JsonSerializationException($"Unexpected token type '{reader.TokenType}' when deserializing UnityEngine.Object");
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions UnityMcpBridge/Runtime/UnityMcpBridge.Runtime.asmdef
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "UnityMcpBridge.Runtime",
"rootNamespace": "UnityMcpBridge.Runtime",
"references": [
"GUID:560b04d1a97f54a46a2660c3cc343a6f"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
7 changes: 7 additions & 0 deletions UnityMcpBridge/Runtime/UnityMcpBridge.Runtime.asmdef.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion UnityMcpServer/src/tools/manage_gameobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def manage_gameobject(
search_inactive: bool = False,
# -- Component Management Arguments --
component_name: str = None,
includeNonPublicSerialized: bool = None, # Controls serialization of private [SerializeField] fields
) -> Dict[str, Any]:
"""Manages GameObjects: create, modify, delete, find, and component operations.

Expand All @@ -59,6 +60,7 @@ def manage_gameobject(
Action-specific arguments (e.g., position, rotation, scale for create/modify;
component_name for component actions;
search_term, find_all for 'find').
includeNonPublicSerialized: If True, includes private fields marked [SerializeField] in component data.

Returns:
Dictionary with operation results ('success', 'message', 'data').
Expand Down Expand Up @@ -91,7 +93,8 @@ def manage_gameobject(
"findAll": find_all,
"searchInChildren": search_in_children,
"searchInactive": search_inactive,
"componentName": component_name
"componentName": component_name,
"includeNonPublicSerialized": includeNonPublicSerialized
}
params = {k: v for k, v in params.items() if v is not None}

Expand Down
4 changes: 2 additions & 2 deletions UnityMcpServer/src/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.