-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEntityUtil.h
144 lines (122 loc) · 4.27 KB
/
EntityUtil.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "Core/Entity.h"
#include <vector>
namespace DYE::DYEditor::EntityUtil
{
bool IsFirstDegreeChildOf(Entity potentialChild, Entity potentialParent);
/// Check recursively if potential child is under potential parent's hierarchy.
bool IsChildOf(Entity potentialChild, Entity potentialParent);
/// Get an array including the given root entity and its children recursively in depth-first order.
std::vector<Entity> GetEntityAndAllChildrenPreorder(Entity root);
/// Get an array of children of the given entity recursively in depth-first order.
std::vector<Entity> GetAllChildrenPreorder(Entity root);
/// Iterate through the entity and its all children (including nth degree children)
/// using depth-first order (preorder). You should not destroy any entity during the iteration.
template<typename Func>
void ForEntityAndEachChildPreorder(Entity root, Func func)
{
std::stack<Entity> entityStack;
entityStack.push(root);
while (!entityStack.empty())
{
Entity entity = entityStack.top();
func(entity);
entityStack.pop();
auto tryGetChild = entity.TryGetComponent<ChildrenComponent>();
if (!tryGetChild.has_value())
{
// No child, nothing to push into the stack.
continue;
}
auto &childrenGUIDs = tryGetChild.value().get().ChildrenGUIDs;
for (int i = childrenGUIDs.size() - 1; i >= 0; i--)
{
auto childGUID = childrenGUIDs[i];
auto tryGetEntityWithGUID = root.GetWorld().TryGetEntityWithGUID(childGUID);
if (!tryGetEntityWithGUID.has_value())
{
continue;
}
// Push the child into the stack.
entityStack.push(tryGetEntityWithGUID.value());
}
}
}
/// Iterate through the entity and its all children (including nth degree children)
/// using depth-first order (preorder). The second parameter of the function will be the relative depth to the root entity.
/// You should not destroy any entity during the iteration.
template<typename Func>
void ForEntityAndEachChildPreorderWithDepth(Entity root, Func func)
{
struct Element
{
Entity Entity;
int Depth = 0;
};
std::stack<Element> entityStack;
entityStack.push({ .Entity = root, .Depth = 0 });
while (!entityStack.empty())
{
Element element = entityStack.top();
Entity entity = element.Entity;
func(entity, element.Depth);
entityStack.pop();
auto tryGetChild = entity.TryGetComponent<ChildrenComponent>();
if (!tryGetChild.has_value())
{
// No child, nothing to push into the stack.
continue;
}
auto &childrenGUIDs = tryGetChild.value().get().ChildrenGUIDs;
for (int i = childrenGUIDs.size() - 1; i >= 0; i--)
{
auto childGUID = childrenGUIDs[i];
auto tryGetEntityWithGUID = root.GetWorld().TryGetEntityWithGUID(childGUID);
if (!tryGetEntityWithGUID.has_value())
{
continue;
}
// Push the child into the stack.
entityStack.push({ .Entity = tryGetEntityWithGUID.value(), .Depth = element.Depth + 1 });
}
}
}
/// Iterate through all children (including nth degree children)
/// using depth-first order (preorder). You should not destroy any entity during the iteration.
/// If you really have to, consider using GetAllChildrenPreorder to get an array of children.
template<typename Func>
void ForEachChildPreorder(Entity root, Func func)
{
std::stack<Entity> entityStack;
entityStack.push(root);
bool isRoot = true;
while (!entityStack.empty())
{
Entity entity = entityStack.top();
// We use a flag to skip the first entity in the stack (which is the parent).
if (!isRoot)
{
func(entity);
}
isRoot = false;
entityStack.pop();
auto tryGetChild = entity.TryGetComponent<ChildrenComponent>();
if (!tryGetChild.has_value())
{
// No child, nothing to push into the stack.
continue;
}
auto &childrenGUIDs = tryGetChild.value().get().ChildrenGUIDs;
for (int i = childrenGUIDs.size() - 1; i >= 0; i--)
{
auto childGUID = childrenGUIDs[i];
auto tryGetEntityWithGUID = root.GetWorld().TryGetEntityWithGUID(childGUID);
if (!tryGetEntityWithGUID.has_value())
{
continue;
}
// Push the child into the stack.
entityStack.push(tryGetEntityWithGUID.value());
}
}
}
}