diff --git a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Unity/Logs/BufferedFileLogStorage.cs b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Unity/Logs/BufferedFileLogStorage.cs
index 514bc9fa0..838dca1de 100644
--- a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Unity/Logs/BufferedFileLogStorage.cs
+++ b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Unity/Logs/BufferedFileLogStorage.cs
@@ -181,19 +181,19 @@ protected override LogEntry[] QueryInternal(
{
if (entry.Timestamp < cutoffTime)
{
- return result.AsEnumerable().Reverse().ToArray();
+ return ClearStackTraceIfNeeded(result.AsEnumerable().Reverse().ToArray(), includeStackTrace);
}
}
result.Add(entry);
if (result.Count >= maxEntries)
- return result.AsEnumerable().Reverse().ToArray();
+ return ClearStackTraceIfNeeded(result.AsEnumerable().Reverse().ToArray(), includeStackTrace);
}
// 2. Exit if we already have enough entries
var neededLogsCount = maxEntries - result.Count;
if (neededLogsCount <= 0)
- return result.AsEnumerable().Reverse().ToArray();
+ return ClearStackTraceIfNeeded(result.AsEnumerable().Reverse().ToArray(), includeStackTrace);
result.Reverse();
@@ -201,7 +201,17 @@ protected override LogEntry[] QueryInternal(
var fileEntries = base.QueryInternal(neededLogsCount, logTypeFilter, includeStackTrace, lastMinutes);
result.AddRange(fileEntries);
- return result.ToArray();
+ return ClearStackTraceIfNeeded(result.ToArray(), includeStackTrace);
+ }
+
+ private static LogEntry[] ClearStackTraceIfNeeded(LogEntry[] entries, bool includeStackTrace)
+ {
+ if (!includeStackTrace)
+ {
+ foreach (var log in entries)
+ log.StackTrace = null;
+ }
+ return entries;
}
~BufferedFileLogStorage() => Dispose();
diff --git a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Unity/Logs/FileLogStorage.cs b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Unity/Logs/FileLogStorage.cs
index 68caf8192..cd948525e 100644
--- a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Unity/Logs/FileLogStorage.cs
+++ b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Unity/Logs/FileLogStorage.cs
@@ -341,6 +341,13 @@ protected virtual LogEntry[] QueryInternal(
.Reverse()
.ToArray();
+ // Clear stack traces if not requested
+ if (!includeStackTrace)
+ {
+ foreach (var log in filteredLogs)
+ log.StackTrace = null;
+ }
+
return filteredLogs;
}
}
diff --git a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Utils/GameObjectUtils.Editor.cs b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Utils/GameObjectUtils.Editor.cs
index 483b059d9..4ce1746a9 100644
--- a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Utils/GameObjectUtils.Editor.cs
+++ b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Utils/GameObjectUtils.Editor.cs
@@ -1,16 +1,16 @@
/*
-┌──────────────────────────────────────────────────────────────────┐
-│ Author: Ivan Murzak (https://github.com/IvanMurzak) │
-│ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
-│ Copyright (c) 2025 Ivan Murzak │
-│ Licensed under the Apache License, Version 2.0. │
-│ See the LICENSE file in the project root for more information. │
-└──────────────────────────────────────────────────────────────────┘
-*/
+ * Author: Ivan Murzak (https://github.com/IvanMurzak)
+ * Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP)
+ * Copyright (c) 2025 Ivan Murzak
+ * Licensed under the Apache License, Version 2.0.
+ * See the LICENSE file in the project root for more information.
+ */
#nullable enable
#if UNITY_EDITOR && UNITY_6000_5_OR_NEWER
+using System.Linq;
using com.IvanMurzak.McpPlugin.Common;
+using UnityEngine;
using UnityEngine.SceneManagement;
namespace com.IvanMurzak.Unity.MCP.Runtime.Utils
@@ -18,36 +18,57 @@ namespace com.IvanMurzak.Unity.MCP.Runtime.Utils
public static partial class GameObjectUtils
{
///
- /// Find Root GameObject in opened Prefab. Of array of GameObjects in a scene.
+ /// Find Root GameObject in opened Prefab, active scene, and DontDestroyOnLoad.
///
/// Scene for the search, if null the current active scene would be used
/// Array of root GameObjects
- public static UnityEngine.GameObject[] FindRootGameObjects(Scene? scene = null)
+ public static GameObject[] FindRootGameObjects(Scene? scene = null)
{
var prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null)
return prefabStage.prefabContentsRoot.MakeArray();
+ GameObject[] rootGos;
+
if (scene == null)
{
- var rootGos = UnityEditor.SceneManagement.EditorSceneManager
+ rootGos = UnityEditor.SceneManagement.EditorSceneManager
.GetActiveScene()
.GetRootGameObjects();
-
- return rootGos;
}
else
{
- return scene.Value.GetRootGameObjects();
+ rootGos = scene.Value.GetRootGameObjects();
+ }
+
+ // Include DontDestroyOnLoad root objects (only available at runtime)
+ if (UnityEditor.EditorApplication.isPlaying)
+ {
+ var ddolRoots = Resources.FindObjectsOfTypeAll()
+ .Where(go => go.scene.name == "DontDestroyOnLoad"
+ && go.transform.parent == null
+ && (go.hideFlags == HideFlags.None || go.hideFlags == HideFlags.HideInHierarchy))
+ .ToArray();
+
+ if (ddolRoots.Length > 0)
+ {
+ var combined = new GameObject[rootGos.Length + ddolRoots.Length];
+ rootGos.CopyTo(combined, 0);
+ ddolRoots.CopyTo(combined, rootGos.Length);
+ return combined;
+ }
}
+
+ return rootGos;
}
- public static UnityEngine.GameObject? FindByInstanceID(UnityEngine.EntityId instanceID)
+
+ public static GameObject? FindByInstanceID(EntityId instanceID)
{
- if (instanceID == UnityEngine.EntityId.None)
+ if (instanceID == EntityId.None)
return null;
var obj = UnityEditor.EditorUtility.EntityIdToObject(instanceID);
- if (obj is not UnityEngine.GameObject go)
+ if (obj is not GameObject go)
return null;
return go;
diff --git a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Utils/GameObjectUtils.Editor.pre-Unity.6.5.cs b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Utils/GameObjectUtils.Editor.pre-Unity.6.5.cs
index 0d405b0db..d13114822 100644
--- a/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Utils/GameObjectUtils.Editor.pre-Unity.6.5.cs
+++ b/Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/Runtime/Utils/GameObjectUtils.Editor.pre-Unity.6.5.cs
@@ -1,15 +1,14 @@
/*
-┌──────────────────────────────────────────────────────────────────┐
-│ Author: Ivan Murzak (https://github.com/IvanMurzak) │
-│ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
-│ Copyright (c) 2025 Ivan Murzak │
-│ Licensed under the Apache License, Version 2.0. │
-│ See the LICENSE file in the project root for more information. │
-└──────────────────────────────────────────────────────────────────┘
-*/
+ * Author: Ivan Murzak (https://github.com/IvanMurzak)
+ * Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP)
+ * Copyright (c) 2025 Ivan Murzak
+ * Licensed under the Apache License, Version 2.0.
+ * See the LICENSE file in the project root for more information.
+ */
#nullable enable
#if UNITY_EDITOR && !UNITY_6000_5_OR_NEWER
+using System.Linq;
using com.IvanMurzak.McpPlugin.Common;
using UnityEngine;
using UnityEngine.SceneManagement;
@@ -19,7 +18,7 @@ namespace com.IvanMurzak.Unity.MCP.Runtime.Utils
public static partial class GameObjectUtils
{
///
- /// Find Root GameObject in opened Prefab. Of array of GameObjects in a scene.
+ /// Find Root GameObject in opened Prefab, active scene, and DontDestroyOnLoad.
///
/// Scene for the search, if null the current active scene would be used
/// Array of root GameObjects
@@ -29,26 +28,47 @@ public static GameObject[] FindRootGameObjects(Scene? scene = null)
if (prefabStage != null)
return prefabStage.prefabContentsRoot.MakeArray();
+ GameObject[] rootGos;
+
if (scene == null)
{
- var rootGos = UnityEditor.SceneManagement.EditorSceneManager
+ rootGos = UnityEditor.SceneManagement.EditorSceneManager
.GetActiveScene()
.GetRootGameObjects();
-
- return rootGos;
}
else
{
- return scene.Value.GetRootGameObjects();
+ rootGos = scene.Value.GetRootGameObjects();
+ }
+
+ // Include DontDestroyOnLoad root objects (only available at runtime)
+ if (UnityEditor.EditorApplication.isPlaying)
+ {
+ var ddolRoots = Resources.FindObjectsOfTypeAll()
+ .Where(go => go.scene.name == "DontDestroyOnLoad"
+ && go.transform.parent == null
+ && (go.hideFlags == HideFlags.None || go.hideFlags == HideFlags.HideInHierarchy))
+ .ToArray();
+
+ if (ddolRoots.Length > 0)
+ {
+ var combined = new GameObject[rootGos.Length + ddolRoots.Length];
+ rootGos.CopyTo(combined, 0);
+ ddolRoots.CopyTo(combined, rootGos.Length);
+ return combined;
+ }
}
+
+ return rootGos;
}
+
public static GameObject? FindByInstanceID(int instanceID)
{
if (instanceID == 0)
return null;
#if UNITY_6000_3_OR_NEWER
- var obj = UnityEditor.EditorUtility.EntityIdToObject((UnityEngine.EntityId)instanceID);
+ var obj = UnityEditor.EditorUtility.EntityIdToObject((EntityId)instanceID);
#else
var obj = UnityEditor.EditorUtility.InstanceIDToObject(instanceID);
#endif