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
217 changes: 217 additions & 0 deletions UnityMCPConnection/Editor/MCPDataCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@

namespace Plugins.GamePilot.Editor.MCP
{
public enum SceneInfoDetail
{
RootObjectsOnly,
FullHierarchy
}

public enum GameObjectInfoDetail
{
BasicInfo,
IncludeComponents,
IncludeChildren,
IncludeComponentsAndChildren // New option to include both components and children
}

public class MCPDataCollector : IDisposable
{
private readonly Queue<LogEntry> logBuffer = new Queue<LogEntry>();
Expand Down Expand Up @@ -279,5 +293,208 @@ private string[] GetAssetPaths()
return new string[0];
}
}

// New method to get current scene information based on requested detail level
public MCPSceneInfo GetCurrentSceneInfo(SceneInfoDetail detailLevel)
{
try
{
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();

var sceneInfo = new MCPSceneInfo
{
Name = scene.name,
Path = scene.path,
IsDirty = scene.isDirty,
RootCount = scene.rootCount
};

if (scene.IsValid())
{
var rootObjects = scene.GetRootGameObjects();

// Map scene objects based on detail level requested
switch (detailLevel)
{
case SceneInfoDetail.RootObjectsOnly:
sceneInfo.RootObjects = rootObjects
.Where(o => o != null)
.Select(o => new MCPGameObjectReference
{
Name = o.name,
InstanceID = o.GetInstanceID(),
Path = GetGameObjectPath(o),
Active = o.activeSelf,
ChildCount = o.transform.childCount
})
.ToList();
break;

case SceneInfoDetail.FullHierarchy:
sceneInfo.RootObjects = rootObjects
.Where(o => o != null)
.Select(o => GetGameObjectReferenceWithChildren(o))
.ToList();
break;
}
}

return sceneInfo;
}
catch (Exception ex)
{
Debug.LogError($"[MCP] Error getting scene info: {ex.Message}");
return new MCPSceneInfo { Name = "Error", ErrorMessage = ex.Message };
}
}

// Helper method to create a game object reference with children
private MCPGameObjectReference GetGameObjectReferenceWithChildren(GameObject obj)
{
if (obj == null) return null;

var reference = new MCPGameObjectReference
{
Name = obj.name,
InstanceID = obj.GetInstanceID(),
Path = GetGameObjectPath(obj),
Active = obj.activeSelf,
ChildCount = obj.transform.childCount,
Children = new List<MCPGameObjectReference>()
};

// Add all children
var transform = obj.transform;
for (int i = 0; i < transform.childCount; i++)
{
var childTransform = transform.GetChild(i);
if (childTransform != null && childTransform.gameObject != null)
{
var childRef = GetGameObjectReferenceWithChildren(childTransform.gameObject);
if (childRef != null)
{
reference.Children.Add(childRef);
}
}
}

return reference;
}

// Get detailed information about specific game objects
public List<MCPGameObjectDetail> GetGameObjectsInfo(int[] objectInstanceIDs, GameObjectInfoDetail detailLevel)
{
var results = new List<MCPGameObjectDetail>();

try
{
foreach (var id in objectInstanceIDs)
{
var obj = EditorUtility.InstanceIDToObject(id) as GameObject;
if (obj != null)
{
results.Add(GetGameObjectDetail(obj, detailLevel));
}
}
}
catch (Exception ex)
{
Debug.LogError($"[MCP] Error getting game object details: {ex.Message}");
}

return results;
}

// Helper method to get detailed info about a game object
private MCPGameObjectDetail GetGameObjectDetail(GameObject obj, GameObjectInfoDetail detailLevel)
{
var detail = new MCPGameObjectDetail
{
Name = obj.name,
InstanceID = obj.GetInstanceID(),
Path = GetGameObjectPath(obj),
Active = obj.activeSelf,
ActiveInHierarchy = obj.activeInHierarchy,
Tag = obj.tag,
Layer = obj.layer,
LayerName = LayerMask.LayerToName(obj.layer),
IsStatic = obj.isStatic,
Transform = new MCPTransformInfo
{
Position = obj.transform.position,
Rotation = obj.transform.rotation.eulerAngles,
LocalPosition = obj.transform.localPosition,
LocalRotation = obj.transform.localRotation.eulerAngles,
LocalScale = obj.transform.localScale
}
};

// Include components if requested
if (detailLevel == GameObjectInfoDetail.IncludeComponents ||
detailLevel == GameObjectInfoDetail.IncludeComponentsAndChildren)
{
detail.Components = obj.GetComponents<Component>()
.Where(c => c != null)
.Select(c => new MCPComponentInfo
{
Type = c.GetType().Name,
IsEnabled = GetComponentEnabled(c),
InstanceID = c.GetInstanceID()
})
.ToList();
}

// Include children if requested
if (detailLevel == GameObjectInfoDetail.IncludeChildren ||
detailLevel == GameObjectInfoDetail.IncludeComponentsAndChildren)
{
detail.Children = new List<MCPGameObjectDetail>();
var transform = obj.transform;

for (int i = 0; i < transform.childCount; i++)
{
var childTransform = transform.GetChild(i);
if (childTransform != null && childTransform.gameObject != null)
{
// When including both components and children, make sure to include components for children too
GameObjectInfoDetail childDetailLevel = detailLevel == GameObjectInfoDetail.IncludeComponentsAndChildren
? GameObjectInfoDetail.IncludeComponentsAndChildren
: GameObjectInfoDetail.BasicInfo;

var childDetail = GetGameObjectDetail(
childTransform.gameObject,
childDetailLevel);

detail.Children.Add(childDetail);
}
}
}

return detail;
}

// Helper for getting component enabled state
private bool GetComponentEnabled(Component component)
{
// Try to check if component is enabled (for components that support it)
try
{
if (component is Behaviour behaviour)
return behaviour.enabled;

if (component is Renderer renderer)
return renderer.enabled;

if (component is Collider collider)
return collider.enabled;
}
catch
{
// Ignore any exceptions
}

// Default to true for components that don't have an enabled property
return true;
}
}
}
56 changes: 1 addition & 55 deletions UnityMCPConnection/Editor/MCPManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static void Initialize()
// Start connection
connectionManager.Connect();

// Register update for connection checking only, NOT periodic updates
// Register update for connection checking only
EditorApplication.update += Update;

isInitialized = true;
Expand All @@ -68,12 +68,6 @@ private static void OnConnected()
try
{
MCPLogger.Log(ComponentName, "Connected to MCP server");

// Send client info to server
messageSender.SendClientInfoAsync().ConfigureAwait(false);

// Don't automatically start sending periodic updates
// EditorApplication.update += SendPeriodicUpdates; <-- REMOVE THIS LINE
}
catch (Exception ex)
{
Expand All @@ -86,9 +80,6 @@ private static void OnDisconnected()
try
{
MCPLogger.Log(ComponentName, "Disconnected from MCP server");

// Stop sending periodic updates if they were started manually
EditorApplication.update -= SendPeriodicUpdates;
}
catch (Exception ex)
{
Expand All @@ -101,9 +92,6 @@ private static void OnError(string errorMessage)
MCPLogger.LogError(ComponentName, $"Connection error: {errorMessage}");
}

private static float updateTimer = 0f;
private static readonly float updateInterval = 1f; // Send updates every 1 second

private static void Update()
{
try
Expand All @@ -113,30 +101,6 @@ private static void Update()
{
connectionManager?.CheckConnection();
}
// No other periodic tasks should be here
}
catch (Exception ex)
{
MCPLogger.LogException(ComponentName, ex);
}
}

// Keep this method but don't register it automatically
// This will be called only when the server explicitly requests updates
private static void SendPeriodicUpdates()
{
try
{
updateTimer += Time.deltaTime;

if (updateTimer >= updateInterval)
{
// Collect and send editor state
var editorState = dataCollector.GetEditorState();
messageSender.SendEditorStateAsync(editorState).ConfigureAwait(false);

updateTimer = 0f;
}
}
catch (Exception ex)
{
Expand Down Expand Up @@ -168,7 +132,6 @@ public static void Shutdown()

// Unregister update callbacks
EditorApplication.update -= Update;
EditorApplication.update -= SendPeriodicUpdates;

// Disconnect
connectionManager?.Disconnect();
Expand All @@ -184,22 +147,5 @@ public static void Shutdown()
MCPLogger.LogException(ComponentName, ex);
}
}

// Add a public method to manually start/stop editor state updates
public static void EnablePeriodicUpdates(bool enable)
{
if (enable)
{
// Start sending periodic updates
EditorApplication.update += SendPeriodicUpdates;
MCPLogger.Log(ComponentName, "Periodic updates enabled");
}
else
{
// Stop sending periodic updates
EditorApplication.update -= SendPeriodicUpdates;
MCPLogger.Log(ComponentName, "Periodic updates disabled");
}
}
}
}
Loading