Skip to content

fix: include DontDestroyOnLoad objects in gameobject-find search scope#827

Draft
kisszuopumingdao wants to merge 1 commit into
IvanMurzak:mainfrom
kisszuopumingdao:fix/ddol-find-support
Draft

fix: include DontDestroyOnLoad objects in gameobject-find search scope#827
kisszuopumingdao wants to merge 1 commit into
IvanMurzak:mainfrom
kisszuopumingdao:fix/ddol-find-support

Conversation

@kisszuopumingdao

Copy link
Copy Markdown

What changed

Added DontDestroyOnLoad scene root objects to the gameobject-find search scope in FindRootGameObjects().

Why

Many games use DontDestroyOnLoad to keep UI canvases alive across scene transitions. The existing FindRootGameObjects() only searched the active scene's root objects via EditorSceneManager.GetActiveScene().GetRootGameObjects(), which returned 0 results when all UI was in DontDestroyOnLoad.

This caused gameobject-find to fail with "Not found GameObject with name 'X'" even though the objects existed and were findable via GameObject.Find().

Root cause

GameObjectUtils.Editor.csFindRootGameObjects() only returned active scene roots. Objects in DontDestroyOnLoad were invisible to the search.

Fix

When in Play mode, additionally search DontDestroyOnLoad root objects using Resources.FindObjectsOfTypeAll and combine them with the active scene roots.

Verification

Tested in a Unity project where all UI canvases use DontDestroyOnLoad:

  • Before: gameobject-find with name "BtnClose" → "Not found"
  • After: gameobject-find with name "BtnClose" → found (sceneName: "DontDestroyOnLoad")

Files changed

  • GameObjectUtils.Editor.cs (Unity 6.5+)
  • GameObjectUtils.Editor.pre-Unity.6.5.cs (pre-Unity 6.5)

Co-authored-by: AI (Codex) noreply@openai.com

When searching by name or path, FindRootGameObjects() only returned
active scene root objects. Games using DontDestroyOnLoad for UI canvases
could not be found by gameobject-find.

Now includes DontDestroyOnLoad root objects when in Play mode.

Co-authored-by: AI (Codex) <noreply@openai.com>

@IvanMurzak IvanMurzak left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably low quality AI model was used. This pull request brings more issues than fixes.

#if UNITY_EDITOR && UNITY_6000_5_OR_NEWER
using System.Linq;
using com.IvanMurzak.McpPlugin.Common;
using UnityEngine;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not add UnityEngine here. The idea to keep each line in the file with the full explicit type name <namespace>.<className> to prevent name conflicts and to simplify support of multiple different Unity versions with different namespaces per the same class name.

Comment on lines -2 to -7
┌──────────────────────────────────────────────────────────────────┐
│ 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. │

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect header style

Comment on lines -46 to +71
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)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to keep using the full explicit class <namespace>.<className>

// Include DontDestroyOnLoad root objects (only available at runtime)
if (UnityEditor.EditorApplication.isPlaying)
{
var ddolRoots = Resources.FindObjectsOfTypeAll<GameObject>()

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is way too heavy operation Resources.FindObjectsOfTypeAll. We can't use it.

Comment on lines +55 to +58
var combined = new GameObject[rootGos.Length + ddolRoots.Length];
rootGos.CopyTo(combined, 0);
ddolRoots.CopyTo(combined, rootGos.Length);
return combined;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead making low level array operations need to utilize IEnumerable and LINQ to prevent emitting garbage memory for temporary arrays.

Comment on lines 1 to 74
@@ -19,7 +18,7 @@ namespace com.IvanMurzak.Unity.MCP.Runtime.Utils
public static partial class GameObjectUtils
{
/// <summary>
/// Find Root GameObject in opened Prefab. Of array of GameObjects in a scene.
/// Find Root GameObject in opened Prefab, active scene, and DontDestroyOnLoad.
/// </summary>
/// <param name="scene">Scene for the search, if null the current active scene would be used</param>
/// <returns>Array of root GameObjects</returns>
@@ -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<GameObject>()
.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

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issues as in the GameObjectUtils.Editor.cs file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants