Skip to main content
Glama
SceneHandler.cs10.8 kB
using UnityEngine; using UnityEditor; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using System; using System.Linq; using System.Collections.Generic; namespace UnityMCP { /// <summary> /// Handles Unity scene operations and hierarchy management /// Provides scene navigation, object finding, and batch operations /// </summary> public static class SceneHandler { public static string HandleCommand(string path, string requestBody) { try { var data = JsonUtility.FromJson<CommandData>(requestBody); switch (path) { case "/scene/list": return ListScenes(); case "/scene/load": return LoadScene(data); case "/scene/save": return SaveScene(data); case "/scene/new": return CreateNewScene(data); case "/scene/hierarchy": return GetHierarchy(); case "/scene/find": return FindInScene(data); case "/scene/cleanup": return CleanupScene(data); default: return Error("Unknown scene command"); } } catch (Exception e) { return Error(e.Message); } } public static string ListScenes() { var scenes = new List<object>(); // List all scenes in build settings for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++) { string scenePath = SceneUtility.GetScenePathByBuildIndex(i); scenes.Add(new { index = i, path = scenePath, name = System.IO.Path.GetFileNameWithoutExtension(scenePath) }); } // Add currently loaded scenes var loadedScenes = new List<object>(); for (int i = 0; i < SceneManager.sceneCount; i++) { var scene = SceneManager.GetSceneAt(i); loadedScenes.Add(new { name = scene.name, path = scene.path, isLoaded = scene.isLoaded, rootCount = scene.rootCount }); } return $"{{\"success\":true,\"buildScenes\":{JsonUtility.ToJson(scenes)},\"loadedScenes\":{JsonUtility.ToJson(loadedScenes)}}}"; } public static string LoadScene(CommandData data) { try { Scene scene; if (data.index >= 0) { string scenePath = SceneUtility.GetScenePathByBuildIndex(data.index); scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single); } else if (!string.IsNullOrEmpty(data.sceneName)) { // Find scene by name in build settings string scenePath = ""; for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++) { string path = SceneUtility.GetScenePathByBuildIndex(i); if (System.IO.Path.GetFileNameWithoutExtension(path) == data.sceneName) { scenePath = path; break; } } if (string.IsNullOrEmpty(scenePath)) { return Error($"Scene not found: {data.sceneName}"); } scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single); } else { return Error("No scene specified"); } return Success($"Loaded scene: {scene.name}"); } catch (Exception e) { return Error($"Failed to load scene: {e.Message}"); } } public static string SaveScene(CommandData data) { try { if (data.saveAll) { EditorSceneManager.SaveOpenScenes(); return Success("Saved all open scenes"); } else { var scene = SceneManager.GetActiveScene(); EditorSceneManager.SaveScene(scene); return Success($"Saved scene: {scene.name}"); } } catch (Exception e) { return Error($"Failed to save scene: {e.Message}"); } } public static string CreateNewScene(CommandData data) { try { var newScene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single); if (!string.IsNullOrEmpty(data.sceneName)) { EditorSceneManager.SaveScene(newScene, $"Assets/Scenes/{data.sceneName}.unity"); } return Success($"Created new scene: {newScene.name}"); } catch (Exception e) { return Error($"Failed to create scene: {e.Message}"); } } public static string GetHierarchy() { var scene = SceneManager.GetActiveScene(); var rootObjects = scene.GetRootGameObjects(); var hierarchy = rootObjects.Select(obj => BuildHierarchyNode(obj)).ToList(); return $"{{\"success\":true,\"scene\":\"{scene.name}\",\"hierarchy\":{JsonUtility.ToJson(hierarchy)}}}"; } public static object BuildHierarchyNode(GameObject obj) { var children = new List<object>(); for (int i = 0; i < obj.transform.childCount; i++) { children.Add(BuildHierarchyNode(obj.transform.GetChild(i).gameObject)); } return new { name = obj.name, tag = obj.tag, layer = LayerMask.LayerToName(obj.layer), active = obj.activeSelf, components = obj.GetComponents<Component>().Select(c => c.GetType().Name).ToArray(), children = children.ToArray() }; } public static string FindInScene(CommandData data) { var results = new List<string>(); if (!string.IsNullOrEmpty(data.tag)) { var objects = GameObject.FindGameObjectsWithTag(data.tag); results = objects.Select(o => o.name).ToList(); } else if (!string.IsNullOrEmpty(data.pattern)) { var scene = SceneManager.GetActiveScene(); var allObjects = scene.GetRootGameObjects(); foreach (var root in allObjects) { FindByPattern(root, data.pattern, results); } } else if (!string.IsNullOrEmpty(data.componentType)) { var type = Type.GetType(data.componentType); if (type != null) { var components = GameObject.FindObjectsByType(type, FindObjectsSortMode.None); results = components.Select(c => (c as Component)?.gameObject.name).Where(n => n != null).ToList(); } } return $"{{\"success\":true,\"count\":{results.Count},\"objects\":[{string.Join(",", results.Select(n => $"\"{n}\""))}]}}"; } public static void FindByPattern(GameObject obj, string pattern, List<string> results) { if (obj.name.Contains(pattern)) { results.Add(obj.name); } for (int i = 0; i < obj.transform.childCount; i++) { FindByPattern(obj.transform.GetChild(i).gameObject, pattern, results); } } public static string CleanupScene(CommandData data) { int cleaned = 0; // Remove missing script references if (data.removeMissingScripts) { var allObjects = GameObject.FindObjectsByType<GameObject>(FindObjectsSortMode.None); foreach (var obj in allObjects) { int count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(obj); if (count > 0) { Undo.RegisterCompleteObjectUndo(obj, "Remove Missing Scripts"); GameObjectUtility.RemoveMonoBehavioursWithMissingScript(obj); cleaned += count; } } } // Remove empty game objects if (data.removeEmpty) { var allObjects = GameObject.FindObjectsByType<GameObject>(FindObjectsSortMode.None); foreach (var obj in allObjects) { if (obj.transform.childCount == 0 && obj.GetComponents<Component>().Length == 1) // Only Transform { Undo.DestroyObjectImmediate(obj); cleaned++; } } } return Success($"Cleaned {cleaned} items from scene"); } public static string Success(string message) { return $"{{\"success\":true,\"message\":\"{message}\"}}"; } public static string Error(string message) { return $"{{\"success\":false,\"error\":\"{message}\"}}"; } [Serializable] public class CommandData { public int index = -1; public string sceneName; public bool saveAll; public string tag; public string pattern; public string componentType; public bool removeMissingScripts; public bool removeEmpty; } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/muammar-yacoob/unity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server