1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <base/math/quaternion.h>
17 #include <base/math/matrix.h>
18 
19 #include <PropertyTools/property_data.h>
20 #include <scene_plugin/interface/intf_ecs_object.h>
21 #include <scene_plugin/namespace.h>
22 
23 #include <3d/ecs/components/material_component.h>
24 #include <3d/ecs/components/name_component.h>
25 #include <3d/ecs/components/render_handle_component.h>
26 #include <core/ecs/intf_ecs.h>
27 #include <core/property/intf_property_api.h>
28 #include <core/property/intf_property_handle.h>
29 #include <core/property/property_types.h>
30 
31 #include <meta/api/make_callback.h>
32 #include <meta/api/engine/util.h>
33 #include <meta/ext/object.h>
34 #include <meta/interface/builtin_objects.h>
35 #include <meta/interface/intf_metadata.h>
36 #include <meta/interface/intf_object.h>
37 #include <meta/interface/engine/intf_engine_value_manager.h>
38 
39 #include "ecs_listener.h"
40 
41 #include <inttypes.h>
42 
43 SCENE_BEGIN_NAMESPACE()
44 
45 class EcsObject
46     : public META_NS::ObjectFwd<EcsObject, ClassId::EcsObject, META_NS::ClassId::Object, IEcsObject, IEcsProxyObject> {
47     using ObjectBase =
48         META_NS::ObjectFwd<EcsObject, ClassId::EcsObject, META_NS::ClassId::Object, IEcsObject, IEcsProxyObject>;
49 
META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(SCENE_NS::IEcsObject,uint8_t,ConnectionStatus,SCENE_NS::IEcsObject::ECS_OBJ_STATUS_DISCONNECTED)50     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(
51         SCENE_NS::IEcsObject, uint8_t, ConnectionStatus, SCENE_NS::IEcsObject::ECS_OBJ_STATUS_DISCONNECTED)
52 
53     bool Build(const IMetadata::Ptr& /*data*/) override
54     {
55         return true;
56     }
57 
GetEcs() const58     CORE_NS::IEcs::Ptr GetEcs() const override
59     {
60         return ecsInstance_;
61     }
62 
GetEntity() const63     CORE_NS::Entity GetEntity() const override
64     {
65         return entity_;
66     }
67 
SetEntity(CORE_NS::IEcs::Ptr ecs,CORE_NS::Entity entity)68     void SetEntity(CORE_NS::IEcs::Ptr ecs, CORE_NS::Entity entity) override
69     {
70         BindObject(nullptr, entity_);
71         // Should we allow setting a valid ecs with invalid entity?
72         if (CORE_NS::EntityUtil::IsValid(entity)) {
73             BindObject(ecs, entity);
74         }
75     }
76 
SetCommonListener(BASE_NS::shared_ptr<SCENE_NS::EcsListener> listener)77     void SetCommonListener(BASE_NS::shared_ptr<SCENE_NS::EcsListener> listener) override
78     {
79         if (auto commonListener = listener_.lock()) {
80             for (auto& componentManager : componentManagers_) {
81                 commonListener->RemoveEntity(entity_, GetSelf<SCENE_NS::IEcsProxyObject>(), *componentManager->manager);
82             }
83             componentManagers_.clear();
84         }
85         listener_ = listener;
86     }
87 
BindObject(CORE_NS::IEcs::Ptr ecsInstance,CORE_NS::Entity entity)88     void BindObject(CORE_NS::IEcs::Ptr ecsInstance, CORE_NS::Entity entity) override
89     {
90         if (ecsInstance && CORE_NS::EntityUtil::IsValid(entity)) {
91             ecsInstance_ = ecsInstance;
92             entity_ = ecsInstance->GetEntityManager().GetReferenceCounted(entity);
93             assert(componentManagers_.size() == 0);
94             UpdateMetaCache();
95             if (auto commonListener = listener_.lock()) {
96                 for (auto& componentManager : componentManagers_) {
97                     commonListener->AddEntity(entity, GetSelf<SCENE_NS::IEcsProxyObject>(), *componentManager->manager);
98                 }
99             }
100             // Nb. we may reach connected state even we don't have listener or single valid component to listen
101             META_ACCESS_PROPERTY(ConnectionStatus)->SetValue(SCENE_NS::IEcsObject::ECS_OBJ_STATUS_CONNECTED);
102         } else if (ecsInstance_) {
103             if (auto commonListener = listener_.lock()) {
104                 for (auto& componentManager : componentManagers_) {
105                     commonListener->RemoveEntity(
106                         entity, GetSelf<SCENE_NS::IEcsProxyObject>(), *componentManager->manager);
107                 }
108             }
109             for (auto& componentManager : componentManagers_) {
110                 componentManager->valueManager->RemoveAll();
111                 for (auto& prop : componentManager->properties) {
112                     RemoveProperty(prop);
113                 }
114             }
115 
116             attachments_.clear();
117             componentManagers_.clear();
118             entity_ = {};
119             ecsInstance_.reset();
120             META_ACCESS_PROPERTY(ConnectionStatus)->SetValue(SCENE_NS::IEcsObject::ECS_OBJ_STATUS_DISCONNECTED);
121         }
122     }
123 
~EcsObject()124     ~EcsObject() override
125     {
126         BindObject(nullptr, entity_);
127     }
128 
DoEntityEvent(CORE_NS::IEcs::EntityListener::EventType type,const CORE_NS::Entity &)129     void DoEntityEvent(CORE_NS::IEcs::EntityListener::EventType type, const CORE_NS::Entity& /*entity*/) override
130     {
131         switch (type) {
132             case CORE_NS::IEcs::EntityListener::EventType::CREATED: {
133                 break;
134             }
135             case CORE_NS::IEcs::EntityListener::EventType::ACTIVATED: {
136                 break;
137             }
138             case CORE_NS::IEcs::EntityListener::EventType::DEACTIVATED: {
139                 break;
140             }
141             case CORE_NS::IEcs::EntityListener::EventType::DESTROYED: {
142                 // detach from the entity. (stop listening for events, and detach the properties)
143                 BindObject(nullptr, entity_);
144                 break;
145             }
146         };
147     }
148 
DoComponentEvent(CORE_NS::IEcs::ComponentListener::EventType type,const CORE_NS::IComponentManager & componentManager,const CORE_NS::Entity & entity)149     void DoComponentEvent(CORE_NS::IEcs::ComponentListener::EventType type,
150         const CORE_NS::IComponentManager& componentManager, const CORE_NS::Entity& entity) override
151     {
152         if (entity!=entity_) {
153             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);
154             return;
155         }
156 
157         if (type == CORE_NS::IEcs::ComponentListener::EventType::CREATED) {
158             // new component added. add it's properties
159         }
160         if (type == CORE_NS::IEcs::ComponentListener::EventType::DESTROYED) {
161             // component removed. remove the properties.
162         }
163         if (type == CORE_NS::IEcs::ComponentListener::EventType::MODIFIED) {
164             // possibly re-evaluate because of change to one of the components..
165             //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);
166             UpdateProperties(componentManager);
167         }
168     }
169 
UpdateMetaCache() const170     void UpdateMetaCache() const
171     {
172         auto obj = const_cast<EcsObject*>(this);
173         obj->UpdateMetaCache();
174     }
175 
DefineTargetProperties(BASE_NS::unordered_map<BASE_NS::string_view,BASE_NS::vector<BASE_NS::string_view>> names)176     void DefineTargetProperties(
177         BASE_NS::unordered_map<BASE_NS::string_view, BASE_NS::vector<BASE_NS::string_view>> names) override
178     {
179         CORE_LOG_E("DefineTargetProperties");
180         if (ecsInstance_) {
181             UpdateMetaCache();
182         }
183     }
184 
185     BASE_NS::unordered_map<BASE_NS::string_view, BASE_NS::vector<BASE_NS::string_view>> names_;
186 
UpdateMetaCache()187     void UpdateMetaCache()
188     {
189         CORE_LOG_E("UpdateMetaCache");
190         BASE_NS::vector<CORE_NS::IComponentManager*> managers;
191         ecsInstance_->GetComponents(entity_, managers);
192         bool addAll = names_.empty();
193         for (auto cm : managers) {
194             auto handle = cm->GetData(entity_);
195             if (!handle) {
196                 break;
197             }
198             if (auto* papi = handle->Owner()) {
199                 BASE_NS::shared_ptr<ComponentManager> m;
200                 for(auto&& v : componentManagers_) {
201                     if(v->manager == cm) {
202                         m = v;
203                         break;
204                     }
205                 }
206                 if(!m) {
207                     m = ComponentManager::Create(*cm);
208                     componentManagers_.push_back(m);
209                 }
210 
211                 // Add a special "Name" property containing the name from a NameComponent
212                 if (cm->GetName() == "NameComponent") {
213                     for (int i = 0; i < papi->PropertyCount(); i++) {
214                         const auto md = papi->MetaData(i);
215                         if (md->type == CORE_NS::PropertyType::STRING_T && md->name == "name") {
216                             m->valueManager->ConstructValue(META_NS::EnginePropertyParams{handle, *md}, {});
217                             auto prop = GetPropertyByName("Name");
218                             if (!prop) {
219                                 prop = META_NS::ConstructProperty<BASE_NS::string>("Name");
220                                 AddProperty(prop);
221                             }
222                             SetEngineValueToProperty(prop, m->valueManager->GetEngineValue("name"));
223                             m->properties.push_back(prop);
224                         }
225                     }
226                 }
227                 BASE_NS::string name { cm->GetName() };
228                 BASE_NS::vector<META_NS::IEngineValue::Ptr> values;
229                 AddEngineValuesRecursively(m->valueManager, handle, META_NS::EngineValueOptions{name, &values, true});
230                 for(auto&& v : values) {
231                     if(auto prop = GetPropertyByName(v->GetName())) {
232                         SetEngineValueToProperty(prop, v);
233                     } else {
234                         AddProperty(m->valueManager->ConstructProperty(v->GetName()));
235                     }
236                 }
237             }
238         }
239     }
240 
UpdateProperties(const CORE_NS::IComponentManager & cm)241     void UpdateProperties(const CORE_NS::IComponentManager& cm)
242     {
243         auto* papi = cm.GetData(entity_)->Owner();
244         if (!papi) {
245             return;
246         }
247 
248         for (auto& active_mgr : componentManagers_) {
249             if (active_mgr->manager == &cm) {
250                 active_mgr->valueManager->Sync(META_NS::EngineSyncDirection::FROM_ENGINE);
251                 return;
252             }
253         }
254     }
255 
GetAttachments()256     virtual BASE_NS::vector<CORE_NS::Entity> GetAttachments() override
257     {
258         return attachments_;
259     }
260 
AddAttachment(CORE_NS::Entity entity)261     void AddAttachment(CORE_NS::Entity entity) override
262     {
263         attachments_.push_back(entity);
264     }
265 
RemoveAttachment(CORE_NS::Entity entity)266     void RemoveAttachment(CORE_NS::Entity entity) override
267     {
268         // assuming that entities can be there only once
269         for (auto attachment = attachments_.cbegin(); attachment != attachments_.cend(); attachment++) {
270             if (attachment->id == entity.id) {
271                 attachments_.erase(attachment);
272                 break;
273             }
274         }
275     }
276 
Activate()277     void Activate() override {}
278 
Deactivate()279     void Deactivate() override {}
280 
281 public:
EcsObject(const META_NS::IMetadata::Ptr & data)282     EcsObject(const META_NS::IMetadata::Ptr& data) {}
EcsObject()283     EcsObject() {}
284 
285 private:
286     CORE_NS::IEcs::Ptr ecsInstance_ {};
287     CORE_NS::EntityReference entity_;
288     BASE_NS::weak_ptr<SCENE_NS::EcsListener> listener_ {};
289     uint64_t firstOffset_ { 0 };
290     struct ComponentManager {
CreateEcsObject::ComponentManager291         static BASE_NS::shared_ptr<ComponentManager> Create(CORE_NS::IComponentManager& manager)
292         {
293             return BASE_NS::shared_ptr<ComponentManager> { new ComponentManager { &manager,
294                 META_NS::GetObjectRegistry().Create<META_NS::IEngineValueManager>(
295                     META_NS::ClassId::EngineValueManager) } };
296         }
297         CORE_NS::IComponentManager* manager;
298         META_NS::IEngineValueManager::Ptr valueManager;
299         BASE_NS::vector<META_NS::IProperty::Ptr> properties;
300     };
301 
302     BASE_NS::vector<BASE_NS::shared_ptr<ComponentManager>> componentManagers_;
303     BASE_NS::vector<CORE_NS::Entity> attachments_;
304 };
305 
RegisterEcsObject()306 void RegisterEcsObject()
307 {
308     META_NS::GetObjectRegistry().RegisterObjectType<EcsObject>();
309 }
310 
UnregisterEcsObject()311 void UnregisterEcsObject()
312 {
313     META_NS::GetObjectRegistry().UnregisterObjectType<EcsObject>();
314 }
315 
316 SCENE_END_NAMESPACE()
317