Optimize Actor::DestroyChildren
This commit is contained in:
@@ -711,7 +711,11 @@ namespace FlaxEditor.Modules
|
||||
|
||||
private void OnActorChildNodesDispose(ActorNode node)
|
||||
{
|
||||
if (Selection.Count == 0)
|
||||
return;
|
||||
|
||||
// TODO: cache if selection contains any actor child node and skip this loop if no need to iterate
|
||||
// TODO: or build a hash set with selected nodes for quick O(1) checks (cached until selection changes)
|
||||
|
||||
// Deselect child nodes
|
||||
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEngine;
|
||||
@@ -658,6 +659,48 @@ namespace FlaxEditor.Modules
|
||||
//node?.TreeNode.OnActiveChanged();
|
||||
}
|
||||
|
||||
private void OnActorDestroyChildren(Actor actor)
|
||||
{
|
||||
// Instead of doing OnActorParentChanged for every child lets remove all of them at once from that actor
|
||||
ActorNode node = GetActorNode(actor);
|
||||
if (node != null)
|
||||
{
|
||||
if (Editor.SceneEditing.HasSthSelected)
|
||||
{
|
||||
// Clear selection if one of the removed actors is selected
|
||||
var selection = new HashSet<Actor>();
|
||||
foreach (var e in Editor.SceneEditing.Selection)
|
||||
{
|
||||
if (e is ActorNode q && q.Actor)
|
||||
selection.Add(q.Actor);
|
||||
}
|
||||
var count = actor.ChildrenCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var child = actor.GetChild(i);
|
||||
if (selection.Contains(child))
|
||||
{
|
||||
Editor.SceneEditing.Deselect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all child nodes (upfront remove all nodes to run faster)
|
||||
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||
{
|
||||
if (node.ChildNodes[i] is ActorNode child)
|
||||
child.parentNode = null;
|
||||
}
|
||||
node.TreeNode.DisposeChildren();
|
||||
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||
{
|
||||
node.ChildNodes[i].Dispose();
|
||||
}
|
||||
node.ChildNodes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor node.
|
||||
/// </summary>
|
||||
@@ -709,6 +752,7 @@ namespace FlaxEditor.Modules
|
||||
Level.ActorOrderInParentChanged += OnActorOrderInParentChanged;
|
||||
Level.ActorNameChanged += OnActorNameChanged;
|
||||
Level.ActorActiveChanged += OnActorActiveChanged;
|
||||
Level.ActorDestroyChildren += OnActorDestroyChildren;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -726,6 +770,7 @@ namespace FlaxEditor.Modules
|
||||
Level.ActorOrderInParentChanged -= OnActorOrderInParentChanged;
|
||||
Level.ActorNameChanged -= OnActorNameChanged;
|
||||
Level.ActorActiveChanged -= OnActorActiveChanged;
|
||||
Level.ActorDestroyChildren -= OnActorDestroyChildren;
|
||||
|
||||
// Cleanup graph
|
||||
Root.Dispose();
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace FlaxEditor.SceneGraph
|
||||
/// <summary>
|
||||
/// The parent node.
|
||||
/// </summary>
|
||||
protected SceneGraphNode parentNode;
|
||||
internal SceneGraphNode parentNode;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children list.
|
||||
|
||||
@@ -466,12 +466,71 @@ Array<Actor*> Actor::GetChildren(const MClass* type) const
|
||||
|
||||
void Actor::DestroyChildren(float timeLeft)
|
||||
{
|
||||
if (Children.IsEmpty())
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
|
||||
// Actors system doesn't support editing scene hierarchy from multiple threads
|
||||
if (!IsInMainThread() && IsDuringPlay())
|
||||
{
|
||||
LOG(Error, "Editing scene hierarchy is only allowed on a main thread.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all actors
|
||||
Array<Actor*> children = Children;
|
||||
|
||||
// Inform Editor beforehand
|
||||
Level::callActorEvent(Level::ActorEventType::OnActorDestroyChildren, this, nullptr);
|
||||
|
||||
if (_scene && IsActiveInHierarchy())
|
||||
{
|
||||
// Disable children
|
||||
for (Actor* child : children)
|
||||
{
|
||||
if (child->IsActiveInHierarchy())
|
||||
{
|
||||
child->OnDisableInHierarchy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Level::ScenesLock.Lock();
|
||||
|
||||
// Remove children all at once
|
||||
Children.Clear();
|
||||
_isHierarchyDirty = true;
|
||||
|
||||
// Unlink children from scene hierarchy
|
||||
for (Actor* child : children)
|
||||
{
|
||||
child->_parent = nullptr;
|
||||
if (!_isActiveInHierarchy)
|
||||
child->_isActive = false; // Force keep children deactivated to reduce overhead during destruction
|
||||
if (_scene)
|
||||
child->SetSceneInHierarchy(nullptr);
|
||||
}
|
||||
|
||||
Level::ScenesLock.Unlock();
|
||||
|
||||
// Inform actors about this
|
||||
for (Actor* child : children)
|
||||
{
|
||||
child->OnParentChanged();
|
||||
}
|
||||
|
||||
// Unlink children for hierarchy
|
||||
for (Actor* child : children)
|
||||
{
|
||||
//child->EndPlay();
|
||||
|
||||
//child->SetParent(nullptr, false, false);
|
||||
}
|
||||
|
||||
// Delete objects
|
||||
const bool useGameTime = timeLeft > ZeroTolerance;
|
||||
for (Actor* child : children)
|
||||
{
|
||||
child->SetParent(nullptr, false, false);
|
||||
child->DeleteObject(timeLeft, useGameTime);
|
||||
}
|
||||
}
|
||||
@@ -1280,7 +1339,6 @@ void Actor::OnActiveChanged()
|
||||
if (wasActiveInTree != IsActiveInHierarchy())
|
||||
OnActiveInTreeChanged();
|
||||
|
||||
//if (GetScene())
|
||||
Level::callActorEvent(Level::ActorEventType::OnActorActiveChanged, this, nullptr);
|
||||
}
|
||||
|
||||
@@ -1311,7 +1369,6 @@ void Actor::OnActiveInTreeChanged()
|
||||
|
||||
void Actor::OnOrderInParentChanged()
|
||||
{
|
||||
//if (GetScene())
|
||||
Level::callActorEvent(Level::ActorEventType::OnActorOrderInParentChanged, this, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -263,6 +263,9 @@ Delegate<Actor*, Actor*> Level::ActorParentChanged;
|
||||
Delegate<Actor*> Level::ActorOrderInParentChanged;
|
||||
Delegate<Actor*> Level::ActorNameChanged;
|
||||
Delegate<Actor*> Level::ActorActiveChanged;
|
||||
#if USE_EDITOR
|
||||
Delegate<Actor*> Level::ActorDestroyChildren;
|
||||
#endif
|
||||
Delegate<Scene*, const Guid&> Level::SceneSaving;
|
||||
Delegate<Scene*, const Guid&> Level::SceneSaved;
|
||||
Delegate<Scene*, const Guid&> Level::SceneSaveError;
|
||||
@@ -851,6 +854,11 @@ void Level::callActorEvent(ActorEventType eventType, Actor* a, Actor* b)
|
||||
case ActorEventType::OnActorActiveChanged:
|
||||
ActorActiveChanged(a);
|
||||
break;
|
||||
#if USE_EDITOR
|
||||
case ActorEventType::OnActorDestroyChildren:
|
||||
ActorDestroyChildren(a);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -549,7 +549,13 @@ private:
|
||||
OnActorOrderInParentChanged = 3,
|
||||
OnActorNameChanged = 4,
|
||||
OnActorActiveChanged = 5,
|
||||
#if USE_EDITOR
|
||||
OnActorDestroyChildren = 6,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void callActorEvent(ActorEventType eventType, Actor* a, Actor* b);
|
||||
#if USE_EDITOR
|
||||
API_EVENT(Internal) static Delegate<Actor*> ActorDestroyChildren;
|
||||
#endif
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user