Editor/FenceLibrary/FenceBlockerMenu.cs
using System.Linq;
namespace Editor;
internal static class FenceBlockerMenu
{
[Menu( "Editor", "Fence Builder/Add Or Update Blockers On Selection", "crop_square" )]
public static void AddOrUpdateBlockersOnSelection()
{
var session = SceneEditorSession.Active;
if ( session is null )
{
EditorUtility.DisplayDialog( "No Active Scene", "Open a scene or prefab session first." );
return;
}
var selectedObjects = session.Selection.OfType<GameObject>().Where( x => x.IsValid() ).ToArray();
if ( selectedObjects.Length == 0 )
{
EditorUtility.DisplayDialog( "No Fence Selection", "Select one or more placed fence roots or fence segment objects first." );
return;
}
var existingBlockerObjects = selectedObjects
.SelectMany( EnumerateHierarchy )
.Where( x => x.IsValid() && string.Equals( x.Name, "NavBlocker", System.StringComparison.Ordinal ) )
.ToArray();
var existingBlockerAreas = selectedObjects
.SelectMany( EnumerateHierarchy )
.Select( x => x.Components.Get<NavMeshArea>( FindMode.EverythingInSelf ) )
.Where( x => x is not null )
.ToArray();
using var sessionScope = SceneEditorSession.Scope();
using var sceneScope = session.Scene.Push();
using var undoScope = session.UndoScope( "Add Fence Blockers" )
.WithGameObjectChanges( selectedObjects, GameObjectUndoFlags.All )
.WithComponentChanges( existingBlockerAreas )
.WithGameObjectDestructions( existingBlockerObjects )
.WithComponentCreations()
.Push();
var blockerCount = 0;
foreach ( var selectedObject in selectedObjects )
{
blockerCount += FenceDefinitionEditorUtility.AddOrUpdateBlockerVolumes( selectedObject );
}
EditorUtility.DisplayDialog( "Fence Blockers Updated", $"Added or updated {blockerCount} fence blocker volume(s)." );
}
private static System.Collections.Generic.IEnumerable<GameObject> EnumerateHierarchy( GameObject root )
{
if ( !root.IsValid() )
yield break;
yield return root;
foreach ( var child in root.Children )
{
foreach ( var descendant in EnumerateHierarchy( child ) )
{
yield return descendant;
}
}
}
}