1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "node.h"
17
18 #include <scene/ext/intf_ecs_context.h>
19 #include <scene/ext/util.h>
20 #include <scene/interface/intf_application_context.h>
21 #include <scene/interface/intf_scene_manager.h>
22
23 #include <meta/api/object_name.h>
24 #include <meta/base/interface_utils.h>
25
26 #include "core/ecs.h"
27
SCENE_BEGIN_NAMESPACE()28 SCENE_BEGIN_NAMESPACE()
29
30 bool Node::Build(const META_NS::IMetadata::Ptr& d)
31 {
32 return Super::Build(d);
33 }
34
Destroy()35 void Node::Destroy()
36 {
37 if (startableHandler_) {
38 startableHandler_->StopAll(GetAttachmentContainer(false));
39 startableHandler_.reset();
40 }
41 if (!imported_.empty()) {
42 if (auto s = GetInternalScene()) {
43 auto& ecs = s->GetEcsContext();
44 for (auto&& ent : imported_) {
45 if (!ecs.IsNodeEntity(ent)) { // Nodes are handled by the hierarchy so don't delete those here?
46 ecs.RemoveEntity(ent);
47 }
48 }
49 }
50 }
51 Super::Destroy();
52 }
53
GetScene() const54 IScene::Ptr Node::GetScene() const
55 {
56 if (auto s = GetInternalScene()) {
57 return s->GetScene();
58 }
59 return nullptr;
60 }
61
GetParent(NodeTag) const62 Future<INode::Ptr> Node::GetParent(NodeTag) const
63 {
64 if (auto s = GetInternalScene()) {
65 return s->AddTask([=] {
66 auto ent = s->GetEcsContext().GetParent(GetEntity());
67 return CORE_NS::EntityUtil::IsValid(ent) ? s->FindNode(ent, {}) : nullptr;
68 });
69 }
70 return {};
71 }
72
SetEcsObject(const IEcsObject::Ptr & obj)73 bool Node::SetEcsObject(const IEcsObject::Ptr& obj)
74 {
75 if (Super::SetEcsObject(obj)) {
76 if (auto scene = GetInternalScene()) {
77 if (scene->GetOptions().enableStartables) {
78 if (!startableHandler_) {
79 startableHandler_ = BASE_NS::make_unique<StartableHandler>(GetSelf<INode>());
80 }
81 if (startableHandler_) {
82 startableHandler_->StartAll(StartableHandler::StartType::DEFERRED);
83 }
84 }
85 }
86 return true;
87 }
88 return false;
89 }
90
Attach(const IObject::Ptr & attachment,const IObject::Ptr & dataContext)91 bool Node::Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
92 {
93 if (Super::Attach(attachment, dataContext)) {
94 if (startableHandler_) {
95 startableHandler_->Start(attachment, StartableHandler::StartType::DEFERRED);
96 }
97 return true;
98 }
99 return false;
100 }
Detach(const IObject::Ptr & attachment)101 bool Node::Detach(const IObject::Ptr& attachment)
102 {
103 if (startableHandler_) {
104 startableHandler_->Stop(attachment);
105 }
106 return Super::Detach(attachment);
107 }
108
GetChildren() const109 Future<BASE_NS::vector<INode::Ptr>> Node::GetChildren() const
110 {
111 if (auto s = GetInternalScene()) {
112 return s->AddTask([=] { return s->GetChildren(object_); });
113 }
114 return {};
115 }
116
RemoveChild(const INode::Ptr & child)117 Future<bool> Node::RemoveChild(const INode::Ptr& child)
118 {
119 if (auto s = GetInternalScene()) {
120 if (auto ecsobj = interface_pointer_cast<IEcsObjectAccess>(child)) {
121 return s->AddTask([=] { return s->RemoveChild(object_, ecsobj->GetEcsObject()); });
122 }
123 }
124 return {};
125 }
AddChild(const INode::Ptr & child,size_t index)126 Future<bool> Node::AddChild(const INode::Ptr& child, size_t index)
127 {
128 if (auto s = GetInternalScene()) {
129 return s->AddTask([=] { return s->AddChild(object_, child, index); });
130 }
131 return {};
132 }
GetName() const133 BASE_NS::string Node::GetName() const
134 {
135 return NamedSceneObject::GetName();
136 }
GetPath() const137 Future<BASE_NS::string> Node::GetPath() const
138 {
139 if (auto s = GetInternalScene()) {
140 return s->AddTask([=] { return object_->GetPath(); });
141 }
142 return {};
143 }
144
ImportChild(const INode::ConstPtr & node)145 Future<INode::Ptr> Node::ImportChild(const INode::ConstPtr& node)
146 {
147 if (!node) {
148 return {};
149 }
150 if (node->GetScene() == GetScene()) {
151 CORE_LOG_W("Child already belongs to the target scene.");
152 return {};
153 }
154 IEcsObject::Ptr eobj;
155 if (auto i = interface_cast<IEcsObjectAccess>(node)) {
156 eobj = i->GetEcsObject();
157 }
158 if (eobj) {
159 if (auto s = GetInternalScene()) {
160 return s->AddTask([=] {
161 auto ent = CopyExternalAsChild(*object_, *eobj);
162 return CORE_NS::EntityUtil::IsValid(ent) ? s->FindNode(ent, {}) : nullptr;
163 });
164 }
165 }
166 return {};
167 }
168
ImportChildScene(const IScene::ConstPtr & scene,BASE_NS::string_view nodeName)169 Future<INode::Ptr> Node::ImportChildScene(const IScene::ConstPtr& scene, BASE_NS::string_view nodeName)
170 {
171 if (auto s = GetInternalScene(); s && scene) {
172 if (scene != GetScene()) {
173 return s->AddTask([=, name = BASE_NS::string(nodeName)] {
174 BASE_NS::vector<CORE_NS::Entity> imported;
175 auto ent = CopyExternalAsChild(*object_, *scene, imported);
176 auto node = CORE_NS::EntityUtil::IsValid(ent) ? s->FindNode(ent, {}) : nullptr;
177 if (auto named = interface_cast<META_NS::INamed>(node)) {
178 named->Name()->SetValue(name);
179 SyncProperty(s, named->Name());
180 }
181 if (auto import = interface_cast<INodeImport>(node)) {
182 import->TrackImportedEntities(imported);
183 }
184 return node;
185 });
186 }
187 CORE_LOG_E("Cannot import a scene into itself.");
188 }
189 return {};
190 }
191
ImportChildScene(BASE_NS::string_view uri,BASE_NS::string_view nodeName)192 Future<INode::Ptr> Node::ImportChildScene(BASE_NS::string_view uri, BASE_NS::string_view nodeName)
193 {
194 if (auto s = GetInternalScene()) {
195 return s->AddTask([=, uri = BASE_NS::string(uri), name = BASE_NS::string(nodeName)] {
196 if (auto provider = interface_cast<IApplicationContextProvider>(s)) {
197 if (auto appContext = provider->GetApplicationContext()) {
198 if (auto manager = appContext->GetSceneManager()) {
199 auto scene = manager->CreateScene(uri, s->GetOptions()).GetResult();
200 return ImportChildScene(scene, name).GetResult();
201 }
202 }
203 }
204 return INode::Ptr {};
205 });
206 }
207 return {};
208 }
209
210 template<typename Func>
IterateImpl(const BASE_NS::vector<INode::Ptr> & cont,const Func & func)211 static META_NS::IterationResult IterateImpl(const BASE_NS::vector<INode::Ptr>& cont, const Func& func)
212 {
213 for (auto&& child : cont) {
214 if (auto obj = interface_pointer_cast<META_NS::IObject>(child)) {
215 auto res = func->Invoke(obj);
216 if (!res.Continue()) {
217 return res;
218 }
219 }
220 }
221 return META_NS::IterationResult::CONTINUE;
222 }
223
224 // --- IIterable
Iterate(const META_NS::IterationParameters & params)225 META_NS::IterationResult Node::Iterate(const META_NS::IterationParameters& params)
226 {
227 auto f = params.function.GetInterface<META_NS::IIterableCallable<META_NS::IObject::Ptr>>();
228 if (!f) {
229 CORE_LOG_W("Incompatible function with Iterate");
230 return META_NS::IterationResult::FAILED;
231 }
232 return IterateImpl(GetChildren().GetResult(), f);
233 }
Iterate(const META_NS::IterationParameters & params) const234 META_NS::IterationResult Node::Iterate(const META_NS::IterationParameters& params) const
235 {
236 auto f = params.function.GetInterface<META_NS::IIterableConstCallable<META_NS::IObject::Ptr>>();
237 if (!f) {
238 CORE_LOG_W("Incompatible function with Iterate");
239 return META_NS::IterationResult::FAILED;
240 }
241 return IterateImpl(GetChildren().GetResult(), f);
242 }
243 // --- IIterable
244
245 // --- IContainer
GetAll() const246 BASE_NS::vector<META_NS::IObject::Ptr> Node::GetAll() const
247 {
248 return META_NS::PtrArrayCast<IObject>(GetChildren().GetResult());
249 }
GetAt(SizeType index) const250 META_NS::IObject::Ptr Node::GetAt(SizeType index) const
251 {
252 auto children = GetChildren().GetResult();
253 return index < children.size() ? interface_pointer_cast<IObject>(children[index]) : nullptr;
254 }
GetSize() const255 META_NS::IContainer::SizeType Node::GetSize() const
256 {
257 return GetChildren().GetResult().size();
258 }
MatchCriteria(const META_NS::IContainer::FindOptions & options,const META_NS::IObject::Ptr & object)259 static bool MatchCriteria(const META_NS::IContainer::FindOptions& options, const META_NS::IObject::Ptr& object)
260 {
261 return object && (options.name.empty() || object->GetName() == options.name) &&
262 META_NS::CheckInterfaces(object, options.uids, options.strict);
263 }
FindAll(const FindOptions & options) const264 BASE_NS::vector<META_NS::IObject::Ptr> Node::FindAll(const FindOptions& options) const
265 {
266 BASE_NS::vector<IObject::Ptr> res;
267 META_NS::Internal::ConstIterate(
268 this,
269 [&](const IObject::Ptr& obj) {
270 if (MatchCriteria(options, obj)) {
271 res.push_back(obj);
272 }
273 return true;
274 },
275 META_NS::IterateStrategy { options.behavior, META_NS::LockType::SHARED_LOCK });
276 return res;
277 }
FindAny(const FindOptions & options) const278 META_NS::IObject::Ptr Node::FindAny(const FindOptions& options) const
279 {
280 IObject::Ptr res;
281 META_NS::Internal::ConstIterate(
282 this,
283 [&](const IObject::Ptr& obj) {
284 if (MatchCriteria(options, obj)) {
285 res = obj;
286 }
287 return !res;
288 },
289 META_NS::IterateStrategy { options.behavior, META_NS::LockType::SHARED_LOCK });
290 return res;
291 }
FindByName(BASE_NS::string_view name) const292 META_NS::IObject::Ptr Node::FindByName(BASE_NS::string_view name) const
293 {
294 return FindAny({ BASE_NS::string(name), META_NS::TraversalType::NO_HIERARCHY });
295 }
Add(const META_NS::IObject::Ptr & object)296 bool Node::Add(const META_NS::IObject::Ptr& object)
297 {
298 if (auto n = interface_pointer_cast<INode>(object)) {
299 return AddChild(n).GetResult();
300 }
301 return false;
302 }
Insert(SizeType index,const META_NS::IObject::Ptr & object)303 bool Node::Insert(SizeType index, const META_NS::IObject::Ptr& object)
304 {
305 if (auto n = interface_pointer_cast<INode>(object)) {
306 return AddChild(n, index).GetResult();
307 }
308 return false;
309 }
Remove(SizeType index)310 bool Node::Remove(SizeType index)
311 {
312 if (auto s = GetInternalScene()) {
313 return s
314 ->AddTask([&] {
315 auto obj = GetAt(index);
316 return obj && Remove(obj);
317 })
318 .GetResult();
319 }
320 return false;
321 }
Remove(const META_NS::IObject::Ptr & child)322 bool Node::Remove(const META_NS::IObject::Ptr& child)
323 {
324 if (auto n = interface_pointer_cast<INode>(child)) {
325 return RemoveChild(n).GetResult();
326 }
327 return false;
328 }
Move(SizeType fromIndex,SizeType toIndex)329 bool Node::Move(SizeType fromIndex, SizeType toIndex)
330 {
331 if (auto s = object_->GetScene()) {
332 return s
333 ->AddTask([&] {
334 auto obj = GetAt(fromIndex);
335 return Move(obj, toIndex);
336 })
337 .GetResult();
338 }
339 return false;
340 }
Move(const META_NS::IObject::Ptr & child,SizeType toIndex)341 bool Node::Move(const META_NS::IObject::Ptr& child, SizeType toIndex)
342 {
343 if (auto s = object_->GetScene()) {
344 return s->AddTask([&] { return child && Remove(child) && Insert(toIndex, child); }).GetResult();
345 }
346 return false;
347 }
Replace(const META_NS::IObject::Ptr & child,const META_NS::IObject::Ptr & replaceWith,bool addAlways)348 bool Node::Replace(const META_NS::IObject::Ptr& child, const META_NS::IObject::Ptr& replaceWith, bool addAlways)
349 {
350 if (auto s = object_->GetScene()) {
351 return s
352 ->AddTask([&] {
353 auto vec = GetAll();
354 size_t index = 0;
355 for (; index < vec.size(); ++index) {
356 if (vec[index] == child) {
357 break;
358 }
359 }
360 if (index == vec.size()) {
361 if (addAlways) {
362 Add(replaceWith);
363 return true;
364 }
365 return false;
366 }
367 return Remove(index) && Insert(index, replaceWith);
368 })
369 .GetResult();
370 }
371 return false;
372 }
RemoveAll()373 void Node::RemoveAll()
374 {
375 if (auto s = object_->GetScene()) {
376 s->AddTask([&] {
377 for (auto&& c : GetAll()) {
378 Remove(c);
379 }
380 }).Wait();
381 }
382 }
IsAncestorOf(const META_NS::IObject::ConstPtr & object) const383 bool Node::IsAncestorOf(const META_NS::IObject::ConstPtr& object) const
384 {
385 if (auto s = object_->GetScene()) {
386 return s
387 ->AddTask([&] {
388 auto node = interface_pointer_cast<INode>(object);
389 auto self = GetSelf<INode>();
390 do {
391 if (node == self) {
392 return true;
393 }
394 if (node) {
395 node = node->GetParent().GetResult();
396 }
397 } while (node);
398 return false;
399 })
400 .GetResult();
401 }
402 return false;
403 }
404
GetParent(ContainableTag) const405 META_NS::IObject::Ptr Node::GetParent(ContainableTag) const
406 {
407 return interface_pointer_cast<META_NS::IObject>(GetParent(NodeTag {}).GetResult());
408 }
409
410 // --- IContainer
411
OnMetadataConstructed(const META_NS::StaticMetadata & m,CORE_NS::IInterface & i)412 void Node::OnMetadataConstructed(const META_NS::StaticMetadata& m, CORE_NS::IInterface& i)
413 {
414 if (BASE_NS::string_view("OnContainerChanged") == m.name) {
415 if (auto s = object_->GetScene()) {
416 s->AddTask([&] { s->ListenNodeChanges(true); }).Wait();
417 }
418 }
419 }
420
OnChildChanged(META_NS::ContainerChangeType type,const INode::Ptr & child,size_t index)421 void Node::OnChildChanged(META_NS::ContainerChangeType type, const INode::Ptr& child, size_t index)
422 {
423 if (auto event = GetEvent("OnContainerChanged", META_NS::MetadataQuery::EXISTING)) {
424 if (auto s = object_->GetScene()) {
425 META_NS::ChildChangedInfo info { type, interface_pointer_cast<META_NS::IObject>(child),
426 GetSelf<META_NS::IContainer>() };
427 if (type == META_NS::ContainerChangeType::ADDED) {
428 info.to = index;
429 }
430 if (type == META_NS::ContainerChangeType::REMOVED) {
431 info.from = index;
432 }
433 s->InvokeUserNotification<META_NS::IOnChildChanged>(event, info);
434 }
435 }
436 }
437
TrackImportedEntities(BASE_NS::array_view<const CORE_NS::Entity> entities)438 void Node::TrackImportedEntities(BASE_NS::array_view<const CORE_NS::Entity> entities)
439 {
440 imported_.insert(imported_.end(), entities.begin(), entities.end());
441 }
442
IsListening() const443 bool Node::IsListening() const
444 {
445 return GetEvent("OnContainerChanged", META_NS::MetadataQuery::EXISTING) != nullptr;
446 }
447
OnNodeActiveStateChanged(NodeActiteStateInfo state)448 void Node::OnNodeActiveStateChanged(NodeActiteStateInfo state)
449 {
450 if (startableHandler_) {
451 if (state == NodeActiteStateInfo::ACTIVATED) {
452 startableHandler_->StartAll(StartableHandler::StartType::DEFERRED);
453 } else if (state == NodeActiteStateInfo::DEACTIVATING) {
454 startableHandler_->StopAll();
455 }
456 }
457 }
458
IsEnabledInHierarchy() const459 Future<bool> Node::IsEnabledInHierarchy() const
460 {
461 if (auto s = GetInternalScene()) {
462 return s->AddTask([=, ent = GetEntity()] {
463 auto& ecs = s->GetEcsContext();
464 if (auto c =
465 static_cast<CORE3D_NS::INodeComponentManager*>(ecs.FindComponent<CORE3D_NS::NodeComponent>())) {
466 if (auto v = c->Read(ent)) {
467 return v->effectivelyEnabled;
468 }
469 }
470 return false;
471 });
472 }
473 return {};
474 }
475
476 SCENE_END_NAMESPACE()
477