• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecs_object.h"
16 
17 #include <scene/ext/intf_ecs_context.h>
18 #include <scene/ext/util.h>
19 
20 #include <3d/ecs/components/name_component.h>
21 #include <core/property_tools/property_data.h>
22 
23 #include <meta/api/engine/util.h>
24 #include <meta/api/make_callback.h>
25 
SCENE_BEGIN_NAMESPACE()26 SCENE_BEGIN_NAMESPACE()
27 
28 bool EcsObject::Build(const META_NS::IMetadata::Ptr& d)
29 {
30     if (Super::Build(d)) {
31         auto s = GetInterfaceBuildArg<IInternalScene>(d, "Scene");
32         auto ent = GetBuildArg<CORE_NS::Entity>(d, "Entity");
33 
34         if (s && CORE_NS::EntityUtil::IsValid(ent)) {
35             valueManager_ =
36                 META_NS::GetObjectRegistry().Create<META_NS::IEngineValueManager>(META_NS::ClassId::EngineValueManager);
37             valueManager_->SetNotificationQueue(s->GetContext()->GetApplicationQueue());
38             scene_ = s;
39             entity_ = ent;
40         }
41     }
42     return valueManager_ != nullptr && CORE_NS::EntityUtil::IsValid(entity_);
43 }
44 
GetName() const45 BASE_NS::string EcsObject::GetName() const
46 {
47     return META_NS::GetValue(Name());
48 }
49 
SetName(const BASE_NS::string & name)50 bool EcsObject::SetName(const BASE_NS::string& name)
51 {
52     if (auto s = GetScene()) {
53         META_NS::SetValue<BASE_NS::string>(Name(), name);
54         return SyncProperty(s, Name()).GetResult();
55     }
56     return false;
57 }
58 
GetPath() const59 BASE_NS::string EcsObject::GetPath() const
60 {
61     if (auto s = GetScene()) {
62         return s->GetEcsContext().GetPath(entity_);
63     }
64     return "";
65 }
66 
GetScene() const67 IInternalScene::Ptr EcsObject::GetScene() const
68 {
69     return scene_.lock();
70 }
71 
GetEntity() const72 CORE_NS::Entity EcsObject::GetEntity() const
73 {
74     return entity_;
75 }
76 
GetEngineValueManager()77 META_NS::IEngineValueManager::Ptr EcsObject::GetEngineValueManager()
78 {
79     return valueManager_;
80 }
81 
AddPropertyUpdateHook(const META_NS::IProperty::Ptr & prop)82 void EcsObject::AddPropertyUpdateHook(const META_NS::IProperty::Ptr& prop)
83 {
84     if (prop) {
85         prop->OnChanged()->AddHandler(
86             META_NS::MakeCallback<META_NS::IOnChanged>([ecsobj = BASE_NS::weak_ptr(GetSelf<IEcsObject>())] {
87                 if (auto eobj = ecsobj.lock()) {
88                     eobj->GetScene()->SchedulePropertyUpdate(eobj);
89                 }
90             }));
91     }
92 }
93 
AddEngineProperty(META_NS::IMetadata & object,const META_NS::IEngineValue::Ptr & v)94 bool EcsObject::AddEngineProperty(META_NS::IMetadata& object, const META_NS::IEngineValue::Ptr& v)
95 {
96     auto prop = object.GetProperty(v->GetName());
97     if (prop) {
98         META_NS::SetEngineValueToProperty(prop, v);
99     } else {
100         prop = valueManager_->ConstructProperty(v->GetName());
101         if (prop) {
102             object.AddProperty(prop);
103         } else {
104             CORE_LOG_E("Failed to add %s", v->GetName().c_str());
105             return false;
106         }
107     }
108     AddPropertyUpdateHook(prop);
109     return true;
110 }
111 
AddAllProperties(META_NS::IMetadata & object,CORE_NS::IComponentManager * m)112 void EcsObject::AddAllProperties(META_NS::IMetadata& object, CORE_NS::IComponentManager* m)
113 {
114     BASE_NS::string name { m->GetName() };
115     BASE_NS::vector<META_NS::IEngineValue::Ptr> values;
116     META_NS::AddEngineValuesRecursively(
117         valueManager_, META_NS::EnginePropertyHandle { m, entity_ }, META_NS::EngineValueOptions { name, &values });
118     for (auto&& v : values) {
119         AddEngineProperty(object, v);
120     }
121 }
122 
AddAllComponentProperties(META_NS::IMetadata & object)123 void EcsObject::AddAllComponentProperties(META_NS::IMetadata& object)
124 {
125     BASE_NS::vector<CORE_NS::IComponentManager*> managers;
126     if (auto s = GetScene()) {
127         s->GetEcsContext().GetNativeEcs()->GetComponents(entity_, managers);
128         for (auto m : managers) {
129             AddAllProperties(object, m);
130         }
131     }
132 }
133 
AddAllNamedComponentProperties(META_NS::IMetadata & object,BASE_NS::string_view cv)134 bool EcsObject::AddAllNamedComponentProperties(META_NS::IMetadata& object, BASE_NS::string_view cv)
135 {
136     BASE_NS::vector<CORE_NS::IComponentManager*> managers;
137     if (auto s = GetScene()) {
138         s->GetEcsContext().GetNativeEcs()->GetComponents(entity_, managers);
139         for (auto m : managers) {
140             if (m->GetName() == cv) {
141                 AddAllProperties(object, m);
142                 return true;
143             }
144         }
145     }
146     return false;
147 }
148 
AddAllProperties(const META_NS::IMetadata::Ptr & object,BASE_NS::string_view cv)149 Future<bool> EcsObject::AddAllProperties(const META_NS::IMetadata::Ptr& object, BASE_NS::string_view cv)
150 {
151     if (auto scene = scene_.lock()) {
152         return scene->AddTask([=, me = BASE_NS::weak_ptr(GetSelf()), component = BASE_NS::string(cv)] {
153             if (auto self = me.lock()) {
154                 if (component.empty()) {
155                     AddAllComponentProperties(*object);
156                     return true;
157                 }
158                 if (auto s = GetScene()) {
159                     auto name = ComponentName(component);
160                     if (auto m = s->GetEcsContext().FindComponent(name)) {
161                         AddAllProperties(*object, m);
162                         return true;
163                     }
164                     return AddAllNamedComponentProperties(*object, name);
165                 }
166             }
167             return false;
168         });
169     }
170     return {};
171 }
172 
AttachEnginePropertyImpl(META_NS::EnginePropertyHandle handle,const BASE_NS::string & component,const META_NS::IProperty::Ptr & p,BASE_NS::string_view path)173 bool EcsObject::AttachEnginePropertyImpl(META_NS::EnginePropertyHandle handle, const BASE_NS::string& component,
174     const META_NS::IProperty::Ptr& p, BASE_NS::string_view path)
175 {
176     BASE_NS::vector<META_NS::IEngineValue::Ptr> values;
177     if (valueManager_->ConstructValue(
178             handle, FullPropertyName(path), META_NS::EngineValueOptions { component, &values })) {
179         if (!values.empty()) {
180             auto ret = META_NS::SetEngineValueToProperty(p, values.front());
181             if (ret) {
182                 AddPropertyUpdateHook(p);
183             }
184             return ret;
185         }
186         // this most likely means we don't have registered access type for the property, lets continue anyhow for now
187         return true;
188     }
189     return false;
190 }
191 
GetPropertyHandle(BASE_NS::string_view component) const192 META_NS::EnginePropertyHandle EcsObject::GetPropertyHandle(BASE_NS::string_view component) const
193 {
194     if (auto s = GetScene()) {
195         if (auto m = s->GetEcsContext().FindComponent(component)) {
196             return { m, entity_ };
197         }
198     }
199     return {};
200 }
201 
AttachProperty(const META_NS::IProperty::Ptr & p,BASE_NS::string_view pv)202 Future<bool> EcsObject::AttachProperty(const META_NS::IProperty::Ptr& p, BASE_NS::string_view pv)
203 {
204     if (auto scene = scene_.lock()) {
205         return scene->AddTask([=, me = BASE_NS::weak_ptr(GetSelf()), path = BASE_NS::string(pv)] {
206             if (auto self = me.lock()) {
207                 auto component = ComponentName(path);
208                 if (auto handle = GetPropertyHandle(component)) {
209                     return AttachEnginePropertyImpl(handle, BASE_NS::string(component), p, path);
210                 }
211             }
212             return false;
213         });
214     }
215     return {};
216 }
217 
CreateProperty(BASE_NS::string_view pv)218 Future<META_NS::IProperty::Ptr> EcsObject::CreateProperty(BASE_NS::string_view pv)
219 {
220     if (auto scene = scene_.lock()) {
221         return scene->AddTask([=, me = BASE_NS::weak_ptr(GetSelf()), path = BASE_NS::string(pv)] {
222             if (auto self = me.lock()) {
223                 auto component = ComponentName(path);
224                 if (auto handle = GetPropertyHandle(component)) {
225                     auto name = FullPropertyName(path);
226                     if (valueManager_->ConstructValue(
227                             handle, name, META_NS::EngineValueOptions { BASE_NS::string(component) })) {
228                         if (auto p = valueManager_->ConstructProperty(path)) {
229                             AddPropertyUpdateHook(p);
230                             return p;
231                         }
232                     }
233                 }
234             }
235             return META_NS::IProperty::Ptr {};
236         });
237     }
238     return {};
239 }
240 
CreateProperty(const META_NS::IEngineValue::Ptr & value)241 Future<META_NS::IProperty::Ptr> EcsObject::CreateProperty(const META_NS::IEngineValue::Ptr& value)
242 {
243     if (auto scene = scene_.lock()) {
244         return scene->AddTask([=, me = BASE_NS::weak_ptr(GetSelf())] {
245             if (auto self = me.lock()) {
246                 BASE_NS::string pname(SCENE_NS::PropertyName(value->GetName()));
247                 if (auto p = META_NS::PropertyFromEngineValue(pname, value)) {
248                     AddPropertyUpdateHook(p);
249                     return p;
250                 }
251             }
252             return META_NS::IProperty::Ptr {};
253         });
254     }
255     return {};
256 }
257 
AttachProperty(const META_NS::IProperty::Ptr & prop,const META_NS::IEngineValue::Ptr & value)258 Future<bool> EcsObject::AttachProperty(const META_NS::IProperty::Ptr& prop, const META_NS::IEngineValue::Ptr& value)
259 {
260     if (auto scene = scene_.lock()) {
261         return scene->AddTask([=, me = BASE_NS::weak_ptr(GetSelf())] {
262             if (auto self = me.lock()) {
263                 if (META_NS::SetEngineValueToProperty(prop, value)) {
264                     AddPropertyUpdateHook(prop);
265                     return true;
266                 }
267             }
268             return false;
269         });
270     }
271     return {};
272 }
273 
SyncProperties()274 void EcsObject::SyncProperties()
275 {
276     valueManager_->Sync(META_NS::EngineSyncDirection::TO_ENGINE);
277 }
278 
OnEntityEvent(CORE_NS::IEcs::EntityListener::EventType type)279 void EcsObject::OnEntityEvent(CORE_NS::IEcs::EntityListener::EventType type)
280 {
281     if (type == CORE_NS::IEcs::EntityListener::EventType::CREATED) {
282     }
283     if (type == CORE_NS::IEcs::EntityListener::EventType::DESTROYED) {
284         valueManager_->RemoveAll();
285     }
286 }
287 
OnComponentEvent(CORE_NS::IEcs::ComponentListener::EventType type,const CORE_NS::IComponentManager & component)288 void EcsObject::OnComponentEvent(
289     CORE_NS::IEcs::ComponentListener::EventType type, const CORE_NS::IComponentManager& component)
290 {
291     if (type == CORE_NS::IEcs::ComponentListener::EventType::MODIFIED) {
292         valueManager_->Sync(META_NS::EngineSyncDirection::AUTO);
293     }
294 }
295 
AttachEngineProperty(const META_NS::IProperty::Ptr & p,BASE_NS::string_view path)296 bool EcsObject::AttachEngineProperty(const META_NS::IProperty::Ptr& p, BASE_NS::string_view path)
297 {
298     return AttachProperty(p, path).GetResult();
299 }
300 
InitDynamicProperty(const META_NS::IProperty::Ptr & p,BASE_NS::string_view path)301 bool EcsObject::InitDynamicProperty(const META_NS::IProperty::Ptr& p, BASE_NS::string_view path)
302 {
303     if (p->GetName() == "Name") {
304         if (!AttachEngineProperty(p, path)) {
305             CORE_LOG_D("Failed to attach '%s' to '%s', falling back to normal property", p->GetName().c_str(),
306                 BASE_NS::string(path).c_str());
307             // no name component? Fallback to normal property
308         }
309         return true;
310     }
311     return AttachEngineProperty(p, path);
312 }
313 
SetActive(bool active)314 Future<bool> EcsObject::SetActive(bool active)
315 {
316     if (auto s = GetScene()) {
317         return s->AddTask([=, me = BASE_NS::weak_ptr(GetSelf<IEcsObject>())] {
318             if (auto self = me.lock()) {
319                 s->SetEntityActive(self, active);
320                 return true;
321             }
322             return false;
323         });
324     }
325     return {};
326 }
327 
328 SCENE_END_NAMESPACE()
329