/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <base/math/quaternion.h> #include <base/math/matrix.h> #include <PropertyTools/property_data.h> #include <scene_plugin/interface/intf_ecs_object.h> #include <scene_plugin/namespace.h> #include <3d/ecs/components/material_component.h> #include <3d/ecs/components/name_component.h> #include <3d/ecs/components/render_handle_component.h> #include <core/ecs/intf_ecs.h> #include <core/property/intf_property_api.h> #include <core/property/intf_property_handle.h> #include <core/property/property_types.h> #include <meta/api/make_callback.h> #include <meta/api/engine/util.h> #include <meta/ext/object.h> #include <meta/interface/builtin_objects.h> #include <meta/interface/intf_metadata.h> #include <meta/interface/intf_object.h> #include <meta/interface/engine/intf_engine_value_manager.h> #include "ecs_listener.h" #include <inttypes.h> SCENE_BEGIN_NAMESPACE() class EcsObject : public META_NS::ObjectFwd<EcsObject, ClassId::EcsObject, META_NS::ClassId::Object, IEcsObject, IEcsProxyObject> { using ObjectBase = META_NS::ObjectFwd<EcsObject, ClassId::EcsObject, META_NS::ClassId::Object, IEcsObject, IEcsProxyObject>; META_IMPLEMENT_INTERFACE_READONLY_PROPERTY( SCENE_NS::IEcsObject, uint8_t, ConnectionStatus, SCENE_NS::IEcsObject::ECS_OBJ_STATUS_DISCONNECTED) bool Build(const IMetadata::Ptr& /*data*/) override { return true; } CORE_NS::IEcs::Ptr GetEcs() const override { return ecsInstance_; } CORE_NS::Entity GetEntity() const override { return entity_; } void SetEntity(CORE_NS::IEcs::Ptr ecs, CORE_NS::Entity entity) override { BindObject(nullptr, entity_); // Should we allow setting a valid ecs with invalid entity? if (CORE_NS::EntityUtil::IsValid(entity)) { BindObject(ecs, entity); } } void SetCommonListener(BASE_NS::shared_ptr<SCENE_NS::EcsListener> listener) override { if (auto commonListener = listener_.lock()) { for (auto& componentManager : componentManagers_) { commonListener->RemoveEntity(entity_, GetSelf<SCENE_NS::IEcsProxyObject>(), *componentManager->manager); } componentManagers_.clear(); } listener_ = listener; } void BindObject(CORE_NS::IEcs::Ptr ecsInstance, CORE_NS::Entity entity) override { if (ecsInstance && CORE_NS::EntityUtil::IsValid(entity)) { ecsInstance_ = ecsInstance; entity_ = ecsInstance->GetEntityManager().GetReferenceCounted(entity); assert(componentManagers_.size() == 0); UpdateMetaCache(); if (auto commonListener = listener_.lock()) { for (auto& componentManager : componentManagers_) { commonListener->AddEntity(entity, GetSelf<SCENE_NS::IEcsProxyObject>(), *componentManager->manager); } } // Nb. we may reach connected state even we don't have listener or single valid component to listen META_ACCESS_PROPERTY(ConnectionStatus)->SetValue(SCENE_NS::IEcsObject::ECS_OBJ_STATUS_CONNECTED); } else if (ecsInstance_) { if (auto commonListener = listener_.lock()) { for (auto& componentManager : componentManagers_) { commonListener->RemoveEntity( entity, GetSelf<SCENE_NS::IEcsProxyObject>(), *componentManager->manager); } } for (auto& componentManager : componentManagers_) { componentManager->valueManager->RemoveAll(); for (auto& prop : componentManager->properties) { RemoveProperty(prop); } } attachments_.clear(); componentManagers_.clear(); entity_ = {}; ecsInstance_.reset(); META_ACCESS_PROPERTY(ConnectionStatus)->SetValue(SCENE_NS::IEcsObject::ECS_OBJ_STATUS_DISCONNECTED); } } ~EcsObject() override { BindObject(nullptr, entity_); } void DoEntityEvent(CORE_NS::IEcs::EntityListener::EventType type, const CORE_NS::Entity& /*entity*/) override { switch (type) { case CORE_NS::IEcs::EntityListener::EventType::CREATED: { break; } case CORE_NS::IEcs::EntityListener::EventType::ACTIVATED: { break; } case CORE_NS::IEcs::EntityListener::EventType::DEACTIVATED: { break; } case CORE_NS::IEcs::EntityListener::EventType::DESTROYED: { // detach from the entity. (stop listening for events, and detach the properties) BindObject(nullptr, entity_); break; } }; } void DoComponentEvent(CORE_NS::IEcs::ComponentListener::EventType type, const CORE_NS::IComponentManager& componentManager, const CORE_NS::Entity& entity) override { if (entity!=entity_) { CORE_LOG_F("Invalid event for %s entity %" PRIx64 " handler object entity %" PRIx64,BASE_NS::string(componentManager.GetName()).c_str(),entity.id,CORE_NS::Entity(entity_).id); return; } if (type == CORE_NS::IEcs::ComponentListener::EventType::CREATED) { // new component added. add it's properties } if (type == CORE_NS::IEcs::ComponentListener::EventType::DESTROYED) { // component removed. remove the properties. } if (type == CORE_NS::IEcs::ComponentListener::EventType::MODIFIED) { // possibly re-evaluate because of change to one of the components.. //CORE_LOG_F("[%p] Modified event for %s entity %llx handler object entity %llx",this, BASE_NS::string(componentManager.GetName()).c_str(),entity.id,CORE_NS::Entity(entity_).id); UpdateProperties(componentManager); } } void UpdateMetaCache() const { auto obj = const_cast<EcsObject*>(this); obj->UpdateMetaCache(); } void DefineTargetProperties( BASE_NS::unordered_map<BASE_NS::string_view, BASE_NS::vector<BASE_NS::string_view>> names) override { CORE_LOG_E("DefineTargetProperties"); if (ecsInstance_) { UpdateMetaCache(); } } BASE_NS::unordered_map<BASE_NS::string_view, BASE_NS::vector<BASE_NS::string_view>> names_; void UpdateMetaCache() { CORE_LOG_E("UpdateMetaCache"); BASE_NS::vector<CORE_NS::IComponentManager*> managers; ecsInstance_->GetComponents(entity_, managers); bool addAll = names_.empty(); for (auto cm : managers) { auto handle = cm->GetData(entity_); if (!handle) { break; } if (auto* papi = handle->Owner()) { BASE_NS::shared_ptr<ComponentManager> m; for(auto&& v : componentManagers_) { if(v->manager == cm) { m = v; break; } } if(!m) { m = ComponentManager::Create(*cm); componentManagers_.push_back(m); } // Add a special "Name" property containing the name from a NameComponent if (cm->GetName() == "NameComponent") { for (int i = 0; i < papi->PropertyCount(); i++) { const auto md = papi->MetaData(i); if (md->type == CORE_NS::PropertyType::STRING_T && md->name == "name") { m->valueManager->ConstructValue(META_NS::EnginePropertyParams{handle, *md}, {}); auto prop = GetPropertyByName("Name"); if (!prop) { prop = META_NS::ConstructProperty<BASE_NS::string>("Name"); AddProperty(prop); } SetEngineValueToProperty(prop, m->valueManager->GetEngineValue("name")); m->properties.push_back(prop); } } } BASE_NS::string name { cm->GetName() }; BASE_NS::vector<META_NS::IEngineValue::Ptr> values; AddEngineValuesRecursively(m->valueManager, handle, META_NS::EngineValueOptions{name, &values, true}); for(auto&& v : values) { if(auto prop = GetPropertyByName(v->GetName())) { SetEngineValueToProperty(prop, v); } else { AddProperty(m->valueManager->ConstructProperty(v->GetName())); } } } } } void UpdateProperties(const CORE_NS::IComponentManager& cm) { auto* papi = cm.GetData(entity_)->Owner(); if (!papi) { return; } for (auto& active_mgr : componentManagers_) { if (active_mgr->manager == &cm) { active_mgr->valueManager->Sync(META_NS::EngineSyncDirection::FROM_ENGINE); return; } } } virtual BASE_NS::vector<CORE_NS::Entity> GetAttachments() override { return attachments_; } void AddAttachment(CORE_NS::Entity entity) override { attachments_.push_back(entity); } void RemoveAttachment(CORE_NS::Entity entity) override { // assuming that entities can be there only once for (auto attachment = attachments_.cbegin(); attachment != attachments_.cend(); attachment++) { if (attachment->id == entity.id) { attachments_.erase(attachment); break; } } } void Activate() override {} void Deactivate() override {} public: EcsObject(const META_NS::IMetadata::Ptr& data) {} EcsObject() {} private: CORE_NS::IEcs::Ptr ecsInstance_ {}; CORE_NS::EntityReference entity_; BASE_NS::weak_ptr<SCENE_NS::EcsListener> listener_ {}; uint64_t firstOffset_ { 0 }; struct ComponentManager { static BASE_NS::shared_ptr<ComponentManager> Create(CORE_NS::IComponentManager& manager) { return BASE_NS::shared_ptr<ComponentManager> { new ComponentManager { &manager, META_NS::GetObjectRegistry().Create<META_NS::IEngineValueManager>( META_NS::ClassId::EngineValueManager) } }; } CORE_NS::IComponentManager* manager; META_NS::IEngineValueManager::Ptr valueManager; BASE_NS::vector<META_NS::IProperty::Ptr> properties; }; BASE_NS::vector<BASE_NS::shared_ptr<ComponentManager>> componentManagers_; BASE_NS::vector<CORE_NS::Entity> attachments_; }; void RegisterEcsObject() { META_NS::GetObjectRegistry().RegisterObjectType<EcsObject>(); } void UnregisterEcsObject() { META_NS::GetObjectRegistry().UnregisterObjectType<EcsObject>(); } SCENE_END_NAMESPACE()