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 "ecs_object.h"
17
18 #include <scene/ext/intf_ecs_context.h>
19 #include <scene/ext/util.h>
20
21 #include <3d/ecs/components/name_component.h>
22 #include <core/property_tools/property_data.h>
23
24 #include <meta/api/engine/util.h>
25 #include <meta/api/make_callback.h>
26
SCENE_BEGIN_NAMESPACE()27 SCENE_BEGIN_NAMESPACE()
28
29 bool EcsObject::Build(const META_NS::IMetadata::Ptr& d)
30 {
31 if (Super::Build(d)) {
32 auto s = GetInterfaceBuildArg<IInternalScene>(d, "Scene");
33 auto ent = GetBuildArg<CORE_NS::Entity>(d, "Entity");
34
35 if (s && CORE_NS::EntityUtil::IsValid(ent)) {
36 valueManager_ =
37 META_NS::GetObjectRegistry().Create<META_NS::IEngineValueManager>(META_NS::ClassId::EngineValueManager);
38 valueManager_->SetNotificationQueue(s->GetAppTaskQueue());
39 scene_ = s;
40 entity_ = ent;
41
42 if (auto m = static_cast<CORE3D_NS::INameComponentManager*>(
43 s->GetEcsContext().FindComponent<CORE3D_NS::NameComponent>())) {
44 if (auto s = m->Read(entity_)) {
45 name_ = s->name;
46 }
47 }
48 }
49 }
50 return valueManager_ != nullptr && CORE_NS::EntityUtil::IsValid(entity_);
51 }
52
GetName() const53 BASE_NS::string EcsObject::GetName() const
54 {
55 std::shared_lock lock { mutex_ };
56 return name_;
57 }
58
SetName(const BASE_NS::string & name)59 bool EcsObject::SetName(const BASE_NS::string& name)
60 {
61 if (auto s = GetScene()) {
62 if (auto m = static_cast<CORE3D_NS::INameComponentManager*>(
63 s->GetEcsContext().FindComponent<CORE3D_NS::NameComponent>())) {
64 if (auto s = m->Write(entity_)) {
65 s->name = name;
66
67 std::unique_lock lock { mutex_ };
68 name_ = name;
69
70 return true;
71 }
72 }
73 }
74 return false;
75 }
76
GetPath() const77 BASE_NS::string EcsObject::GetPath() const
78 {
79 if (auto s = GetScene()) {
80 return s->GetEcsContext().GetPath(entity_);
81 }
82 return "";
83 }
84
GetScene() const85 IInternalScene::Ptr EcsObject::GetScene() const
86 {
87 return scene_.lock();
88 }
89
GetEntity() const90 CORE_NS::Entity EcsObject::GetEntity() const
91 {
92 return entity_;
93 }
94
GetEngineValueManager()95 META_NS::IEngineValueManager::Ptr EcsObject::GetEngineValueManager()
96 {
97 return valueManager_;
98 }
99
AddEngineProperty(META_NS::IMetadata & object,const META_NS::IEngineValue::Ptr & v)100 bool EcsObject::AddEngineProperty(META_NS::IMetadata& object, const META_NS::IEngineValue::Ptr& v)
101 {
102 auto prop = object.GetProperty(v->GetName());
103 if (prop) {
104 META_NS::SetEngineValueToProperty(prop, v);
105 } else {
106 prop = valueManager_->ConstructProperty(v->GetName());
107 if (prop) {
108 object.AddProperty(prop);
109 } else {
110 CORE_LOG_E("Failed to add %s", v->GetName().c_str());
111 return false;
112 }
113 }
114 if (prop) {
115 prop->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this] {
116 if (auto scene = scene_.lock()) {
117 scene->SchedulePropertyUpdate(GetSelf<IEcsObject>());
118 }
119 }));
120 }
121 return true;
122 }
123
AddAllProperties(META_NS::IMetadata & object,CORE_NS::IComponentManager * m)124 void EcsObject::AddAllProperties(META_NS::IMetadata& object, CORE_NS::IComponentManager* m)
125 {
126 BASE_NS::string name { m->GetName() };
127 BASE_NS::vector<META_NS::IEngineValue::Ptr> values;
128 META_NS::AddEngineValuesRecursively(
129 valueManager_, META_NS::EnginePropertyHandle { m, entity_ }, META_NS::EngineValueOptions { name, &values });
130 for (auto&& v : values) {
131 AddEngineProperty(object, v);
132 }
133 }
134
AddAllComponentProperties(META_NS::IMetadata & object)135 void EcsObject::AddAllComponentProperties(META_NS::IMetadata& object)
136 {
137 BASE_NS::vector<CORE_NS::IComponentManager*> managers;
138 if (auto s = GetScene()) {
139 s->GetEcsContext().GetNativeEcs()->GetComponents(entity_, managers);
140 for (auto m : managers) {
141 AddAllProperties(object, m);
142 }
143 }
144 }
145
AddAllEngineProperties(const META_NS::IMetadata::Ptr & object,BASE_NS::string_view cv)146 Future<bool> EcsObject::AddAllEngineProperties(const META_NS::IMetadata::Ptr& object, BASE_NS::string_view cv)
147 {
148 if (auto scene = scene_.lock()) {
149 return scene->AddTask([=, me = BASE_NS::weak_ptr(GetSelf()), component = BASE_NS::string(cv)] {
150 if (auto self = me.lock()) {
151 if (component.empty()) {
152 AddAllComponentProperties(*object);
153 return true;
154 }
155 if (auto s = GetScene()) {
156 if (auto m = s->GetEcsContext().FindComponent(ComponentName(component))) {
157 AddAllProperties(*object, m);
158 return true;
159 }
160 }
161 }
162 return false;
163 });
164 }
165 return {};
166 }
167
AttachEnginePropertyImpl(META_NS::EnginePropertyHandle handle,const BASE_NS::string & component,const META_NS::IProperty::Ptr & p,BASE_NS::string_view path)168 bool EcsObject::AttachEnginePropertyImpl(META_NS::EnginePropertyHandle handle, const BASE_NS::string& component,
169 const META_NS::IProperty::Ptr& p, BASE_NS::string_view path)
170 {
171 BASE_NS::vector<META_NS::IEngineValue::Ptr> values;
172 if (valueManager_->ConstructValue(
173 handle, FullPropertyName(path), META_NS::EngineValueOptions { component, &values })) {
174 if (!values.empty()) {
175 auto ret = META_NS::SetEngineValueToProperty(p, values.front());
176 if (ret) {
177 p->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this] {
178 if (auto scene = scene_.lock()) {
179 scene->SchedulePropertyUpdate(GetSelf<IEcsObject>());
180 }
181 }));
182 }
183 return ret;
184 }
185 // this most likely means we don't have registered access type for the property, lets continue anyhow for now
186 return true;
187 }
188 return false;
189 }
190
GetPropertyHandle(BASE_NS::string_view component) const191 META_NS::EnginePropertyHandle EcsObject::GetPropertyHandle(BASE_NS::string_view component) const
192 {
193 if (auto s = GetScene()) {
194 if (auto m = s->GetEcsContext().FindComponent(component)) {
195 return { m, entity_ };
196 }
197 }
198 return {};
199 }
200
AttachEngineProperty(const META_NS::IProperty::Ptr & p,BASE_NS::string_view pv)201 Future<bool> EcsObject::AttachEngineProperty(const META_NS::IProperty::Ptr& p, BASE_NS::string_view pv)
202 {
203 if (auto scene = scene_.lock()) {
204 return scene->AddTask([=, me = BASE_NS::weak_ptr(GetSelf()), path = BASE_NS::string(pv)] {
205 if (auto self = me.lock()) {
206 auto component = ComponentName(path);
207 if (auto handle = GetPropertyHandle(component)) {
208 return AttachEnginePropertyImpl(handle, BASE_NS::string(component), p, path);
209 }
210 }
211 return false;
212 });
213 }
214 return {};
215 }
216
CreateEngineProperty(BASE_NS::string_view pv)217 Future<META_NS::IProperty::Ptr> EcsObject::CreateEngineProperty(BASE_NS::string_view pv)
218 {
219 if (auto scene = scene_.lock()) {
220 return scene->AddTask([=, me = BASE_NS::weak_ptr(GetSelf()), path = BASE_NS::string(pv)] {
221 if (auto self = me.lock()) {
222 auto component = ComponentName(path);
223 if (auto handle = GetPropertyHandle(component)) {
224 auto name = FullPropertyName(path);
225 if (valueManager_->ConstructValue(
226 handle, name, META_NS::EngineValueOptions { BASE_NS::string(component) })) {
227 if (auto p = valueManager_->ConstructProperty(path)) {
228 p->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this] {
229 if (auto scene = scene_.lock()) {
230 scene->SchedulePropertyUpdate(GetSelf<IEcsObject>());
231 }
232 }));
233 return p;
234 }
235 }
236 }
237 }
238 return META_NS::IProperty::Ptr {};
239 });
240 }
241 return {};
242 }
243
SyncProperties()244 void EcsObject::SyncProperties()
245 {
246 valueManager_->Sync(META_NS::EngineSyncDirection::TO_ENGINE);
247 }
248
OnEntityEvent(CORE_NS::IEcs::EntityListener::EventType type)249 void EcsObject::OnEntityEvent(CORE_NS::IEcs::EntityListener::EventType type)
250 {
251 if (type == CORE_NS::IEcs::EntityListener::EventType::CREATED) {
252 }
253 if (type == CORE_NS::IEcs::EntityListener::EventType::DESTROYED) {
254 valueManager_->RemoveAll();
255 }
256 }
257
OnComponentEvent(CORE_NS::IEcs::ComponentListener::EventType type,const CORE_NS::IComponentManager & component)258 void EcsObject::OnComponentEvent(
259 CORE_NS::IEcs::ComponentListener::EventType type, const CORE_NS::IComponentManager& component)
260 {
261 if (type == CORE_NS::IEcs::ComponentListener::EventType::MODIFIED) {
262 valueManager_->Sync(META_NS::EngineSyncDirection::AUTO);
263 }
264 }
265
266 SCENE_END_NAMESPACE()
267