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