18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci#include "node_impl.h"
168bf80f4bSopenharmony_ci
178bf80f4bSopenharmony_ci#include "task_utils.h"
188bf80f4bSopenharmony_ci
198bf80f4bSopenharmony_ciusing SCENE_NS::MakeTask;
208bf80f4bSopenharmony_ci
218bf80f4bSopenharmony_ci#include <scene_plugin/api/material_uid.h>
228bf80f4bSopenharmony_ci#include <scene_plugin/api/mesh_uid.h>
238bf80f4bSopenharmony_ci#include <scene_plugin/api/scene_uid.h>
248bf80f4bSopenharmony_ci
258bf80f4bSopenharmony_ci#include "intf_multi_mesh_initialization.h"
268bf80f4bSopenharmony_ci
278bf80f4bSopenharmony_cibool HasChangedProperties(META_NS::IMetadata& meta)
288bf80f4bSopenharmony_ci{
298bf80f4bSopenharmony_ci    for (auto& property : meta.GetAllProperties()) {
308bf80f4bSopenharmony_ci        bool isInternal = META_NS::IsFlagSet(property, META_NS::ObjectFlagBits::INTERNAL);
318bf80f4bSopenharmony_ci        if (isInternal) {
328bf80f4bSopenharmony_ci            continue;
338bf80f4bSopenharmony_ci        }
348bf80f4bSopenharmony_ci
358bf80f4bSopenharmony_ci        bool isSerializable = META_NS::IsFlagSet(property, META_NS::ObjectFlagBits::SERIALIZE);
368bf80f4bSopenharmony_ci        if (isSerializable && property->IsValueSet()) {
378bf80f4bSopenharmony_ci            return true;
388bf80f4bSopenharmony_ci        }
398bf80f4bSopenharmony_ci    }
408bf80f4bSopenharmony_ci
418bf80f4bSopenharmony_ci    return false;
428bf80f4bSopenharmony_ci}
438bf80f4bSopenharmony_ci
448bf80f4bSopenharmony_cinamespace {
458bf80f4bSopenharmony_ci
468bf80f4bSopenharmony_cisize_t GetChildIndex(SCENE_NS::INode& parent, SCENE_NS::INode& child)
478bf80f4bSopenharmony_ci{
488bf80f4bSopenharmony_ci    auto object = interface_cast<META_NS::IObject>(&child);
498bf80f4bSopenharmony_ci
508bf80f4bSopenharmony_ci    auto container = interface_cast<META_NS::IContainer>(&parent);
518bf80f4bSopenharmony_ci    if (container) {
528bf80f4bSopenharmony_ci        for (auto i = 0; i < container->GetSize(); ++i) {
538bf80f4bSopenharmony_ci            if (container->GetAt(i).get() == object) {
548bf80f4bSopenharmony_ci                return i;
558bf80f4bSopenharmony_ci            }
568bf80f4bSopenharmony_ci        }
578bf80f4bSopenharmony_ci    }
588bf80f4bSopenharmony_ci
598bf80f4bSopenharmony_ci    return SIZE_MAX;
608bf80f4bSopenharmony_ci}
618bf80f4bSopenharmony_ci
628bf80f4bSopenharmony_ci} // namespace
638bf80f4bSopenharmony_ci
648bf80f4bSopenharmony_ci#include "bind_templates.inl"
658bf80f4bSopenharmony_ci
668bf80f4bSopenharmony_ci// implements CORE_NS::IInterface
678bf80f4bSopenharmony_ciconst CORE_NS::IInterface* NodeImpl::GetInterface(const BASE_NS::Uid& uid) const
688bf80f4bSopenharmony_ci{
698bf80f4bSopenharmony_ci    if (META_NS::TypeId(uid) == SCENE_NS::InterfaceId::IEnvironment.Id()) {
708bf80f4bSopenharmony_ci        return environment_.get();
718bf80f4bSopenharmony_ci    } else {
728bf80f4bSopenharmony_ci        return Fwd::GetInterface(uid);
738bf80f4bSopenharmony_ci    }
748bf80f4bSopenharmony_ci}
758bf80f4bSopenharmony_ci
768bf80f4bSopenharmony_ciCORE_NS::IInterface* NodeImpl::GetInterface(const BASE_NS::Uid& uid)
778bf80f4bSopenharmony_ci{
788bf80f4bSopenharmony_ci    if (META_NS::TypeId(uid) == SCENE_NS::InterfaceId::IEnvironment.Id()) {
798bf80f4bSopenharmony_ci        return environment_.get();
808bf80f4bSopenharmony_ci    } else {
818bf80f4bSopenharmony_ci        return Fwd::GetInterface(uid);
828bf80f4bSopenharmony_ci    }
838bf80f4bSopenharmony_ci}
848bf80f4bSopenharmony_ci
858bf80f4bSopenharmony_ciSCENE_NS::NodeState NodeImpl::GetAttachedState() const
868bf80f4bSopenharmony_ci{
878bf80f4bSopenharmony_ci    return attachedState_;
888bf80f4bSopenharmony_ci}
898bf80f4bSopenharmony_ci
908bf80f4bSopenharmony_cibool NodeImpl::IsConnected()
918bf80f4bSopenharmony_ci{
928bf80f4bSopenharmony_ci    if (Status()->GetValue() == SCENE_NS::INode::NODE_STATUS_CONNECTED ||
938bf80f4bSopenharmony_ci        Status()->GetValue() == SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED)
948bf80f4bSopenharmony_ci        return true;
958bf80f4bSopenharmony_ci
968bf80f4bSopenharmony_ci    return false;
978bf80f4bSopenharmony_ci}
988bf80f4bSopenharmony_ci
998bf80f4bSopenharmony_civoid NodeImpl::DisableInputHandling()
1008bf80f4bSopenharmony_ci{
1018bf80f4bSopenharmony_ci    /*auto inputMode = META_ACCESS_PROPERTY(InputMode);
1028bf80f4bSopenharmony_ci    if (auto i = interface_cast<META_NS::IMetaPropertyInternal>(inputMode)) {
1038bf80f4bSopenharmony_ci        auto flags = inputMode->Flags();
1048bf80f4bSopenharmony_ci        flags &= ~META_NS::IMetaProperty::PropertyFlagsValue(META_NS::IMetaProperty::PropertyFlagBits::SERIALIZABLE);
1058bf80f4bSopenharmony_ci        flags |= META_NS::IMetaProperty::PropertyFlagsValue(META_NS::IMetaProperty::PropertyFlagBits::INTERNAL);
1068bf80f4bSopenharmony_ci        i->SetFlags(flags);
1078bf80f4bSopenharmony_ci    }*/
1088bf80f4bSopenharmony_ci}
1098bf80f4bSopenharmony_ci
1108bf80f4bSopenharmony_cibool NodeImpl::Connect(const INode::Ptr& parent)
1118bf80f4bSopenharmony_ci{
1128bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("Node::Connect called for: '%s' (%s)", GetName().c_str(), Path()->Get().c_str());
1138bf80f4bSopenharmony_ci    if (parent) {
1148bf80f4bSopenharmony_ci        auto sceneObject = interface_pointer_cast<IObject>(parent->GetScene());
1158bf80f4bSopenharmony_ci        if (sceneObject) {
1168bf80f4bSopenharmony_ci            if (auto sceneInterface = interface_pointer_cast<SCENE_NS::IEcsScene>(sceneObject)) {
1178bf80f4bSopenharmony_ci                CORE_ASSERT(sceneInterface);
1188bf80f4bSopenharmony_ci
1198bf80f4bSopenharmony_ci                BASE_NS::string path = "/";
1208bf80f4bSopenharmony_ci                if (parent) {
1218bf80f4bSopenharmony_ci                    path = parent->Path()->GetValue() + parent->Name()->GetValue() + "/";
1228bf80f4bSopenharmony_ci                }
1238bf80f4bSopenharmony_ci
1248bf80f4bSopenharmony_ci                META_ACCESS_PROPERTY(Path)->SetValue(path);
1258bf80f4bSopenharmony_ci
1268bf80f4bSopenharmony_ci                if (!ecsObject_) {
1278bf80f4bSopenharmony_ci                    EnsureEcsBinding(sceneInterface);
1288bf80f4bSopenharmony_ci                }
1298bf80f4bSopenharmony_ci
1308bf80f4bSopenharmony_ci                return true;
1318bf80f4bSopenharmony_ci            }
1328bf80f4bSopenharmony_ci        }
1338bf80f4bSopenharmony_ci    }
1348bf80f4bSopenharmony_ci
1358bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("Node::Connect - NO PARENT - '%s'", GetName().c_str());
1368bf80f4bSopenharmony_ci    return false;
1378bf80f4bSopenharmony_ci}
1388bf80f4bSopenharmony_ci
1398bf80f4bSopenharmony_civoid NodeImpl::Activate()
1408bf80f4bSopenharmony_ci{
1418bf80f4bSopenharmony_ci    auto parent = interface_pointer_cast<INode>(GetParent());
1428bf80f4bSopenharmony_ci
1438bf80f4bSopenharmony_ci    if (auto sceneHolder = SceneHolder()) {
1448bf80f4bSopenharmony_ci        size_t index = SIZE_MAX;
1458bf80f4bSopenharmony_ci        BASE_NS::string path = "/";
1468bf80f4bSopenharmony_ci        if (parent) {
1478bf80f4bSopenharmony_ci            path = parent->Path()->GetValue() + parent->Name()->GetValue() + "/";
1488bf80f4bSopenharmony_ci            index = GetChildIndex(*parent, *this);
1498bf80f4bSopenharmony_ci        }
1508bf80f4bSopenharmony_ci        sceneHolder->QueueEngineTask(
1518bf80f4bSopenharmony_ci            META_NS::MakeCallback<META_NS::ITaskQueueTask>(
1528bf80f4bSopenharmony_ci                [path, index, e = ecsObject_->GetEntity(), weak_sh = BASE_NS::weak_ptr(sceneHolder)] {
1538bf80f4bSopenharmony_ci                    auto sh = weak_sh.lock();
1548bf80f4bSopenharmony_ci                    if (sh) {
1558bf80f4bSopenharmony_ci                        sh->SetEntityActive(e, true);
1568bf80f4bSopenharmony_ci                        sh->ReparentEntity(e, path, index);
1578bf80f4bSopenharmony_ci                    }
1588bf80f4bSopenharmony_ci                    return false;
1598bf80f4bSopenharmony_ci                }),
1608bf80f4bSopenharmony_ci            false);
1618bf80f4bSopenharmony_ci        META_ACCESS_PROPERTY(Path)->SetValue(path);
1628bf80f4bSopenharmony_ci        UpdateChildrenPath();
1638bf80f4bSopenharmony_ci        RecursivelyEnableCache(true);
1648bf80f4bSopenharmony_ci    }
1658bf80f4bSopenharmony_ci}
1668bf80f4bSopenharmony_ci
1678bf80f4bSopenharmony_civoid NodeImpl::Deactivate()
1688bf80f4bSopenharmony_ci{
1698bf80f4bSopenharmony_ci    if (auto sceneHolder = SceneHolder()) {
1708bf80f4bSopenharmony_ci        // TODO: Check if we can set parent to "invalid entity".
1718bf80f4bSopenharmony_ci        sceneHolder->QueueEngineTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>(
1728bf80f4bSopenharmony_ci                                         [e = ecsObject_->GetEntity(), weak_sh = BASE_NS::weak_ptr(sceneHolder)] {
1738bf80f4bSopenharmony_ci                                             auto sh = weak_sh.lock();
1748bf80f4bSopenharmony_ci                                             if (sh) {
1758bf80f4bSopenharmony_ci                                                 sh->SetEntityActive(e, false);
1768bf80f4bSopenharmony_ci                                             }
1778bf80f4bSopenharmony_ci                                             return false;
1788bf80f4bSopenharmony_ci                                         }),
1798bf80f4bSopenharmony_ci            false);
1808bf80f4bSopenharmony_ci
1818bf80f4bSopenharmony_ci        RecursivelyEnableCache(false);
1828bf80f4bSopenharmony_ci    }
1838bf80f4bSopenharmony_ci}
1848bf80f4bSopenharmony_ci
1858bf80f4bSopenharmony_civoid NodeImpl::AttachToHierarchy()
1868bf80f4bSopenharmony_ci{
1878bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG(
1888bf80f4bSopenharmony_ci        "Node::AttachToHierarchy called for: '%s' (%s)", GetName().c_str(), Path()->GetValue().c_str());
1898bf80f4bSopenharmony_ci
1908bf80f4bSopenharmony_ci    // If we have an entity, that we simply need to activate.
1918bf80f4bSopenharmony_ci    // If we are unbound, we need to try to bind this node to scene graph.
1928bf80f4bSopenharmony_ci    if (IsConnected()) {
1938bf80f4bSopenharmony_ci        Activate();
1948bf80f4bSopenharmony_ci    } else {
1958bf80f4bSopenharmony_ci        Connect(interface_pointer_cast<INode>(GetParent()));
1968bf80f4bSopenharmony_ci    }
1978bf80f4bSopenharmony_ci
1988bf80f4bSopenharmony_ci    attachedState_ = SCENE_NS::NodeState::ATTACHED;
1998bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("Node::AttachToHierarchy path is: '%s'", Path()->GetValue().c_str());
2008bf80f4bSopenharmony_ci}
2018bf80f4bSopenharmony_ci
2028bf80f4bSopenharmony_civoid NodeImpl::DetachFromHierarchy()
2038bf80f4bSopenharmony_ci{
2048bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG(
2058bf80f4bSopenharmony_ci        "Node::DetachFromHierarchy called for: '%s' (%s)", GetName().c_str(), Path()->GetValue().c_str());
2068bf80f4bSopenharmony_ci
2078bf80f4bSopenharmony_ci    // We are being detachad from the scene graph.
2088bf80f4bSopenharmony_ci    if (IsConnected()) {
2098bf80f4bSopenharmony_ci        // We simply need to deactivate.
2108bf80f4bSopenharmony_ci        Deactivate();
2118bf80f4bSopenharmony_ci    }
2128bf80f4bSopenharmony_ci
2138bf80f4bSopenharmony_ci    // TODO: Is there something we need to do here?
2148bf80f4bSopenharmony_ci    attachedState_ = SCENE_NS::NodeState::DETACHED;
2158bf80f4bSopenharmony_ci
2168bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("Node::DetachFromHierarchy path is: '%s'", Path()->GetValue().c_str());
2178bf80f4bSopenharmony_ci}
2188bf80f4bSopenharmony_ci
2198bf80f4bSopenharmony_civoid NodeImpl::SubscribeToNameChanges()
2208bf80f4bSopenharmony_ci{
2218bf80f4bSopenharmony_ci    if (!nameChangedToken_) {
2228bf80f4bSopenharmony_ci        nameChangedToken_ = Name()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this] {
2238bf80f4bSopenharmony_ci            if (IsResourceClassType() || ownsEntity_) {
2248bf80f4bSopenharmony_ci                RenameEntity(META_ACCESS_PROPERTY(Name)->GetValue());
2258bf80f4bSopenharmony_ci            }
2268bf80f4bSopenharmony_ci        }));
2278bf80f4bSopenharmony_ci    }
2288bf80f4bSopenharmony_ci}
2298bf80f4bSopenharmony_ci
2308bf80f4bSopenharmony_civoid NodeImpl::UnsubscribeFromNameChanges()
2318bf80f4bSopenharmony_ci{
2328bf80f4bSopenharmony_ci    if (nameChangedToken_) {
2338bf80f4bSopenharmony_ci        Name()->OnChanged()->RemoveHandler(nameChangedToken_);
2348bf80f4bSopenharmony_ci        nameChangedToken_ = { 0 };
2358bf80f4bSopenharmony_ci    }
2368bf80f4bSopenharmony_ci}
2378bf80f4bSopenharmony_ci
2388bf80f4bSopenharmony_cibool NodeImpl::IsResourceClassType()
2398bf80f4bSopenharmony_ci{
2408bf80f4bSopenharmony_ci    auto classUid = GetClassId();
2418bf80f4bSopenharmony_ci    bool isResourceClassType = (classUid == SCENE_NS::ClassId::Material) || // Material
2428bf80f4bSopenharmony_ci                               (classUid == SCENE_NS::ClassId::Mesh) ||     // Mesh
2438bf80f4bSopenharmony_ci                               (classUid == SCENE_NS::ClassId::Animation);  // Animation
2448bf80f4bSopenharmony_ci
2458bf80f4bSopenharmony_ci    return isResourceClassType;
2468bf80f4bSopenharmony_ci}
2478bf80f4bSopenharmony_ci/*
2488bf80f4bSopenharmony_cibool NodeImpl::Import(
2498bf80f4bSopenharmony_ci    META_NS::Serialization::IImportContext& context, const META_NS::Serialization::ClassPrimitive& value)
2508bf80f4bSopenharmony_ci{
2518bf80f4bSopenharmony_ci    if (!Fwd::Import(context, value)) {
2528bf80f4bSopenharmony_ci        return false;
2538bf80f4bSopenharmony_ci    }
2548bf80f4bSopenharmony_ci
2558bf80f4bSopenharmony_ci    // Backwards compatibility.
2568bf80f4bSopenharmony_ci    auto prop = GetPropertyByName("SceneUid");
2578bf80f4bSopenharmony_ci    if (prop) {
2588bf80f4bSopenharmony_ci        RemoveProperty(prop);
2598bf80f4bSopenharmony_ci    }
2608bf80f4bSopenharmony_ci
2618bf80f4bSopenharmony_ci    prop = GetPropertyByName("Path");
2628bf80f4bSopenharmony_ci    if (auto path = META_NS::property_cast<BASE_NS::string>(prop)) {
2638bf80f4bSopenharmony_ci        path->Reset();
2648bf80f4bSopenharmony_ci    }
2658bf80f4bSopenharmony_ci
2668bf80f4bSopenharmony_ci    return true;
2678bf80f4bSopenharmony_ci}
2688bf80f4bSopenharmony_ci*/
2698bf80f4bSopenharmony_cibool NodeImpl::Build(const IMetadata::Ptr& data)
2708bf80f4bSopenharmony_ci{
2718bf80f4bSopenharmony_ci    ClaimOwnershipOfEntity(false);
2728bf80f4bSopenharmony_ci
2738bf80f4bSopenharmony_ci    OnMoved()->AddHandler(META_NS::MakeCallback<META_NS::IOnChildMoved>([](const META_NS::ChildMovedInfo& info) {
2748bf80f4bSopenharmony_ci        auto parent = interface_cast<IObject>(info.parent.lock())->GetName();
2758bf80f4bSopenharmony_ci        auto object = info.object->GetName();
2768bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("Child '%s' moved in '%s'", object.c_str(), parent.c_str());
2778bf80f4bSopenharmony_ci    }));
2788bf80f4bSopenharmony_ci
2798bf80f4bSopenharmony_ci    PropertyNameMask().clear();
2808bf80f4bSopenharmony_ci    PropertyNameMask()[TRANSFORM_COMPONENT_NAME] = { TRANSFORM_POSITION.substr(TRANSFORM_COMPONENT_NAME_LEN),
2818bf80f4bSopenharmony_ci        TRANSFORM_SCALE.substr(TRANSFORM_COMPONENT_NAME_LEN), TRANSFORM_ROTATION.substr(TRANSFORM_COMPONENT_NAME_LEN) };
2828bf80f4bSopenharmony_ci    PropertyNameMask()[NODE_COMPONENT_NAME] = { NODE_ENABLED.substr(NODE_COMPONENT_NAME_LEN) };
2838bf80f4bSopenharmony_ci    PropertyNameMask()[LAYER_COMPONENT_NAME] = { LAYER_MASK.substr(LAYER_COMPONENT_NAME_LEN) };
2848bf80f4bSopenharmony_ci    PropertyNameMask()[LMATRIX_COMPONENT_NAME] = { LMATRIX_MATRIX.substr(LMATRIX_COMPONENT_NAME_LEN) };
2858bf80f4bSopenharmony_ci    PropertyNameMask()[RM_COMPONENT_NAME] = { RM_HANDLE.substr(RM_COMPONENT_NAME_LEN) };
2868bf80f4bSopenharmony_ci    PropertyNameMask()[ENVIRONMENT_COMPONENT_NAME] = {}; // read everything if it happens to be present
2878bf80f4bSopenharmony_ci
2888bf80f4bSopenharmony_ci    objectRegistry_ = &META_NS::GetObjectRegistry();
2898bf80f4bSopenharmony_ci    return true;
2908bf80f4bSopenharmony_ci}
2918bf80f4bSopenharmony_ci
2928bf80f4bSopenharmony_ciBASE_NS::string NodeImpl::GetName() const
2938bf80f4bSopenharmony_ci{
2948bf80f4bSopenharmony_ci    return META_NS::GetValue(Name());
2958bf80f4bSopenharmony_ci}
2968bf80f4bSopenharmony_ci
2978bf80f4bSopenharmony_ciCORE_NS::IEcs::Ptr NodeImpl::GetEcs() const
2988bf80f4bSopenharmony_ci{
2998bf80f4bSopenharmony_ci    if (ecsObject_) {
3008bf80f4bSopenharmony_ci        return ecsObject_->GetEcs();
3018bf80f4bSopenharmony_ci    }
3028bf80f4bSopenharmony_ci    return CORE_NS::IEcs::Ptr {};
3038bf80f4bSopenharmony_ci}
3048bf80f4bSopenharmony_ci
3058bf80f4bSopenharmony_civoid NodeImpl::SetEntity(CORE_NS::IEcs::Ptr ecs, CORE_NS::Entity entity)
3068bf80f4bSopenharmony_ci{
3078bf80f4bSopenharmony_ci    if (ecsObject_) {
3088bf80f4bSopenharmony_ci        return ecsObject_->SetEntity(ecs, entity);
3098bf80f4bSopenharmony_ci    }
3108bf80f4bSopenharmony_ci}
3118bf80f4bSopenharmony_ci
3128bf80f4bSopenharmony_ciCORE_NS::Entity NodeImpl::GetEntity() const
3138bf80f4bSopenharmony_ci{
3148bf80f4bSopenharmony_ci    if (ecsObject_) {
3158bf80f4bSopenharmony_ci        return ecsObject_->GetEntity();
3168bf80f4bSopenharmony_ci    }
3178bf80f4bSopenharmony_ci    return CORE_NS::Entity {};
3188bf80f4bSopenharmony_ci}
3198bf80f4bSopenharmony_ci
3208bf80f4bSopenharmony_civoid NodeImpl::BindObject(CORE_NS::IEcs::Ptr ecsInstance, CORE_NS::Entity entity)
3218bf80f4bSopenharmony_ci{
3228bf80f4bSopenharmony_ci    if (ecsObject_) {
3238bf80f4bSopenharmony_ci        ecsObject_->BindObject(ecsInstance, entity);
3248bf80f4bSopenharmony_ci    }
3258bf80f4bSopenharmony_ci}
3268bf80f4bSopenharmony_ci
3278bf80f4bSopenharmony_civoid NodeImpl::DefineTargetProperties(
3288bf80f4bSopenharmony_ci    BASE_NS::unordered_map<BASE_NS::string_view, BASE_NS::vector<BASE_NS::string_view>> names)
3298bf80f4bSopenharmony_ci{
3308bf80f4bSopenharmony_ci    if (ecsObject_) {
3318bf80f4bSopenharmony_ci        ecsObject_->DefineTargetProperties(names);
3328bf80f4bSopenharmony_ci    }
3338bf80f4bSopenharmony_ci}
3348bf80f4bSopenharmony_ci
3358bf80f4bSopenharmony_ciBASE_NS::vector<CORE_NS::Entity> NodeImpl::GetAttachments()
3368bf80f4bSopenharmony_ci{
3378bf80f4bSopenharmony_ci    if (ecsObject_) {
3388bf80f4bSopenharmony_ci        return ecsObject_->GetAttachments();
3398bf80f4bSopenharmony_ci    }
3408bf80f4bSopenharmony_ci    return BASE_NS::vector<CORE_NS::Entity> {};
3418bf80f4bSopenharmony_ci}
3428bf80f4bSopenharmony_ci
3438bf80f4bSopenharmony_civoid NodeImpl::AddAttachment(CORE_NS::Entity entity)
3448bf80f4bSopenharmony_ci{
3458bf80f4bSopenharmony_ci    if (ecsObject_) {
3468bf80f4bSopenharmony_ci        ecsObject_->AddAttachment(entity);
3478bf80f4bSopenharmony_ci    }
3488bf80f4bSopenharmony_ci}
3498bf80f4bSopenharmony_ci
3508bf80f4bSopenharmony_civoid NodeImpl::RemoveAttachment(CORE_NS::Entity entity)
3518bf80f4bSopenharmony_ci{
3528bf80f4bSopenharmony_ci    if (ecsObject_) {
3538bf80f4bSopenharmony_ci        ecsObject_->RemoveAttachment(entity);
3548bf80f4bSopenharmony_ci    }
3558bf80f4bSopenharmony_ci}
3568bf80f4bSopenharmony_ci
3578bf80f4bSopenharmony_civoid NodeImpl::CloneEcs(const BASE_NS::string& name, META_NS::IObject::Ptr target) const
3588bf80f4bSopenharmony_ci{
3598bf80f4bSopenharmony_ci    EcsScene()->AddEngineTask(
3608bf80f4bSopenharmony_ci        MakeTask(
3618bf80f4bSopenharmony_ci            [name, other = BASE_NS::weak_ptr(target)](auto self) {
3628bf80f4bSopenharmony_ci                if (auto sceneHolder = self->SceneHolder()) {
3638bf80f4bSopenharmony_ci                    // We have set the name unique, so for simplicity use it without padding
3648bf80f4bSopenharmony_ci                    auto clone = sceneHolder->CloneEntity(self->EcsObject()->GetEntity(), name, false);
3658bf80f4bSopenharmony_ci                    if (CORE_NS::EntityUtil::IsValid(clone)) {
3668bf80f4bSopenharmony_ci                        sceneHolder->QueueApplicationTask(MakeTask(
3678bf80f4bSopenharmony_ci                                                              [name](auto self, auto other) {
3688bf80f4bSopenharmony_ci                                                                  if (auto ret = static_pointer_cast<NodeImpl>(other)) {
3698bf80f4bSopenharmony_ci                                                                      META_NS::Property<uint32_t>(ret->GetLifecycleInfo())->SetValue(NODE_LC_CLONED);
3708bf80f4bSopenharmony_ci                                                                      ret->EnsureEcsBinding(self->EcsScene(), true);
3718bf80f4bSopenharmony_ci                                                                  }
3728bf80f4bSopenharmony_ci                                                                  return false;
3738bf80f4bSopenharmony_ci                                                              },
3748bf80f4bSopenharmony_ci                                                              self, other),
3758bf80f4bSopenharmony_ci                            false);
3768bf80f4bSopenharmony_ci                    }
3778bf80f4bSopenharmony_ci                }
3788bf80f4bSopenharmony_ci                return false;
3798bf80f4bSopenharmony_ci            },
3808bf80f4bSopenharmony_ci            static_pointer_cast<NodeImpl>(GetSelf())),
3818bf80f4bSopenharmony_ci        false);
3828bf80f4bSopenharmony_ci}
3838bf80f4bSopenharmony_ci
3848bf80f4bSopenharmony_ci/*META_NS::IObject::Ptr NodeImpl::GetClone(META_NS::ICloneableObject::CloneBehaviorFlags flags) const
3858bf80f4bSopenharmony_ci{
3868bf80f4bSopenharmony_ci    META_NS::IObject::Ptr ret = Super::GetClone(flags);
3878bf80f4bSopenharmony_ci    auto namebuf = BASE_NS::to_string(interface_cast<META_NS::IObjectInstance>(ret)->GetInstanceId());
3888bf80f4bSopenharmony_ci    BASE_NS::string name(namebuf.data(), namebuf.size());
3898bf80f4bSopenharmony_ci    META_NS::SetValue(interface_pointer_cast<META_NS::INamed>(ret)->Name(), name);
3908bf80f4bSopenharmony_ci    if (flags | META_NS::ICloneableObject::DEEP_CLONE_W_VALUES) {
3918bf80f4bSopenharmony_ci        // clone also entity
3928bf80f4bSopenharmony_ci        CloneEcs(name, ret);
3938bf80f4bSopenharmony_ci    } else {
3948bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("Cloned %s", name.c_str());
3958bf80f4bSopenharmony_ci    }
3968bf80f4bSopenharmony_ci
3978bf80f4bSopenharmony_ci    // ensure ecs bindings w/ new object
3988bf80f4bSopenharmony_ci    return ret;
3998bf80f4bSopenharmony_ci}*/
4008bf80f4bSopenharmony_ci
4018bf80f4bSopenharmony_ciSCENE_NS::IEcsScene::Ptr NodeImpl::EcsScene() const
4028bf80f4bSopenharmony_ci{
4038bf80f4bSopenharmony_ci    return ecsScene_.lock();
4048bf80f4bSopenharmony_ci}
4058bf80f4bSopenharmony_ci
4068bf80f4bSopenharmony_ciSCENE_NS::IEcsObject::Ptr NodeImpl::EcsObject() const
4078bf80f4bSopenharmony_ci{
4088bf80f4bSopenharmony_ci    return ecsObject_;
4098bf80f4bSopenharmony_ci}
4108bf80f4bSopenharmony_ci
4118bf80f4bSopenharmony_ciSceneHolder::Ptr NodeImpl::SceneHolder() const
4128bf80f4bSopenharmony_ci{
4138bf80f4bSopenharmony_ci    return sceneHolder_.lock();
4148bf80f4bSopenharmony_ci}
4158bf80f4bSopenharmony_ci
4168bf80f4bSopenharmony_civoid NodeImpl::ClaimOwnershipOfEntity(bool ownsEntity)
4178bf80f4bSopenharmony_ci{
4188bf80f4bSopenharmony_ci    ownsEntity_ = ownsEntity;
4198bf80f4bSopenharmony_ci    /*
4208bf80f4bSopenharmony_ci    if (!IsResourceClassType()) {
4218bf80f4bSopenharmony_ci        // If we do not own the target entity, the name property will be in read-only mode.
4228bf80f4bSopenharmony_ci        auto nameInternal = interface_pointer_cast<META_NS::IMetaPropertyInternal>(Name());
4238bf80f4bSopenharmony_ci        if (nameInternal) {
4248bf80f4bSopenharmony_ci            auto flags = Name()->Flags();
4258bf80f4bSopenharmony_ci
4268bf80f4bSopenharmony_ci            if (ownsEntity_) {
4278bf80f4bSopenharmony_ci                flags = META_NS::SetFlag(flags, META_NS::IMetaProperty::PropertyFlagBits::WRITE);
4288bf80f4bSopenharmony_ci            } else {
4298bf80f4bSopenharmony_ci                flags = META_NS::ResetFlag(flags, META_NS::IMetaProperty::PropertyFlagBits::WRITE);
4308bf80f4bSopenharmony_ci            }
4318bf80f4bSopenharmony_ci            nameInternal->SetFlags(flags);
4328bf80f4bSopenharmony_ci        }
4338bf80f4bSopenharmony_ci    }
4348bf80f4bSopenharmony_ci    */
4358bf80f4bSopenharmony_ci}
4368bf80f4bSopenharmony_ci
4378bf80f4bSopenharmony_civoid NodeImpl::RemoveIndex(size_t index)
4388bf80f4bSopenharmony_ci{
4398bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("remove node from %zu", index);
4408bf80f4bSopenharmony_ci    removeIndex_ = index;
4418bf80f4bSopenharmony_ci}
4428bf80f4bSopenharmony_ci
4438bf80f4bSopenharmony_civoid NodeImpl::SetIndex(size_t index)
4448bf80f4bSopenharmony_ci{
4458bf80f4bSopenharmony_ci    if (removeIndex_ == index) {
4468bf80f4bSopenharmony_ci        return;
4478bf80f4bSopenharmony_ci    }
4488bf80f4bSopenharmony_ci
4498bf80f4bSopenharmony_ci    if (removeIndex_ != SIZE_MAX && removeIndex_ < index) {
4508bf80f4bSopenharmony_ci        index--;
4518bf80f4bSopenharmony_ci    }
4528bf80f4bSopenharmony_ci
4538bf80f4bSopenharmony_ci    if (auto scene = EcsScene()) {
4548bf80f4bSopenharmony_ci        scene->AddEngineTask(MakeTask(
4558bf80f4bSopenharmony_ci                                 [index](auto self) {
4568bf80f4bSopenharmony_ci                                     if (auto sceneHolder = self->SceneHolder()) {
4578bf80f4bSopenharmony_ci                                         sceneHolder->ReindexEntity(self->EcsObject()->GetEntity(), index);
4588bf80f4bSopenharmony_ci                                     }
4598bf80f4bSopenharmony_ci                                     return false;
4608bf80f4bSopenharmony_ci                                 },
4618bf80f4bSopenharmony_ci                                 static_pointer_cast<NodeImpl>(GetSelf())),
4628bf80f4bSopenharmony_ci            false);
4638bf80f4bSopenharmony_ci    }
4648bf80f4bSopenharmony_ci    removeIndex_ = SIZE_MAX; // reset, this is not very convenient with subsequent async calls
4658bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("move node to %zu", index);
4668bf80f4bSopenharmony_ci}
4678bf80f4bSopenharmony_ci
4688bf80f4bSopenharmony_ciSCENE_NS::IScene::Ptr NodeImpl::GetScene() const
4698bf80f4bSopenharmony_ci{
4708bf80f4bSopenharmony_ci    return interface_pointer_cast<SCENE_NS::IScene>(ecsScene_);
4718bf80f4bSopenharmony_ci}
4728bf80f4bSopenharmony_ci
4738bf80f4bSopenharmony_civoid NodeImpl::RenameEntity(const BASE_NS::string& name)
4748bf80f4bSopenharmony_ci{
4758bf80f4bSopenharmony_ci    auto ecsScene = EcsScene();
4768bf80f4bSopenharmony_ci    if (!ecsScene) {
4778bf80f4bSopenharmony_ci        return;
4788bf80f4bSopenharmony_ci    }
4798bf80f4bSopenharmony_ci
4808bf80f4bSopenharmony_ci    ecsScene->AddEngineTask(MakeTask(
4818bf80f4bSopenharmony_ci                                [name](auto self) {
4828bf80f4bSopenharmony_ci                                    if (auto sceneHolder = self->SceneHolder()) {
4838bf80f4bSopenharmony_ci                                        sceneHolder->RenameEntity(self->EcsObject()->GetEntity(), name);
4848bf80f4bSopenharmony_ci                                    }
4858bf80f4bSopenharmony_ci                                    return false;
4868bf80f4bSopenharmony_ci                                },
4878bf80f4bSopenharmony_ci                                static_pointer_cast<NodeImpl>(GetSelf())),
4888bf80f4bSopenharmony_ci        false);
4898bf80f4bSopenharmony_ci    UpdateChildrenPath();
4908bf80f4bSopenharmony_ci}
4918bf80f4bSopenharmony_ci
4928bf80f4bSopenharmony_ci// Todo, this is assuming moderate size of hierarchy, may have to rethink the recursion if that is not the case
4938bf80f4bSopenharmony_civoid NodeImpl::RecursivelyEnableCache(bool isActive)
4948bf80f4bSopenharmony_ci{
4958bf80f4bSopenharmony_ci    if (auto scene = GetScene()) {
4968bf80f4bSopenharmony_ci        scene->SetCacheEnabled(GetSelf<SCENE_NS::INode>(), isActive);
4978bf80f4bSopenharmony_ci    }
4988bf80f4bSopenharmony_ci
4998bf80f4bSopenharmony_ci    if (auto container = GetSelf<META_NS::IContainer>()) {
5008bf80f4bSopenharmony_ci        for (auto& object : container->GetAll()) {
5018bf80f4bSopenharmony_ci            auto child = static_cast<NodeImpl*>(object.get());
5028bf80f4bSopenharmony_ci
5038bf80f4bSopenharmony_ci            child->RecursivelyEnableCache(isActive);
5048bf80f4bSopenharmony_ci        }
5058bf80f4bSopenharmony_ci    }
5068bf80f4bSopenharmony_ci}
5078bf80f4bSopenharmony_ci
5088bf80f4bSopenharmony_ci// Todo, this is assuming moderate size of hierarchy, may have to rethink the recursion if that is not the case
5098bf80f4bSopenharmony_civoid NodeImpl::UpdateChildrenPath()
5108bf80f4bSopenharmony_ci{
5118bf80f4bSopenharmony_ci    if (auto scene=GetScene()) {
5128bf80f4bSopenharmony_ci        scene->UpdateCachedNodePath(GetSelf<SCENE_NS::INode>());
5138bf80f4bSopenharmony_ci    }
5148bf80f4bSopenharmony_ci
5158bf80f4bSopenharmony_ci    if (auto container = GetSelf<META_NS::IContainer>()) {
5168bf80f4bSopenharmony_ci        auto cachedPath = META_ACCESS_PROPERTY(Path)->GetValue();
5178bf80f4bSopenharmony_ci        cachedPath.append(Name()->GetValue());
5188bf80f4bSopenharmony_ci        cachedPath.append("/");
5198bf80f4bSopenharmony_ci        for (auto& object : container->GetAll()) {
5208bf80f4bSopenharmony_ci            auto child = dynamic_cast<NodeImpl*>(object.get());
5218bf80f4bSopenharmony_ci            if (child) {
5228bf80f4bSopenharmony_ci                child->META_ACCESS_PROPERTY(Path)->SetValue(cachedPath);
5238bf80f4bSopenharmony_ci                child->UpdateChildrenPath();
5248bf80f4bSopenharmony_ci            }
5258bf80f4bSopenharmony_ci        }
5268bf80f4bSopenharmony_ci    }
5278bf80f4bSopenharmony_ci}
5288bf80f4bSopenharmony_ci
5298bf80f4bSopenharmony_cibool NodeImpl::ShouldExport() const
5308bf80f4bSopenharmony_ci{
5318bf80f4bSopenharmony_ci    bool isProxyNode = false;
5328bf80f4bSopenharmony_ci    auto priv = interface_cast<INodeEcsInterfacePrivate>(GetSelf());
5338bf80f4bSopenharmony_ci    if (META_NS::Property<uint32_t> lifeCycleInfo = priv->GetLifecycleInfo(false)) {
5348bf80f4bSopenharmony_ci        if (lifeCycleInfo->GetValue() == NODE_LC_MIRROR_EXISTING) {
5358bf80f4bSopenharmony_ci            isProxyNode = true;
5368bf80f4bSopenharmony_ci        }
5378bf80f4bSopenharmony_ci    }
5388bf80f4bSopenharmony_ci
5398bf80f4bSopenharmony_ci    if (!isProxyNode) {
5408bf80f4bSopenharmony_ci        isProxyNode = !ownsEntity_;
5418bf80f4bSopenharmony_ci    }
5428bf80f4bSopenharmony_ci
5438bf80f4bSopenharmony_ci    // If we have mesh that needs to be exported, then serialize self.
5448bf80f4bSopenharmony_ci    auto mesh = GetMesh();
5458bf80f4bSopenharmony_ci    if (auto privateInterface = interface_cast<INodeEcsInterfacePrivate>(mesh)) {
5468bf80f4bSopenharmony_ci        if (privateInterface->ShouldExport()) {
5478bf80f4bSopenharmony_ci            return true;
5488bf80f4bSopenharmony_ci        }
5498bf80f4bSopenharmony_ci    }
5508bf80f4bSopenharmony_ci
5518bf80f4bSopenharmony_ci    // Proxy node is exported if ..
5528bf80f4bSopenharmony_ci    if (isProxyNode) {
5538bf80f4bSopenharmony_ci        // It has changed properties.
5548bf80f4bSopenharmony_ci        if (HasChangedProperties(*GetSelf<META_NS::IMetadata>())) {
5558bf80f4bSopenharmony_ci            return true;
5568bf80f4bSopenharmony_ci        }
5578bf80f4bSopenharmony_ci
5588bf80f4bSopenharmony_ci        // It has attachments.
5598bf80f4bSopenharmony_ci        if (auto attach = GetSelf<META_NS::IAttach>()) {
5608bf80f4bSopenharmony_ci            if (attach->GetAttachments({}, false).size() > 0) {
5618bf80f4bSopenharmony_ci                return true;
5628bf80f4bSopenharmony_ci            }
5638bf80f4bSopenharmony_ci        }
5648bf80f4bSopenharmony_ci
5658bf80f4bSopenharmony_ci        // Any of its child needs to be exported.
5668bf80f4bSopenharmony_ci        if (auto container = GetSelf<META_NS::IContainer>()) {
5678bf80f4bSopenharmony_ci            for (auto& childNode : container->GetAll<INode>()) {
5688bf80f4bSopenharmony_ci                if (auto privateInterface = interface_cast<INodeEcsInterfacePrivate>(childNode)) {
5698bf80f4bSopenharmony_ci                    if (privateInterface->ShouldExport()) {
5708bf80f4bSopenharmony_ci                        return true;
5718bf80f4bSopenharmony_ci                    }
5728bf80f4bSopenharmony_ci                }
5738bf80f4bSopenharmony_ci            }
5748bf80f4bSopenharmony_ci        }
5758bf80f4bSopenharmony_ci
5768bf80f4bSopenharmony_ci        return false;
5778bf80f4bSopenharmony_ci    }
5788bf80f4bSopenharmony_ci
5798bf80f4bSopenharmony_ci    return true;
5808bf80f4bSopenharmony_ci}
5818bf80f4bSopenharmony_ci
5828bf80f4bSopenharmony_cibool NodeImpl::Initialize(SCENE_NS::IEcsScene::Ptr& scene, SCENE_NS::IEcsObject::Ptr& ecsObject,
5838bf80f4bSopenharmony_ci    SCENE_NS::INode::Ptr parent, const BASE_NS::string& path, const BASE_NS::string& name,
5848bf80f4bSopenharmony_ci    SceneHolder::WeakPtr sceneHolder, CORE_NS::Entity entity)
5858bf80f4bSopenharmony_ci{
5868bf80f4bSopenharmony_ci    if (!ecsObject || !scene) {
5878bf80f4bSopenharmony_ci        return false;
5888bf80f4bSopenharmony_ci    }
5898bf80f4bSopenharmony_ci
5908bf80f4bSopenharmony_ci    ecsScene_ = scene;
5918bf80f4bSopenharmony_ci    ecsObject_ = ecsObject;
5928bf80f4bSopenharmony_ci    sceneHolder_ = sceneHolder;
5938bf80f4bSopenharmony_ci
5948bf80f4bSopenharmony_ci    auto currentParent = GetParent();
5958bf80f4bSopenharmony_ci    if (!currentParent && parent) {
5968bf80f4bSopenharmony_ci        interface_cast<IContainer>(parent)->Add(GetSelf());
5978bf80f4bSopenharmony_ci    }
5988bf80f4bSopenharmony_ci
5998bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(ConnectionStatus)->SetBind(ecsObject->ConnectionStatus());
6008bf80f4bSopenharmony_ci
6018bf80f4bSopenharmony_ci    // Need to set a path before ECS instantiation to enable IContainer to share a proxy beforehand
6028bf80f4bSopenharmony_ci    SetPath(path, name, entity);
6038bf80f4bSopenharmony_ci    if (!ecsObject->GetEcs()) {
6048bf80f4bSopenharmony_ci        // We will not proceed further with construction until we have esc object bound
6058bf80f4bSopenharmony_ci        return false;
6068bf80f4bSopenharmony_ci    }
6078bf80f4bSopenharmony_ci
6088bf80f4bSopenharmony_ci    return true; // CompleteInitialization(path);
6098bf80f4bSopenharmony_ci}
6108bf80f4bSopenharmony_ci
6118bf80f4bSopenharmony_civoid NodeImpl::BindObject(SCENE_NS::INode::Ptr node)
6128bf80f4bSopenharmony_ci{
6138bf80f4bSopenharmony_ci    auto priv = interface_cast<INodeEcsInterfacePrivate>(node);
6148bf80f4bSopenharmony_ci    if (!priv) {
6158bf80f4bSopenharmony_ci        return;
6168bf80f4bSopenharmony_ci    }
6178bf80f4bSopenharmony_ci
6188bf80f4bSopenharmony_ci    if (priv->EcsObject()) {
6198bf80f4bSopenharmony_ci        return;
6208bf80f4bSopenharmony_ci    }
6218bf80f4bSopenharmony_ci
6228bf80f4bSopenharmony_ci    bool create = false;
6238bf80f4bSopenharmony_ci
6248bf80f4bSopenharmony_ci    if (META_NS::Property<uint32_t> creationPolicy = priv->GetLifecycleInfo()) {
6258bf80f4bSopenharmony_ci        create = (creationPolicy->GetValue() == NODE_LC_CREATED);
6268bf80f4bSopenharmony_ci    }
6278bf80f4bSopenharmony_ci
6288bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG(
6298bf80f4bSopenharmony_ci        "Connecting object from property: %s", (GetValue(node->Path()) + GetValue(node->Name())).c_str());
6308bf80f4bSopenharmony_ci    EcsScene()->BindNodeToEcs(node, GetValue(node->Path()) + GetValue(node->Name()), create);
6318bf80f4bSopenharmony_ci}
6328bf80f4bSopenharmony_ci
6338bf80f4bSopenharmony_cibool NodeImpl::CompleteInitialization(const BASE_NS::string& path)
6348bf80f4bSopenharmony_ci{
6358bf80f4bSopenharmony_ci    initializeTaskToken_ = {};
6368bf80f4bSopenharmony_ci
6378bf80f4bSopenharmony_ci    if (auto scene = EcsScene()) {
6388bf80f4bSopenharmony_ci        auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_);
6398bf80f4bSopenharmony_ci
6408bf80f4bSopenharmony_ci        if (auto name = Name()->GetValue(); name != path) {
6418bf80f4bSopenharmony_ci            RenameEntity(name);
6428bf80f4bSopenharmony_ci        }
6438bf80f4bSopenharmony_ci
6448bf80f4bSopenharmony_ci        // Ensure that our cache path is correct now that we have entity connected.
6458bf80f4bSopenharmony_ci        interface_cast<SCENE_NS::IScene>(scene)->UpdateCachedNodePath(GetSelf<SCENE_NS::INode>());
6468bf80f4bSopenharmony_ci
6478bf80f4bSopenharmony_ci        propHandler_.Reset();
6488bf80f4bSopenharmony_ci        propHandler_.SetSceneHolder(SceneHolder());
6498bf80f4bSopenharmony_ci
6508bf80f4bSopenharmony_ci        // Use node properties as default, in case we have created the entity to ECS.
6518bf80f4bSopenharmony_ci        propHandler_.SetUseEcsDefaults(!ownsEntity_);
6528bf80f4bSopenharmony_ci
6538bf80f4bSopenharmony_ci        BindChanges<BASE_NS::Math::Quat>(propHandler_, META_ACCESS_PROPERTY(Rotation), meta, TRANSFORM_ROTATION);
6548bf80f4bSopenharmony_ci        BindChanges<BASE_NS::Math::Vec3>(propHandler_, META_ACCESS_PROPERTY(Position), meta, TRANSFORM_POSITION);
6558bf80f4bSopenharmony_ci        BindChanges<BASE_NS::Math::Vec3>(propHandler_, META_ACCESS_PROPERTY(Scale), meta, TRANSFORM_SCALE);
6568bf80f4bSopenharmony_ci        BindChanges<bool>(propHandler_, META_ACCESS_PROPERTY(Visible), meta, NODE_ENABLED);
6578bf80f4bSopenharmony_ci        BindChanges<uint64_t>(propHandler_, META_ACCESS_PROPERTY(LayerMask), meta, LAYER_MASK);
6588bf80f4bSopenharmony_ci
6598bf80f4bSopenharmony_ci        // Restore default behavior.
6608bf80f4bSopenharmony_ci        propHandler_.SetUseEcsDefaults(true);
6618bf80f4bSopenharmony_ci
6628bf80f4bSopenharmony_ci        BindChanges<BASE_NS::Math::Mat4X4>(propHandler_, META_ACCESS_PROPERTY(LocalMatrix), meta, LMATRIX_MATRIX);
6638bf80f4bSopenharmony_ci
6648bf80f4bSopenharmony_ci        auto rh = meta->GetPropertyByName(RM_HANDLE);
6658bf80f4bSopenharmony_ci
6668bf80f4bSopenharmony_ci        auto mesh = META_NS::GetValue(Mesh());
6678bf80f4bSopenharmony_ci        if (mesh) {
6688bf80f4bSopenharmony_ci            // if se have a mesh set, initialize it
6698bf80f4bSopenharmony_ci            InitializeMesh(mesh, GetSelf<IEcsObject>());
6708bf80f4bSopenharmony_ci        } else if (rh) {
6718bf80f4bSopenharmony_ci            // otherwise get mesh from engine only if the component has render mesh present
6728bf80f4bSopenharmony_ci            GetMeshFromEngine();
6738bf80f4bSopenharmony_ci        }
6748bf80f4bSopenharmony_ci
6758bf80f4bSopenharmony_ci        // if the node has render mesh component, subscribe changes from engin
6768bf80f4bSopenharmony_ci        if (rh) {
6778bf80f4bSopenharmony_ci            rh->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this]() { GetMeshFromEngine(); }),
6788bf80f4bSopenharmony_ci                reinterpret_cast<uint64_t>(this));
6798bf80f4bSopenharmony_ci        }
6808bf80f4bSopenharmony_ci
6818bf80f4bSopenharmony_ci        // and set the proxy if user wants to change the mesh through the property
6828bf80f4bSopenharmony_ci        Mesh()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this]() {
6838bf80f4bSopenharmony_ci            if (auto node = interface_pointer_cast<SCENE_NS::INode>(META_NS::GetValue(Mesh()))) {
6848bf80f4bSopenharmony_ci                node->Status()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>(
6858bf80f4bSopenharmony_ci                    [](const auto& self, const auto& status) {
6868bf80f4bSopenharmony_ci                        if (self && status && status->GetValue() == SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED) {
6878bf80f4bSopenharmony_ci                            static_cast<NodeImpl*>(self.get())->SetMeshToEngine();
6888bf80f4bSopenharmony_ci                        }
6898bf80f4bSopenharmony_ci                    },
6908bf80f4bSopenharmony_ci                    GetSelf(), node->Status()));
6918bf80f4bSopenharmony_ci                if (auto status = META_NS::GetValue(node->Status());
6928bf80f4bSopenharmony_ci                    status == SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED ||
6938bf80f4bSopenharmony_ci                    status == SCENE_NS::INode::NODE_STATUS_CONNECTED) {
6948bf80f4bSopenharmony_ci                    SetMeshToEngine();
6958bf80f4bSopenharmony_ci                }
6968bf80f4bSopenharmony_ci            }
6978bf80f4bSopenharmony_ci        }),
6988bf80f4bSopenharmony_ci            reinterpret_cast<uint64_t>(this));
6998bf80f4bSopenharmony_ci
7008bf80f4bSopenharmony_ci        if (buildBehavior_ == NODE_BUILD_CHILDREN_GRADUAL) {
7018bf80f4bSopenharmony_ci            // We are assumingly on the correct thread already, but have deriving classes a slot to complete
7028bf80f4bSopenharmony_ci            // initialization Before notifying the client
7038bf80f4bSopenharmony_ci            scene->AddApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>(
7048bf80f4bSopenharmony_ci                                          [buildBehavior = buildBehavior_](const auto& node) {
7058bf80f4bSopenharmony_ci                                              if (node) {
7068bf80f4bSopenharmony_ci                                                  node->BuildChildren(buildBehavior);
7078bf80f4bSopenharmony_ci                                              }
7088bf80f4bSopenharmony_ci                                              return false;
7098bf80f4bSopenharmony_ci                                          },
7108bf80f4bSopenharmony_ci                                          GetSelf<SCENE_NS::INode>()),
7118bf80f4bSopenharmony_ci                true);
7128bf80f4bSopenharmony_ci        }
7138bf80f4bSopenharmony_ci
7148bf80f4bSopenharmony_ci        if (auto sceneHolder = SceneHolder()) {
7158bf80f4bSopenharmony_ci            for (auto& attachment : ecsObject_->GetAttachments()) {
7168bf80f4bSopenharmony_ci                if (auto animation = sceneHolder->GetAnimation(attachment)) {
7178bf80f4bSopenharmony_ci                    // Make flat animation array based on name-property + entity id separated by ':'
7188bf80f4bSopenharmony_ci                    // This is identical to meshes and materials, but the implementation is tad different
7198bf80f4bSopenharmony_ci                    auto name = META_NS::GetValue(interface_cast<META_NS::INamed>(animation)->Name());
7208bf80f4bSopenharmony_ci                    name.append(":");
7218bf80f4bSopenharmony_ci                    name.append(BASE_NS::to_hex(attachment.id));
7228bf80f4bSopenharmony_ci                    if (auto attachment = GetScene()->GetAnimation(name)) {
7238bf80f4bSopenharmony_ci                        if (auto typed = interface_cast<META_NS::IAttachment>(attachment)) {
7248bf80f4bSopenharmony_ci                            Attach(interface_pointer_cast<IObject>(attachment), GetSelf());
7258bf80f4bSopenharmony_ci                        }
7268bf80f4bSopenharmony_ci                    }
7278bf80f4bSopenharmony_ci                }
7288bf80f4bSopenharmony_ci            }
7298bf80f4bSopenharmony_ci        }
7308bf80f4bSopenharmony_ci
7318bf80f4bSopenharmony_ci        SubscribeToNameChanges();
7328bf80f4bSopenharmony_ci
7338bf80f4bSopenharmony_ci        return true;
7348bf80f4bSopenharmony_ci    }
7358bf80f4bSopenharmony_ci    return false;
7368bf80f4bSopenharmony_ci}
7378bf80f4bSopenharmony_ci
7388bf80f4bSopenharmony_civoid NodeImpl::SetPathWithEcsNode(const BASE_NS::shared_ptr<NodeImpl>& self, const BASE_NS::string& name,
7398bf80f4bSopenharmony_ci    SceneHolder::Ptr sceneHolder, const CORE3D_NS::ISceneNode* ecsNode)
7408bf80f4bSopenharmony_ci{
7418bf80f4bSopenharmony_ci    BASE_NS::weak_ptr<IObject> me = static_pointer_cast<IObject>(self);
7428bf80f4bSopenharmony_ci    if (!self->EcsObject()->GetEcs()) {
7438bf80f4bSopenharmony_ci        // Initialize ECS Object
7448bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("binding node: %s", name.c_str());
7458bf80f4bSopenharmony_ci        // We enable layer component just to have it handled consistently across
7468bf80f4bSopenharmony_ci        // the other properties, this may not be desired
7478bf80f4bSopenharmony_ci        auto entity = ecsNode->GetEntity();
7488bf80f4bSopenharmony_ci        sceneHolder->EnableLayerComponent(entity);
7498bf80f4bSopenharmony_ci
7508bf80f4bSopenharmony_ci        auto ecsObject = self->EcsObject();
7518bf80f4bSopenharmony_ci        // Introspect the engine components
7528bf80f4bSopenharmony_ci        if (auto proxyIf = interface_cast<SCENE_NS::IEcsProxyObject>(ecsObject)) {
7538bf80f4bSopenharmony_ci            proxyIf->SetCommonListener(sceneHolder->GetCommonEcsListener());
7548bf80f4bSopenharmony_ci        }
7558bf80f4bSopenharmony_ci        ecsObject->DefineTargetProperties(self->PropertyNameMask());
7568bf80f4bSopenharmony_ci        ecsObject->SetEntity(sceneHolder->GetEcs(), entity);
7578bf80f4bSopenharmony_ci        sceneHolder->UpdateAttachments(ecsObject);
7588bf80f4bSopenharmony_ci        sceneHolder->QueueApplicationTask(
7598bf80f4bSopenharmony_ci            MakeTask(
7608bf80f4bSopenharmony_ci                [name](auto selfObject) {
7618bf80f4bSopenharmony_ci                    if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
7628bf80f4bSopenharmony_ci                        self->CompleteInitialization(name);
7638bf80f4bSopenharmony_ci                        self->SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTED);
7648bf80f4bSopenharmony_ci                        if (auto node = interface_cast<SCENE_NS::INode>(selfObject)) {
7658bf80f4bSopenharmony_ci                            META_NS::Invoke<META_NS::IOnChanged>(node->OnLoaded());
7668bf80f4bSopenharmony_ci                        }
7678bf80f4bSopenharmony_ci                    }
7688bf80f4bSopenharmony_ci                    return false;
7698bf80f4bSopenharmony_ci                },
7708bf80f4bSopenharmony_ci                me),
7718bf80f4bSopenharmony_ci            false);
7728bf80f4bSopenharmony_ci    } else {
7738bf80f4bSopenharmony_ci        // ECS was already initialized, presumably we were just re-parented, update index
7748bf80f4bSopenharmony_ci        sceneHolder->QueueApplicationTask(MakeTask(
7758bf80f4bSopenharmony_ci                                              [](auto selfObject) {
7768bf80f4bSopenharmony_ci                                                  if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
7778bf80f4bSopenharmony_ci                                                      self->UpdateChildrenPath();
7788bf80f4bSopenharmony_ci                                                  }
7798bf80f4bSopenharmony_ci                                                  return false;
7808bf80f4bSopenharmony_ci                                              },
7818bf80f4bSopenharmony_ci                                              me),
7828bf80f4bSopenharmony_ci            false);
7838bf80f4bSopenharmony_ci    }
7848bf80f4bSopenharmony_ci}
7858bf80f4bSopenharmony_ci
7868bf80f4bSopenharmony_cibool NodeImpl::SetPathWithoutNode(const BASE_NS::shared_ptr<NodeImpl>& self, const BASE_NS::string& name,
7878bf80f4bSopenharmony_ci    const BASE_NS::string& fullPath, SceneHolder::Ptr sceneHolder)
7888bf80f4bSopenharmony_ci{
7898bf80f4bSopenharmony_ci    CORE_NS::Entity entity;
7908bf80f4bSopenharmony_ci    BASE_NS::weak_ptr<IObject> me = static_pointer_cast<IObject>(self);
7918bf80f4bSopenharmony_ci    if (sceneHolder->FindResource(name, fullPath, entity)) {
7928bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("binding resource: %s", name.c_str());
7938bf80f4bSopenharmony_ci        if (auto proxyIf = interface_cast<SCENE_NS::IEcsProxyObject>(self->EcsObject())) {
7948bf80f4bSopenharmony_ci            proxyIf->SetCommonListener(sceneHolder->GetCommonEcsListener());
7958bf80f4bSopenharmony_ci        }
7968bf80f4bSopenharmony_ci        self->EcsObject()->DefineTargetProperties(self->PropertyNameMask());
7978bf80f4bSopenharmony_ci        self->EcsObject()->SetEntity(sceneHolder->GetEcs(), entity);
7988bf80f4bSopenharmony_ci        sceneHolder->QueueApplicationTask(MakeTask(
7998bf80f4bSopenharmony_ci                                              [name](auto selfObject) {
8008bf80f4bSopenharmony_ci                                                  if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
8018bf80f4bSopenharmony_ci                                                      // There is not much to bind inside node, could presumably
8028bf80f4bSopenharmony_ci                                                      // fork this as own instance
8038bf80f4bSopenharmony_ci                                                      self->CompleteInitialization(name);
8048bf80f4bSopenharmony_ci                                                      self->SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTED);
8058bf80f4bSopenharmony_ci                                                      if (self->buildBehavior_ == NODE_BUILD_CHILDREN_ALL) {
8068bf80f4bSopenharmony_ci                                                          self->BuildChildren(self->buildBehavior_);
8078bf80f4bSopenharmony_ci                                                      }
8088bf80f4bSopenharmony_ci                                                      META_NS::Invoke<META_NS::IOnChanged>(self->OnLoaded());
8098bf80f4bSopenharmony_ci                                                  }
8108bf80f4bSopenharmony_ci                                                  return false;
8118bf80f4bSopenharmony_ci                                              },
8128bf80f4bSopenharmony_ci                                              me),
8138bf80f4bSopenharmony_ci            false);
8148bf80f4bSopenharmony_ci    } else if (META_NS::GetValue(self->GetScene()->Asynchronous()) && self->shouldRetry_) {
8158bf80f4bSopenharmony_ci        // When nodes are deserialized, it is possible that the construction order
8168bf80f4bSopenharmony_ci        // prepares children before their parent, just letting the task spin once more
8178bf80f4bSopenharmony_ci        // fixes the problem. ToDo: Get more elegant solution for this
8188bf80f4bSopenharmony_ci        self->shouldRetry_ = false;
8198bf80f4bSopenharmony_ci        return true;
8208bf80f4bSopenharmony_ci    } else {
8218bf80f4bSopenharmony_ci        // Giving in. If the node arrives later, it may be re-attempted due e.g. parent
8228bf80f4bSopenharmony_ci        // or name changes, otherwise we are done with it.
8238bf80f4bSopenharmony_ci        self->shouldRetry_ = true;
8248bf80f4bSopenharmony_ci        sceneHolder->QueueApplicationTask(MakeTask(
8258bf80f4bSopenharmony_ci                                              [name](auto selfObject) {
8268bf80f4bSopenharmony_ci                                                  if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
8278bf80f4bSopenharmony_ci                                                      self->SetStatus(SCENE_NS::INode::NODE_STATUS_DISCONNECTED);
8288bf80f4bSopenharmony_ci                                                  }
8298bf80f4bSopenharmony_ci                                                  return false;
8308bf80f4bSopenharmony_ci                                              },
8318bf80f4bSopenharmony_ci                                              me),
8328bf80f4bSopenharmony_ci            false);
8338bf80f4bSopenharmony_ci    }
8348bf80f4bSopenharmony_ci    return false;
8358bf80f4bSopenharmony_ci}
8368bf80f4bSopenharmony_ci
8378bf80f4bSopenharmony_ci// It is turning out that the path is pretty much the only thing that we can rely when operating asynchronously
8388bf80f4bSopenharmony_ci// from application thread to engine thread. Still this can go wrong if subsequent events are not recorded in
8398bf80f4bSopenharmony_ci// order.
8408bf80f4bSopenharmony_civoid NodeImpl::SetPath(const BASE_NS::string& path, const BASE_NS::string& name, CORE_NS::Entity entity)
8418bf80f4bSopenharmony_ci{
8428bf80f4bSopenharmony_ci    // BASE_NS::string name;
8438bf80f4bSopenharmony_ci
8448bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(Path)->SetValue(path);
8458bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(Name)->SetValue(name);
8468bf80f4bSopenharmony_ci
8478bf80f4bSopenharmony_ci    // SCENE_PLUGIN_VERBOSE_LOG("asking engine to make sure that: '%s' is child of '%s'", name.c_str(),
8488bf80f4bSopenharmony_ci    if (auto scene = EcsScene()) {
8498bf80f4bSopenharmony_ci        SetStatus(SCENE_NS::INode::NODE_STATUS_CONNECTING);
8508bf80f4bSopenharmony_ci        if (auto iscene = interface_cast<SCENE_NS::IScene>(scene)) {
8518bf80f4bSopenharmony_ci            iscene->UpdateCachedNodePath(GetSelf<SCENE_NS::INode>());
8528bf80f4bSopenharmony_ci        }
8538bf80f4bSopenharmony_ci
8548bf80f4bSopenharmony_ci        initializeTaskToken_ = scene->AddEngineTask(
8558bf80f4bSopenharmony_ci            MakeTask(
8568bf80f4bSopenharmony_ci                [name, fullpath = path + name](auto selfObject) {
8578bf80f4bSopenharmony_ci                    if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
8588bf80f4bSopenharmony_ci                        if (auto sceneHolder = self->SceneHolder()) {
8598bf80f4bSopenharmony_ci                            auto parentPath = self->META_ACCESS_PROPERTY(Path)
8608bf80f4bSopenharmony_ci                                                  ->GetValue(); // should also this be snapshot from App thread?
8618bf80f4bSopenharmony_ci
8628bf80f4bSopenharmony_ci                            auto ecsNode = sceneHolder->ReparentEntity(parentPath, name);
8638bf80f4bSopenharmony_ci
8648bf80f4bSopenharmony_ci                            if (ecsNode) {
8658bf80f4bSopenharmony_ci                                SetPathWithEcsNode(self, name, sceneHolder, ecsNode);
8668bf80f4bSopenharmony_ci                            } else {
8678bf80f4bSopenharmony_ci                                // The entity might be valid even if there is no node attached
8688bf80f4bSopenharmony_ci                                return SetPathWithoutNode(self, name, fullpath, sceneHolder);
8698bf80f4bSopenharmony_ci                            }
8708bf80f4bSopenharmony_ci                        }
8718bf80f4bSopenharmony_ci                    }
8728bf80f4bSopenharmony_ci                    return false;
8738bf80f4bSopenharmony_ci                },
8748bf80f4bSopenharmony_ci                GetSelf()),
8758bf80f4bSopenharmony_ci            false);
8768bf80f4bSopenharmony_ci    }
8778bf80f4bSopenharmony_ci}
8788bf80f4bSopenharmony_ci
8798bf80f4bSopenharmony_ci// static constexpr BASE_NS::string_view LIFECYCLE_PROPERTY_NAME = "NodeLifeCycle";
8808bf80f4bSopenharmony_ci
8818bf80f4bSopenharmony_cibool NodeImpl::HasLifecycleInfo()
8828bf80f4bSopenharmony_ci{
8838bf80f4bSopenharmony_ci    return GetLifecycleInfo(false) != nullptr;
8848bf80f4bSopenharmony_ci}
8858bf80f4bSopenharmony_ci
8868bf80f4bSopenharmony_ci// Different scenarios currently to be considered
8878bf80f4bSopenharmony_ci// 1) Create and bind a new prefab instance
8888bf80f4bSopenharmony_ci// -> create and assign ecs node
8898bf80f4bSopenharmony_ci// -> create new prefab instance
8908bf80f4bSopenharmony_ci// -> bind (read data from prefab)
8918bf80f4bSopenharmony_ci// prefab and its children need to know they were generated by prefab
8928bf80f4bSopenharmony_ci//
8938bf80f4bSopenharmony_ci// 2) Bind a new node to an existing entity:
8948bf80f4bSopenharmony_ci// this can take place throud two different routes, either the node is explicitly requested from the scene or
8958bf80f4bSopenharmony_ci// restored by de-serialization/import/clone
8968bf80f4bSopenharmony_ci// -> just prepare and assign ecs object
8978bf80f4bSopenharmony_ci// -> system will try find and sync the state later (potentially bidirectional sync)
8988bf80f4bSopenharmony_ci// values that are modified should have set-bits on properties
8998bf80f4bSopenharmony_ci//
9008bf80f4bSopenharmony_ci// 3) Create new proxy with entity and component with default values:
9018bf80f4bSopenharmony_ci// this is either through de-serialization or c++ api
9028bf80f4bSopenharmony_ci// -> sync the proxy state to ecs
9038bf80f4bSopenharmony_ci// information on entity creation needs to be preserved
9048bf80f4bSopenharmony_ci
9058bf80f4bSopenharmony_ciMETA_NS::IProperty::Ptr NodeImpl::GetLifecycleInfo(bool create)
9068bf80f4bSopenharmony_ci{
9078bf80f4bSopenharmony_ci    META_NS::IProperty::Ptr creationPolicy;
9088bf80f4bSopenharmony_ci    if (auto meta = GetSelf<META_NS::IMetadata>()) {
9098bf80f4bSopenharmony_ci        META_NS::IProperty::Ptr lifeCycle;
9108bf80f4bSopenharmony_ci        if (lifeCycle = meta->GetPropertyByName(LIFECYCLE_PROPERTY_NAME); !lifeCycle && create) {
9118bf80f4bSopenharmony_ci            auto p = META_NS::ConstructProperty<uint32_t>(LIFECYCLE_PROPERTY_NAME, 0, META_NS::DEFAULT_PROPERTY_FLAGS | META_NS::ObjectFlagBits::INTERNAL);
9128bf80f4bSopenharmony_ci            meta->AddProperty(p);
9138bf80f4bSopenharmony_ci            lifeCycle = p;
9148bf80f4bSopenharmony_ci        }
9158bf80f4bSopenharmony_ci
9168bf80f4bSopenharmony_ci        if (creationPolicy = META_NS::Property<uint32_t>(lifeCycle); !creationPolicy && create) {
9178bf80f4bSopenharmony_ci            CORE_LOG_E("%s: inconsistent system state. Can not store creation info for node", __func__);
9188bf80f4bSopenharmony_ci        }
9198bf80f4bSopenharmony_ci    }
9208bf80f4bSopenharmony_ci    return creationPolicy;
9218bf80f4bSopenharmony_ci}
9228bf80f4bSopenharmony_ci
9238bf80f4bSopenharmony_civoid NodeImpl::EnsureEcsBinding(SCENE_NS::IEcsScene::Ptr scene, bool force)
9248bf80f4bSopenharmony_ci{
9258bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("Node::EnsureEcsBinding called for %s (%s)", GetName().c_str(), Path()->Get().c_str());
9268bf80f4bSopenharmony_ci    if (scene && (force || !EcsScene())) {
9278bf80f4bSopenharmony_ci        BASE_NS::string fullPath = META_NS::GetValue(META_ACCESS_PROPERTY(Path));
9288bf80f4bSopenharmony_ci        fullPath.append(META_NS::GetValue(Name()));
9298bf80f4bSopenharmony_ci        auto self = GetSelf<SCENE_NS::INode>();
9308bf80f4bSopenharmony_ci
9318bf80f4bSopenharmony_ci        INodeEcsInterfacePrivate* privateParts { nullptr };
9328bf80f4bSopenharmony_ci
9338bf80f4bSopenharmony_ci	bool shouldCreate = true;
9348bf80f4bSopenharmony_ci        privateParts = interface_cast<INodeEcsInterfacePrivate>(self);
9358bf80f4bSopenharmony_ci        if (auto lifeCycleInfo = privateParts->GetLifecycleInfo(false)) {
9368bf80f4bSopenharmony_ci           if (auto value = META_NS::Property<uint32_t>(lifeCycleInfo)->GetValue()) {
9378bf80f4bSopenharmony_ci                shouldCreate = (value & NODE_LC_CLONED) || (value & NODE_LC_CREATED);
9388bf80f4bSopenharmony_ci            }
9398bf80f4bSopenharmony_ci        }
9408bf80f4bSopenharmony_ci        scene->BindNodeToEcs(self, fullPath, shouldCreate);
9418bf80f4bSopenharmony_ci    }
9428bf80f4bSopenharmony_ci}
9438bf80f4bSopenharmony_ci
9448bf80f4bSopenharmony_ciBASE_NS::vector<SCENE_NS::IProxyObject::PropertyPair> NodeImpl::ListBoundProperties() const
9458bf80f4bSopenharmony_ci{
9468bf80f4bSopenharmony_ci    return propHandler_.GetBoundProperties();
9478bf80f4bSopenharmony_ci}
9488bf80f4bSopenharmony_ci
9498bf80f4bSopenharmony_civoid NodeImpl::BuildChildrenIterateOver(const BASE_NS::shared_ptr<NodeImpl>& self, const SCENE_NS::IEcsScene::Ptr& ecs,
9508bf80f4bSopenharmony_ci    const BASE_NS::string& fullPath, BASE_NS::array_view<CORE3D_NS::ISceneNode* const> children)
9518bf80f4bSopenharmony_ci{
9528bf80f4bSopenharmony_ci    BASE_NS::weak_ptr<IObject> me = static_pointer_cast<IObject>(self);
9538bf80f4bSopenharmony_ci    for (const auto& child : children) {
9548bf80f4bSopenharmony_ci        auto childPath = fullPath;
9558bf80f4bSopenharmony_ci        auto childName = child->GetName();
9568bf80f4bSopenharmony_ci        if (!childName.empty() && childName.find("/") == BASE_NS::string_view::npos &&
9578bf80f4bSopenharmony_ci            !childName.starts_with(MULTI_MESH_CHILD_PREFIX)) {
9588bf80f4bSopenharmony_ci            childPath.append("/");
9598bf80f4bSopenharmony_ci            childPath.append(childName);
9608bf80f4bSopenharmony_ci
9618bf80f4bSopenharmony_ci            ecs->AddApplicationTask(
9628bf80f4bSopenharmony_ci                MakeTask(
9638bf80f4bSopenharmony_ci                    [childPath, childName](auto selfObject) {
9648bf80f4bSopenharmony_ci                        if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
9658bf80f4bSopenharmony_ci                            if (auto scene = self->GetScene()) {
9668bf80f4bSopenharmony_ci                                if (auto child = interface_pointer_cast<SCENE_NS::INode>(self->FindByName(childName))) {
9678bf80f4bSopenharmony_ci                                    self->MonitorChild(child);
9688bf80f4bSopenharmony_ci                                    // The call is pretty much costless when the ecs object has been already set, not
9698bf80f4bSopenharmony_ci                                    // sure if there is a code path that needs this, though
9708bf80f4bSopenharmony_ci                                    static_pointer_cast<NodeImpl>(child)->EnsureEcsBinding(self->EcsScene());
9718bf80f4bSopenharmony_ci                                } else {
9728bf80f4bSopenharmony_ci                                    auto node = scene->GetNode(childPath, META_NS::IObject::UID, self->buildBehavior_);
9738bf80f4bSopenharmony_ci                                    self->MonitorChild(node);
9748bf80f4bSopenharmony_ci                                    node->BuildChildren(self->buildBehavior_);
9758bf80f4bSopenharmony_ci                                }
9768bf80f4bSopenharmony_ci                            }
9778bf80f4bSopenharmony_ci                        }
9788bf80f4bSopenharmony_ci                        return false;
9798bf80f4bSopenharmony_ci                    },
9808bf80f4bSopenharmony_ci                    me),
9818bf80f4bSopenharmony_ci                false);
9828bf80f4bSopenharmony_ci        }
9838bf80f4bSopenharmony_ci    }
9848bf80f4bSopenharmony_ci}
9858bf80f4bSopenharmony_ci
9868bf80f4bSopenharmony_cibool NodeImpl::BuildChildren(SCENE_NS::INode::BuildBehavior options)
9878bf80f4bSopenharmony_ci{
9888bf80f4bSopenharmony_ci    buildBehavior_ = options;
9898bf80f4bSopenharmony_ci
9908bf80f4bSopenharmony_ci    if (options == SCENE_NS::INode::NODE_BUILD_CHILDREN_NO_BUILD || !GetScene()) {
9918bf80f4bSopenharmony_ci        return true;
9928bf80f4bSopenharmony_ci    }
9938bf80f4bSopenharmony_ci
9948bf80f4bSopenharmony_ci    if (!ecsObject_ || !ecsObject_->GetEcs()) {
9958bf80f4bSopenharmony_ci        if (!META_NS::GetValue(GetScene()->Asynchronous())) {
9968bf80f4bSopenharmony_ci            CORE_LOG_W("%s: no ecs available, cannot inspect children", __func__);
9978bf80f4bSopenharmony_ci        }
9988bf80f4bSopenharmony_ci        return false;
9998bf80f4bSopenharmony_ci    }
10008bf80f4bSopenharmony_ci
10018bf80f4bSopenharmony_ci    if (auto scene = EcsScene()) {
10028bf80f4bSopenharmony_ci        BASE_NS::string fullPath = META_ACCESS_PROPERTY(Path)->GetValue();
10038bf80f4bSopenharmony_ci        fullPath.append(Name()->GetValue());
10048bf80f4bSopenharmony_ci
10058bf80f4bSopenharmony_ci        if (fullPath.starts_with("/")) {
10068bf80f4bSopenharmony_ci            fullPath.erase(0, 1);
10078bf80f4bSopenharmony_ci        }
10088bf80f4bSopenharmony_ci        if (options == SCENE_NS::INode::NODE_BUILD_ONLY_DIRECT_CHILDREN) {
10098bf80f4bSopenharmony_ci            // yeah, for now.. let's just do this.
10108bf80f4bSopenharmony_ci            options = SCENE_NS::INode::NODE_BUILD_CHILDREN_GRADUAL;
10118bf80f4bSopenharmony_ci        }
10128bf80f4bSopenharmony_ci
10138bf80f4bSopenharmony_ci        scene->AddEngineTask(MakeTask([me = BASE_NS::weak_ptr(GetSelf()), fullPath]() {
10148bf80f4bSopenharmony_ci            if (auto self = static_pointer_cast<NodeImpl>(me.lock())) {
10158bf80f4bSopenharmony_ci                if (auto ecs = self->EcsScene()) {
10168bf80f4bSopenharmony_ci                    CORE3D_NS::INodeSystem* nodeSystem =
10178bf80f4bSopenharmony_ci                        static_cast<CORE3D_NS::INodeSystem*>(ecs->GetEcs()->GetSystem(CORE3D_NS::INodeSystem::UID));
10188bf80f4bSopenharmony_ci                    const auto& root = nodeSystem->GetRootNode();
10198bf80f4bSopenharmony_ci                    const auto& node = root.LookupNodeByPath(fullPath);
10208bf80f4bSopenharmony_ci                    if (!node) {
10218bf80f4bSopenharmony_ci                        CORE_LOG_W("%s: cannot find '%s'", __func__, fullPath.c_str());
10228bf80f4bSopenharmony_ci                    } else {
10238bf80f4bSopenharmony_ci                        // 1) on engine queue introspect children nodes
10248bf80f4bSopenharmony_ci                        const auto& children = node->GetChildren();
10258bf80f4bSopenharmony_ci                        if (children.size() == 0 &&
10268bf80f4bSopenharmony_ci                            META_NS::GetValue(self->Status()) != SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED) {
10278bf80f4bSopenharmony_ci                            ecs->AddApplicationTask(MakeTask(
10288bf80f4bSopenharmony_ci                                                        [](auto selfObject) {
10298bf80f4bSopenharmony_ci                                                            if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
10308bf80f4bSopenharmony_ci                                                                self->SetStatus(
10318bf80f4bSopenharmony_ci                                                                    SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED);
10328bf80f4bSopenharmony_ci                                                                META_NS::Invoke<META_NS::IOnChanged>(self->OnBound());
10338bf80f4bSopenharmony_ci                                                                self->bound_ = true;
10348bf80f4bSopenharmony_ci                                                            }
10358bf80f4bSopenharmony_ci                                                            return false;
10368bf80f4bSopenharmony_ci                                                        },
10378bf80f4bSopenharmony_ci                                                        me),
10388bf80f4bSopenharmony_ci                                false);
10398bf80f4bSopenharmony_ci                        } else {
10408bf80f4bSopenharmony_ci                            // 2) on app queue instantiate nodes
10418bf80f4bSopenharmony_ci                            BuildChildrenIterateOver(self, ecs, fullPath, children);
10428bf80f4bSopenharmony_ci
10438bf80f4bSopenharmony_ci                            // once we have iterated through children, check status once
10448bf80f4bSopenharmony_ci                            ecs->AddApplicationTask(MakeTask(
10458bf80f4bSopenharmony_ci                                                        [](auto selfObject) {
10468bf80f4bSopenharmony_ci                                                            if (auto self = static_pointer_cast<NodeImpl>(selfObject)) {
10478bf80f4bSopenharmony_ci                                                                self->CheckChildrenStatus();
10488bf80f4bSopenharmony_ci                                                            }
10498bf80f4bSopenharmony_ci                                                            return false;
10508bf80f4bSopenharmony_ci                                                        },
10518bf80f4bSopenharmony_ci                                                        me),
10528bf80f4bSopenharmony_ci                                false);
10538bf80f4bSopenharmony_ci                        }
10548bf80f4bSopenharmony_ci                    }
10558bf80f4bSopenharmony_ci                }
10568bf80f4bSopenharmony_ci            }
10578bf80f4bSopenharmony_ci            return false;
10588bf80f4bSopenharmony_ci        }),
10598bf80f4bSopenharmony_ci            false);
10608bf80f4bSopenharmony_ci    }
10618bf80f4bSopenharmony_ci    return true;
10628bf80f4bSopenharmony_ci}
10638bf80f4bSopenharmony_ci
10648bf80f4bSopenharmony_civoid NodeImpl::CheckChildrenStatus()
10658bf80f4bSopenharmony_ci{
10668bf80f4bSopenharmony_ci    for (const auto& child : monitored_) {
10678bf80f4bSopenharmony_ci        if (!child->Ready()) {
10688bf80f4bSopenharmony_ci            return;
10698bf80f4bSopenharmony_ci        }
10708bf80f4bSopenharmony_ci    }
10718bf80f4bSopenharmony_ci    size_t ix = 0;
10728bf80f4bSopenharmony_ci    while (ix < monitored_.size()) {
10738bf80f4bSopenharmony_ci        if (monitored_[ix]->Valid()) {
10748bf80f4bSopenharmony_ci            ix++;
10758bf80f4bSopenharmony_ci        } else {
10768bf80f4bSopenharmony_ci            monitored_.erase(monitored_.begin() + ix);
10778bf80f4bSopenharmony_ci        }
10788bf80f4bSopenharmony_ci    }
10798bf80f4bSopenharmony_ci
10808bf80f4bSopenharmony_ci    if (META_NS::GetValue(Status()) != SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED) {
10818bf80f4bSopenharmony_ci        SetStatus(SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED);
10828bf80f4bSopenharmony_ci    }
10838bf80f4bSopenharmony_ci
10848bf80f4bSopenharmony_ci    if (!bound_) {
10858bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG("%s: all children completed", META_NS::GetValue(Name()).c_str());
10868bf80f4bSopenharmony_ci        META_NS::Invoke<META_NS::IOnChanged>(OnBound());
10878bf80f4bSopenharmony_ci    }
10888bf80f4bSopenharmony_ci
10898bf80f4bSopenharmony_ci    bound_ = true;
10908bf80f4bSopenharmony_ci}
10918bf80f4bSopenharmony_ci
10928bf80f4bSopenharmony_ciBASE_NS::Math::Mat4X4 NodeImpl::GetGlobalTransform() const
10938bf80f4bSopenharmony_ci{
10948bf80f4bSopenharmony_ci    auto ret = BASE_NS::Math::IDENTITY_4X4;
10958bf80f4bSopenharmony_ci    BASE_NS::vector<META_NS::IContainable::Ptr> nodes;
10968bf80f4bSopenharmony_ci    nodes.push_back(GetSelf<META_NS::IContainable>());
10978bf80f4bSopenharmony_ci    auto current = nodes.back()->GetParent();
10988bf80f4bSopenharmony_ci    while (auto containable = interface_pointer_cast<META_NS::IContainable>(current)) {
10998bf80f4bSopenharmony_ci        nodes.push_back(containable);
11008bf80f4bSopenharmony_ci        current = nodes.back()->GetParent();
11018bf80f4bSopenharmony_ci    }
11028bf80f4bSopenharmony_ci
11038bf80f4bSopenharmony_ci    for (size_t ix = nodes.size(); ix != 0; ix--) {
11048bf80f4bSopenharmony_ci        ret = ret * META_NS::GetValue(interface_pointer_cast<INode>(nodes[ix - 1])->LocalMatrix());
11058bf80f4bSopenharmony_ci    }
11068bf80f4bSopenharmony_ci
11078bf80f4bSopenharmony_ci    return ret;
11088bf80f4bSopenharmony_ci}
11098bf80f4bSopenharmony_ci
11108bf80f4bSopenharmony_civoid NodeImpl::SetGlobalTransform(const BASE_NS::Math::Mat4X4& mat)
11118bf80f4bSopenharmony_ci{
11128bf80f4bSopenharmony_ci    auto global = BASE_NS::Math::IDENTITY_4X4;
11138bf80f4bSopenharmony_ci    BASE_NS::vector<META_NS::IContainable::Ptr> nodes;
11148bf80f4bSopenharmony_ci    nodes.push_back(GetSelf<META_NS::IContainable>());
11158bf80f4bSopenharmony_ci
11168bf80f4bSopenharmony_ci    auto current = nodes.back()->GetParent();
11178bf80f4bSopenharmony_ci    while (auto containable = interface_pointer_cast<META_NS::IContainable>(current)) {
11188bf80f4bSopenharmony_ci        nodes.push_back(containable);
11198bf80f4bSopenharmony_ci        current = nodes.back()->GetParent();
11208bf80f4bSopenharmony_ci    }
11218bf80f4bSopenharmony_ci
11228bf80f4bSopenharmony_ci    for (size_t ix = nodes.size(); ix != 1; ix--) {
11238bf80f4bSopenharmony_ci        global = global * META_NS::GetValue(interface_pointer_cast<INode>(nodes[ix - 1])->LocalMatrix());
11248bf80f4bSopenharmony_ci    }
11258bf80f4bSopenharmony_ci
11268bf80f4bSopenharmony_ci    // META_NS::SetValue(LocalMatrix(), mat / global);
11278bf80f4bSopenharmony_ci    auto newLocal = BASE_NS::Math::Inverse(global) * mat;
11288bf80f4bSopenharmony_ci    BASE_NS::Math::Quat rotation;
11298bf80f4bSopenharmony_ci    BASE_NS::Math::Vec3 scale;
11308bf80f4bSopenharmony_ci    BASE_NS::Math::Vec3 translate;
11318bf80f4bSopenharmony_ci    BASE_NS::Math::Vec3 skew;
11328bf80f4bSopenharmony_ci    BASE_NS::Math::Vec4 persp;
11338bf80f4bSopenharmony_ci    if (BASE_NS::Math::Decompose(newLocal, scale, rotation, translate, skew, persp)) {
11348bf80f4bSopenharmony_ci        META_NS::SetValue(Scale(), scale);
11358bf80f4bSopenharmony_ci        META_NS::SetValue(Rotation(), rotation);
11368bf80f4bSopenharmony_ci        META_NS::SetValue(Position(), translate);
11378bf80f4bSopenharmony_ci    }
11388bf80f4bSopenharmony_ci}
11398bf80f4bSopenharmony_ci
11408bf80f4bSopenharmony_civoid NodeImpl::MonitorChild(SCENE_NS::INode::Ptr node)
11418bf80f4bSopenharmony_ci{
11428bf80f4bSopenharmony_ci    for (auto& child : monitored_) {
11438bf80f4bSopenharmony_ci        if (*child == node) {
11448bf80f4bSopenharmony_ci            return;
11458bf80f4bSopenharmony_ci        }
11468bf80f4bSopenharmony_ci    }
11478bf80f4bSopenharmony_ci
11488bf80f4bSopenharmony_ci    monitored_.emplace_back(NodeMonitor::Create(node, *this));
11498bf80f4bSopenharmony_ci    bound_ = false;
11508bf80f4bSopenharmony_ci}
11518bf80f4bSopenharmony_ci
11528bf80f4bSopenharmony_civoid NodeImpl::SetMeshToEngine()
11538bf80f4bSopenharmony_ci{
11548bf80f4bSopenharmony_ci    if (auto mesh = META_NS::GetValue(Mesh())) {
11558bf80f4bSopenharmony_ci        if (auto ecsObject = interface_pointer_cast<SCENE_NS::IEcsObject>(mesh)) {
11568bf80f4bSopenharmony_ci            if (auto scene = EcsScene()) {
11578bf80f4bSopenharmony_ci                scene->AddEngineTask(
11588bf80f4bSopenharmony_ci                    MakeTask(
11598bf80f4bSopenharmony_ci                        [](const auto self, const auto meshObject) {
11608bf80f4bSopenharmony_ci                            if (auto sceneHolder = static_cast<NodeImpl*>(self.get())->SceneHolder()) {
11618bf80f4bSopenharmony_ci                                sceneHolder->SetMesh(self->GetEntity(), meshObject->GetEntity());
11628bf80f4bSopenharmony_ci                            }
11638bf80f4bSopenharmony_ci                            return false;
11648bf80f4bSopenharmony_ci                        },
11658bf80f4bSopenharmony_ci                        GetSelf<SCENE_NS::IEcsObject>(), interface_pointer_cast<SCENE_NS::IEcsObject>(mesh)),
11668bf80f4bSopenharmony_ci                    false);
11678bf80f4bSopenharmony_ci            }
11688bf80f4bSopenharmony_ci        }
11698bf80f4bSopenharmony_ci    }
11708bf80f4bSopenharmony_ci}
11718bf80f4bSopenharmony_ci
11728bf80f4bSopenharmony_civoid NodeImpl::SetMesh(SCENE_NS::IMesh::Ptr mesh)
11738bf80f4bSopenharmony_ci{
11748bf80f4bSopenharmony_ci    if (mesh == META_NS::GetValue(Mesh())) {
11758bf80f4bSopenharmony_ci        return; // the matching mesh is already set
11768bf80f4bSopenharmony_ci    }
11778bf80f4bSopenharmony_ci
11788bf80f4bSopenharmony_ci    META_NS::SetValue(Mesh(), mesh);
11798bf80f4bSopenharmony_ci}
11808bf80f4bSopenharmony_ci
11818bf80f4bSopenharmony_ciSCENE_NS::IMultiMeshProxy::Ptr NodeImpl::CreateMeshProxy(size_t count, SCENE_NS::IMesh::Ptr mesh)
11828bf80f4bSopenharmony_ci{
11838bf80f4bSopenharmony_ci    // SCENE_NS::IMultiMeshProxy::Ptr ret { SCENE_NS::MultiMeshProxy() };
11848bf80f4bSopenharmony_ci    SCENE_NS::IMultiMeshProxy::Ptr ret =
11858bf80f4bSopenharmony_ci        GetObjectRegistry().Create<SCENE_NS::IMultiMeshProxy>(SCENE_NS::ClassId::MultiMeshProxy);
11868bf80f4bSopenharmony_ci
11878bf80f4bSopenharmony_ci    interface_cast<IMultimeshInitilization>(ret)->Initialize(SceneHolder(), count, EcsObject()->GetEntity());
11888bf80f4bSopenharmony_ci
11898bf80f4bSopenharmony_ci    if (mesh) {
11908bf80f4bSopenharmony_ci        ret->Mesh()->SetValue(mesh);
11918bf80f4bSopenharmony_ci    }
11928bf80f4bSopenharmony_ci
11938bf80f4bSopenharmony_ci    // return
11948bf80f4bSopenharmony_ci    SetMultiMeshProxy(ret);
11958bf80f4bSopenharmony_ci    return ret;
11968bf80f4bSopenharmony_ci}
11978bf80f4bSopenharmony_ci
11988bf80f4bSopenharmony_civoid NodeImpl::SetMultiMeshProxy(SCENE_NS::IMultiMeshProxy::Ptr multimesh)
11998bf80f4bSopenharmony_ci{
12008bf80f4bSopenharmony_ci    multimesh_ = multimesh;
12018bf80f4bSopenharmony_ci}
12028bf80f4bSopenharmony_ci
12038bf80f4bSopenharmony_ciSCENE_NS::IMultiMeshProxy::Ptr NodeImpl::GetMultiMeshProxy() const
12048bf80f4bSopenharmony_ci{
12058bf80f4bSopenharmony_ci    return multimesh_;
12068bf80f4bSopenharmony_ci}
12078bf80f4bSopenharmony_ci
12088bf80f4bSopenharmony_civoid NodeImpl::ReleaseEntityOwnership()
12098bf80f4bSopenharmony_ci{
12108bf80f4bSopenharmony_ci    if (!ecsObject_) {
12118bf80f4bSopenharmony_ci        return;
12128bf80f4bSopenharmony_ci    }
12138bf80f4bSopenharmony_ci
12148bf80f4bSopenharmony_ci    auto entity = ecsObject_->GetEntity();
12158bf80f4bSopenharmony_ci    if (!CORE_NS::EntityUtil::IsValid(entity)) {
12168bf80f4bSopenharmony_ci        return;
12178bf80f4bSopenharmony_ci    }
12188bf80f4bSopenharmony_ci
12198bf80f4bSopenharmony_ci    auto sh = SceneHolder();
12208bf80f4bSopenharmony_ci    if (sh) {
12218bf80f4bSopenharmony_ci        auto attachments = ecsObject_->GetAttachments();
12228bf80f4bSopenharmony_ci        for (auto attachment : attachments) {
12238bf80f4bSopenharmony_ci            ecsObject_->RemoveAttachment(attachment);
12248bf80f4bSopenharmony_ci        }
12258bf80f4bSopenharmony_ci    }
12268bf80f4bSopenharmony_ci
12278bf80f4bSopenharmony_ci    if (sh) {
12288bf80f4bSopenharmony_ci        sh->SetEntityActive(entity, true);
12298bf80f4bSopenharmony_ci
12308bf80f4bSopenharmony_ci        if (ownsEntity_) {
12318bf80f4bSopenharmony_ci            sh->DestroyEntity(entity);
12328bf80f4bSopenharmony_ci        }
12338bf80f4bSopenharmony_ci
12348bf80f4bSopenharmony_ci        SetEntity(ecsObject_->GetEcs(), {});
12358bf80f4bSopenharmony_ci    }
12368bf80f4bSopenharmony_ci}
12378bf80f4bSopenharmony_ci
12388bf80f4bSopenharmony_civoid NodeImpl::Destroy()
12398bf80f4bSopenharmony_ci{
12408bf80f4bSopenharmony_ci    UnsubscribeFromNameChanges();
12418bf80f4bSopenharmony_ci
12428bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().Purge();
12438bf80f4bSopenharmony_ci
12448bf80f4bSopenharmony_ci    if (Name()) {
12458bf80f4bSopenharmony_ci        SCENE_PLUGIN_VERBOSE_LOG(
12468bf80f4bSopenharmony_ci            "Tearing down: %s%s", META_NS::GetValue(Path()).c_str(), META_NS::GetValue(Name()).c_str());
12478bf80f4bSopenharmony_ci        if (auto ecss = ecsScene_.lock()) {
12488bf80f4bSopenharmony_ci            ecss->CancelEngineTask(initializeTaskToken_);
12498bf80f4bSopenharmony_ci        }
12508bf80f4bSopenharmony_ci    }
12518bf80f4bSopenharmony_ci
12528bf80f4bSopenharmony_ci    ReleaseEntityOwnership();
12538bf80f4bSopenharmony_ci    Fwd::Destroy();
12548bf80f4bSopenharmony_ci}
12558bf80f4bSopenharmony_ci
12568bf80f4bSopenharmony_ciSCENE_NS::IPickingResult::Ptr NodeImpl::GetWorldMatrixComponentAABB(bool isRecursive) const
12578bf80f4bSopenharmony_ci{
12588bf80f4bSopenharmony_ci    auto ret = objectRegistry_->Create<SCENE_NS::IPickingResult>(SCENE_NS::ClassId::PendingVec3Request);
12598bf80f4bSopenharmony_ci    if (ret && SceneHolder()) {
12608bf80f4bSopenharmony_ci        SceneHolder()->QueueEngineTask(
12618bf80f4bSopenharmony_ci            META_NS::MakeCallback<META_NS::ITaskQueueTask>([isRecursive, weakRet = BASE_NS::weak_ptr(ret),
12628bf80f4bSopenharmony_ci                                                           weakSh = sceneHolder_,
12638bf80f4bSopenharmony_ci                                                           weakSelf = BASE_NS::weak_ptr(ecsObject_)]() {
12648bf80f4bSopenharmony_ci                if (auto sh = weakSh.lock()) {
12658bf80f4bSopenharmony_ci                    if (auto ret = weakRet.lock()) {
12668bf80f4bSopenharmony_ci                        if (auto self = weakSelf.lock()) {
12678bf80f4bSopenharmony_ci                            if (sh->GetWorldMatrixComponentAABB(ret, self->GetEntity(), isRecursive)) {
12688bf80f4bSopenharmony_ci                                sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet]() {
12698bf80f4bSopenharmony_ci                                    if (auto writable =
12708bf80f4bSopenharmony_ci                                            interface_pointer_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(
12718bf80f4bSopenharmony_ci                                                weakRet)) {
12728bf80f4bSopenharmony_ci                                        writable->MarkReady();
12738bf80f4bSopenharmony_ci                                    }
12748bf80f4bSopenharmony_ci                                    return false;
12758bf80f4bSopenharmony_ci                                }),
12768bf80f4bSopenharmony_ci                                    false);
12778bf80f4bSopenharmony_ci                            }
12788bf80f4bSopenharmony_ci                        }
12798bf80f4bSopenharmony_ci                    }
12808bf80f4bSopenharmony_ci                }
12818bf80f4bSopenharmony_ci                return false;
12828bf80f4bSopenharmony_ci            }),
12838bf80f4bSopenharmony_ci            false);
12848bf80f4bSopenharmony_ci        return ret;
12858bf80f4bSopenharmony_ci    }
12868bf80f4bSopenharmony_ci    return SCENE_NS::IPickingResult::Ptr();
12878bf80f4bSopenharmony_ci}
12888bf80f4bSopenharmony_ci
12898bf80f4bSopenharmony_ciSCENE_NS::IPickingResult::Ptr NodeImpl::GetTransformComponentAABB(bool isRecursive) const
12908bf80f4bSopenharmony_ci{
12918bf80f4bSopenharmony_ci    auto ret = objectRegistry_->Create<SCENE_NS::IPickingResult>(SCENE_NS::ClassId::PendingVec3Request);
12928bf80f4bSopenharmony_ci    if (ret && SceneHolder()) {
12938bf80f4bSopenharmony_ci        SceneHolder()->QueueEngineTask(
12948bf80f4bSopenharmony_ci            META_NS::MakeCallback<META_NS::ITaskQueueTask>([isRecursive, weakRet = BASE_NS::weak_ptr(ret),
12958bf80f4bSopenharmony_ci                                                           weakSh = sceneHolder_,
12968bf80f4bSopenharmony_ci                                                           weakSelf = BASE_NS::weak_ptr(ecsObject_)]() {
12978bf80f4bSopenharmony_ci                if (auto sh = weakSh.lock()) {
12988bf80f4bSopenharmony_ci                    if (auto ret = weakRet.lock()) {
12998bf80f4bSopenharmony_ci                        if (auto self = weakSelf.lock()) {
13008bf80f4bSopenharmony_ci                            if (sh->GetTransformComponentAABB(ret, self->GetEntity(), isRecursive)) {
13018bf80f4bSopenharmony_ci                                sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet]() {
13028bf80f4bSopenharmony_ci                                    if (auto writable =
13038bf80f4bSopenharmony_ci                                            interface_pointer_cast<SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(
13048bf80f4bSopenharmony_ci                                                weakRet)) {
13058bf80f4bSopenharmony_ci                                        writable->MarkReady();
13068bf80f4bSopenharmony_ci                                    }
13078bf80f4bSopenharmony_ci                                    return false;
13088bf80f4bSopenharmony_ci                                }),
13098bf80f4bSopenharmony_ci                                    false);
13108bf80f4bSopenharmony_ci                            }
13118bf80f4bSopenharmony_ci                        }
13128bf80f4bSopenharmony_ci                    }
13138bf80f4bSopenharmony_ci                }
13148bf80f4bSopenharmony_ci                return false;
13158bf80f4bSopenharmony_ci            }),
13168bf80f4bSopenharmony_ci            false);
13178bf80f4bSopenharmony_ci        return ret;
13188bf80f4bSopenharmony_ci    }
13198bf80f4bSopenharmony_ci    return SCENE_NS::IPickingResult::Ptr();
13208bf80f4bSopenharmony_ci}
13218bf80f4bSopenharmony_ci
13228bf80f4bSopenharmony_civoid NodeImpl::SetStatus(SCENE_NS::INode::NodeStatus status)
13238bf80f4bSopenharmony_ci{
13248bf80f4bSopenharmony_ci    META_ACCESS_PROPERTY(Status)->SetValue(status);
13258bf80f4bSopenharmony_ci}
13268bf80f4bSopenharmony_ci/*
13278bf80f4bSopenharmony_cibool NodeImpl::Export(
13288bf80f4bSopenharmony_ci    META_NS::Serialization::IExportContext& context, META_NS::Serialization::ClassPrimitive& value) const
13298bf80f4bSopenharmony_ci{
13308bf80f4bSopenharmony_ci    if (!ShouldExport()) {
13318bf80f4bSopenharmony_ci        return false;
13328bf80f4bSopenharmony_ci    }
13338bf80f4bSopenharmony_ci
13348bf80f4bSopenharmony_ci    SCENE_PLUGIN_VERBOSE_LOG("NodeImpl::%s %s", __func__, Name()->Get().c_str());
13358bf80f4bSopenharmony_ci    return Fwd::Export(context, value);
13368bf80f4bSopenharmony_ci}
13378bf80f4bSopenharmony_ci*/
13388bf80f4bSopenharmony_civoid NodeImpl::SetSuperInstance(const IObject::Ptr& aggr, const IObject::Ptr& super)
13398bf80f4bSopenharmony_ci{
13408bf80f4bSopenharmony_ci    Fwd::SetSuperInstance(aggr, super);
13418bf80f4bSopenharmony_ci    containable_ = interface_cast<IContainable>(super);
13428bf80f4bSopenharmony_ci    mutableContainable_ = interface_cast<IMutableContainable>(super);
13438bf80f4bSopenharmony_ci}
13448bf80f4bSopenharmony_ci
13458bf80f4bSopenharmony_civoid NodeImpl::SetParent(const IObject::Ptr& parent)
13468bf80f4bSopenharmony_ci{
13478bf80f4bSopenharmony_ci    if (mutableContainable_) {
13488bf80f4bSopenharmony_ci        mutableContainable_->SetParent(parent);
13498bf80f4bSopenharmony_ci    } else {
13508bf80f4bSopenharmony_ci        parent_ = parent;
13518bf80f4bSopenharmony_ci    }
13528bf80f4bSopenharmony_ci}
13538bf80f4bSopenharmony_ci
13548bf80f4bSopenharmony_ciMETA_NS::IObject::Ptr NodeImpl::GetParent() const
13558bf80f4bSopenharmony_ci{
13568bf80f4bSopenharmony_ci    if (containable_) {
13578bf80f4bSopenharmony_ci        return containable_->GetParent();
13588bf80f4bSopenharmony_ci    }
13598bf80f4bSopenharmony_ci
13608bf80f4bSopenharmony_ci    auto parent = parent_.lock();
13618bf80f4bSopenharmony_ci    if (parent) {
13628bf80f4bSopenharmony_ci        return parent;
13638bf80f4bSopenharmony_ci    }
13648bf80f4bSopenharmony_ci
13658bf80f4bSopenharmony_ci    return {};
13668bf80f4bSopenharmony_ci}
13678bf80f4bSopenharmony_ci
13688bf80f4bSopenharmony_ciSCENE_NS::IMesh::Ptr NodeImpl::GetMesh() const
13698bf80f4bSopenharmony_ci{
13708bf80f4bSopenharmony_ci    return META_NS::GetValue(Mesh());
13718bf80f4bSopenharmony_ci}
13728bf80f4bSopenharmony_ci
13738bf80f4bSopenharmony_civoid NodeImpl::InitializeMesh(
13748bf80f4bSopenharmony_ci    const SCENE_NS::IMesh::Ptr& mesh, const BASE_NS::shared_ptr<NodeImpl>& node, const BASE_NS::string_view entityName)
13758bf80f4bSopenharmony_ci{
13768bf80f4bSopenharmony_ci    auto scene = node->EcsScene();
13778bf80f4bSopenharmony_ci    if (auto ecsObject = META_NS::GetObjectRegistry().Create<SCENE_NS::IEcsObject>(SCENE_NS::ClassId::EcsObject)) {
13788bf80f4bSopenharmony_ci        if (auto privateInit = interface_cast<INodeEcsInterfacePrivate>(mesh)) {
13798bf80f4bSopenharmony_ci            privateInit->Initialize(scene, ecsObject, {}, "", BASE_NS::string(entityName), node->SceneHolder(), {});
13808bf80f4bSopenharmony_ci        }
13818bf80f4bSopenharmony_ci    }
13828bf80f4bSopenharmony_ci}
13838bf80f4bSopenharmony_ci
13848bf80f4bSopenharmony_civoid NodeImpl::InitializeMesh(const SCENE_NS::IMesh::Ptr& mesh, const BASE_NS::shared_ptr<SCENE_NS::IEcsObject>& self)
13858bf80f4bSopenharmony_ci{
13868bf80f4bSopenharmony_ci    auto strongMe = interface_pointer_cast<IObject>(self);
13878bf80f4bSopenharmony_ci    if (auto node = static_pointer_cast<NodeImpl>(strongMe)) {
13888bf80f4bSopenharmony_ci        if (auto sceneHolder = node->SceneHolder()) {
13898bf80f4bSopenharmony_ci            auto entityName = sceneHolder->GetMeshName(self->GetEntity());
13908bf80f4bSopenharmony_ci            if (!entityName.empty()) {
13918bf80f4bSopenharmony_ci                sceneHolder->QueueApplicationTask(MakeTask(
13928bf80f4bSopenharmony_ci                                                      [entityName, mesh](auto selfObject) {
13938bf80f4bSopenharmony_ci                                                          if (auto node = static_pointer_cast<NodeImpl>(selfObject)) {
13948bf80f4bSopenharmony_ci                                                              InitializeMesh(mesh, node, entityName);
13958bf80f4bSopenharmony_ci                                                          }
13968bf80f4bSopenharmony_ci                                                          return false;
13978bf80f4bSopenharmony_ci                                                      },
13988bf80f4bSopenharmony_ci                                                      strongMe),
13998bf80f4bSopenharmony_ci                    false);
14008bf80f4bSopenharmony_ci            }
14018bf80f4bSopenharmony_ci        }
14028bf80f4bSopenharmony_ci    }
14038bf80f4bSopenharmony_ci}
14048bf80f4bSopenharmony_ci
14058bf80f4bSopenharmony_ciSCENE_NS::IMesh::Ptr NodeImpl::GetMeshFromEngine()
14068bf80f4bSopenharmony_ci{
14078bf80f4bSopenharmony_ci    SCENE_NS::IMesh::Ptr ret {};
14088bf80f4bSopenharmony_ci    if (auto iscene = GetScene()) {
14098bf80f4bSopenharmony_ci        if (META_NS::GetValue(iscene->Asynchronous()) == false) {
14108bf80f4bSopenharmony_ci            auto entityName = SceneHolder()->GetMeshName(EcsObject()->GetEntity());
14118bf80f4bSopenharmony_ci            if (!entityName.empty()) {
14128bf80f4bSopenharmony_ci                ret = iscene->GetMesh(entityName);
14138bf80f4bSopenharmony_ci            }
14148bf80f4bSopenharmony_ci        }
14158bf80f4bSopenharmony_ci    }
14168bf80f4bSopenharmony_ci
14178bf80f4bSopenharmony_ci    if (!ret) {
14188bf80f4bSopenharmony_ci        ret = GetObjectRegistry().Create<SCENE_NS::IMesh>(SCENE_NS::ClassId::Mesh);
14198bf80f4bSopenharmony_ci
14208bf80f4bSopenharmony_ci        if (auto scene = EcsScene()) {
14218bf80f4bSopenharmony_ci            scene->AddEngineTask(MakeTask(
14228bf80f4bSopenharmony_ci                                     [ret](auto selfObject) {
14238bf80f4bSopenharmony_ci                                         if (auto self = interface_pointer_cast<SCENE_NS::IEcsObject>(selfObject)) {
14248bf80f4bSopenharmony_ci                                             InitializeMesh(ret, self);
14258bf80f4bSopenharmony_ci                                         }
14268bf80f4bSopenharmony_ci                                         return false;
14278bf80f4bSopenharmony_ci                                     },
14288bf80f4bSopenharmony_ci                                     GetSelf()),
14298bf80f4bSopenharmony_ci                false);
14308bf80f4bSopenharmony_ci        }
14318bf80f4bSopenharmony_ci    }
14328bf80f4bSopenharmony_ci    if (auto node = interface_cast<SCENE_NS::INode>(ret)) {
14338bf80f4bSopenharmony_ci        if (META_NS::GetValue(node->Status()) != SCENE_NS::INode::NODE_STATUS_DISCONNECTED) {
14348bf80f4bSopenharmony_ci            META_NS::SetValue(Mesh(), ret);
14358bf80f4bSopenharmony_ci        }
14368bf80f4bSopenharmony_ci    }
14378bf80f4bSopenharmony_ci
14388bf80f4bSopenharmony_ci    return ret;
14398bf80f4bSopenharmony_ci}
14408bf80f4bSopenharmony_ci
14418bf80f4bSopenharmony_ciusing PropertyNameCriteria = BASE_NS::unordered_map<BASE_NS::string_view, BASE_NS::vector<BASE_NS::string_view>>;
14428bf80f4bSopenharmony_ciPropertyNameCriteria& NodeImpl::PropertyNameMask()
14438bf80f4bSopenharmony_ci{
14448bf80f4bSopenharmony_ci    return ecs_property_names_;
14458bf80f4bSopenharmony_ci}
14468bf80f4bSopenharmony_ci
14478bf80f4bSopenharmony_ciMETA_NS::IObject::Ptr NodeImpl::Resolve(const META_NS::RefUri& uri) const
14488bf80f4bSopenharmony_ci{
14498bf80f4bSopenharmony_ci    auto p = Super::Resolve(uri);
14508bf80f4bSopenharmony_ci    if (p) {
14518bf80f4bSopenharmony_ci        return p;
14528bf80f4bSopenharmony_ci    }
14538bf80f4bSopenharmony_ci
14548bf80f4bSopenharmony_ci    INode::Ptr current = GetSelf<INode>();
14558bf80f4bSopenharmony_ci
14568bf80f4bSopenharmony_ci    META_NS::RefUri ref { uri.RelativeUri() };
14578bf80f4bSopenharmony_ci    if (ref.IsEmpty()) {
14588bf80f4bSopenharmony_ci        return interface_pointer_cast<META_NS::IObject>(current);
14598bf80f4bSopenharmony_ci    }
14608bf80f4bSopenharmony_ci
14618bf80f4bSopenharmony_ci    if (ref.StartsFromRoot()) {
14628bf80f4bSopenharmony_ci        ref.SetStartsFromRoot(false);
14638bf80f4bSopenharmony_ci        auto obj = interface_pointer_cast<META_NS::IObject>(GetScene()->RootNode()->GetValue());
14648bf80f4bSopenharmony_ci        return obj ? obj->Resolve(BASE_NS::move(ref)) : nullptr;
14658bf80f4bSopenharmony_ci    }
14668bf80f4bSopenharmony_ci
14678bf80f4bSopenharmony_ci    return {}; // ResolveSegment(current, BASE_NS::move(ref));
14688bf80f4bSopenharmony_ci}
14698bf80f4bSopenharmony_ci
14708bf80f4bSopenharmony_ciSCENE_BEGIN_NAMESPACE()
14718bf80f4bSopenharmony_civoid RegisterNodeImpl()
14728bf80f4bSopenharmony_ci{
14738bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().RegisterObjectType<NodeImpl>();
14748bf80f4bSopenharmony_ci}
14758bf80f4bSopenharmony_civoid UnregisterNodeImpl()
14768bf80f4bSopenharmony_ci{
14778bf80f4bSopenharmony_ci    META_NS::GetObjectRegistry().UnregisterObjectType<NodeImpl>();
14788bf80f4bSopenharmony_ci}
14798bf80f4bSopenharmony_ciSCENE_END_NAMESPACE()
1480