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