VR4RoboticArm2/VR4RoboticArm/Library/PackageCache/com.meta.xr.sdk.interaction/Editor/AutoWiring/UnityObjectAddedBroadcaster.cs
IonutMocanu d7aba243a2 Main
2025-09-08 11:04:02 +03:00

209 lines
7.8 KiB
C#

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Oculus.Interaction.Editor
{
[InitializeOnLoad]
public static class UnityObjectAddedBroadcaster
{
public static event Action<GameObject> WhenGameObjectHierarchyAdded = (_) => { };
public static event Action<Component> WhenComponentAdded = (_) => { };
private static int _objectAddedUndoNestingCounter = 0;
private static int _objectAddedUndoGroupId = -1;
static UnityObjectAddedBroadcaster()
{
HashSet<int> knownIds = new HashSet<int>();
EditorSceneManager.SceneOpenedCallback handleSceneOpened = (scene, mode) =>
{
UnityObjectAddedBroadcaster.HandleSceneOpened(scene, mode, knownIds);
};
Action handleHierarchyChanged = () =>
{
UnityObjectAddedBroadcaster.HandleHierarchyChanged(knownIds);
};
Action<Component> handleComponentWasAdded = (component) =>
{
UnityObjectAddedBroadcaster.HandleComponentWasAdded(component);
};
AssemblyReloadEvents.AssemblyReloadCallback handleBeforeAssemblyReload = null;
handleBeforeAssemblyReload = () =>
{
UnityObjectAddedBroadcaster.WhenGameObjectHierarchyAdded = (_) => { };
UnityObjectAddedBroadcaster.WhenComponentAdded = (_) => { };
EditorSceneManager.sceneOpened -= handleSceneOpened;
EditorApplication.hierarchyChanged -= handleHierarchyChanged;
ObjectFactory.componentWasAdded -= handleComponentWasAdded;
AssemblyReloadEvents.beforeAssemblyReload -= handleBeforeAssemblyReload;
};
EditorSceneManager.sceneOpened += handleSceneOpened;
EditorApplication.hierarchyChanged += handleHierarchyChanged;
ObjectFactory.componentWasAdded += handleComponentWasAdded;
AssemblyReloadEvents.beforeAssemblyReload += handleBeforeAssemblyReload;
#if UNITY_2022_2_OR_NEWER
// loadedSceneCount was graduated from EditorSceneManager to SceneManager in 2022.2
for (int idx = 0; idx < SceneManager.loadedSceneCount; ++idx)
#else
for (int idx = 0; idx < EditorSceneManager.loadedSceneCount; ++idx)
#endif
{
handleSceneOpened(EditorSceneManager.GetSceneAt(idx), OpenSceneMode.Additive);
}
}
private static void HandleSceneOpened(Scene scene, OpenSceneMode mode, HashSet<int> knownIds)
{
if (mode == OpenSceneMode.Single)
{
knownIds.Clear();
}
if (!scene.isLoaded)
{
return;
}
AddInstanceIdsFromSubHierarchyToCache(knownIds, scene.GetRootGameObjects());
}
/// <summary>
/// Fires signals for GameObjects and Components added through the addition of a prefab,
/// checking whether the selected GameObject at the moment of a hierarchy change is
/// unfamiliar (i.e., has an instance ID which is not already in known IDs) and signaling
/// appropriately. Note that this will NOT signal GameObjects or Components added to the
/// scene through prefab updating, which are added without modifying the Editor's
/// selection variable, upon which this handler relies.
/// </summary>
/// <param name="knownIds">Cache of known GameObject instance IDs</param>
private static void HandleHierarchyChanged(HashSet<int> knownIds)
{
if (EditorApplication.isPlaying)
{
return;
}
var selection = Selection.activeGameObject;
if (selection == null)
{
return;
}
if (!selection.scene.isLoaded)
{
return;
}
if (!knownIds.Contains(selection.GetInstanceID()))
{
AddInstanceIdsFromSubHierarchyToCache(knownIds, selection);
StartUndoGroup();
UnityObjectAddedBroadcaster.WhenGameObjectHierarchyAdded(selection);
// ObjectFactory.componentWasAdded is not called for components added to the scene
// as part of a prefab, so we manually iterate them here so that
// Signaler.WhenComponentAdded presents a more complete picture of activity in
// the scene.
var addedComponents = selection.GetComponentsInChildren<Component>(true);
foreach (var component in addedComponents)
{
UnityObjectAddedBroadcaster.WhenComponentAdded(component);
}
EndUndoGroup();
}
}
/// <summary>
/// Fires signals for Components added to existing GameObjects. Note that this will
/// NOT signal Components added to the scene through prefab updating, which are added
/// without triggering the ObjectFactory, upon which this handler relies.
/// </summary>
/// <param name="component">The component added to the scene</param>
private static void HandleComponentWasAdded(Component component)
{
if (EditorApplication.isPlaying)
{
return;
}
StartUndoGroup();
UnityObjectAddedBroadcaster.WhenComponentAdded(component);
EndUndoGroup();
}
public static void HandleObjectWasAdded(GameObject gameObject)
{
StartUndoGroup();
var addedComponents = gameObject.GetComponentsInChildren<Component>(true);
foreach (var component in addedComponents)
{
UnityObjectAddedBroadcaster.WhenComponentAdded(component);
}
EndUndoGroup();
}
private static void AddInstanceIdsFromSubHierarchyToCache(HashSet<int> cache, params GameObject[] subHierarchyRoots)
{
foreach (var gameObject in subHierarchyRoots)
{
cache.Add(gameObject.GetInstanceID());
for (int idx = 0; idx < gameObject.transform.childCount; ++idx)
{
AddInstanceIdsFromSubHierarchyToCache(cache, gameObject.transform.GetChild(idx).gameObject);
}
}
}
private static void StartUndoGroup()
{
if (_objectAddedUndoNestingCounter == 0)
{
_objectAddedUndoGroupId = Undo.GetCurrentGroup() - 1;
}
_objectAddedUndoNestingCounter++;
}
private static void EndUndoGroup()
{
_objectAddedUndoNestingCounter--;
if (_objectAddedUndoNestingCounter == 0)
{
Undo.FlushUndoRecordObjects();
Undo.CollapseUndoOperations(_objectAddedUndoGroupId);
}
}
}
}