• 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 
16 #include "system_graph_loader.h"
17 
18 #include <charconv>
19 #include <cstddef>
20 #include <cstdint>
21 
22 #include <base/containers/array_view.h>
23 #include <base/containers/iterator.h>
24 #include <base/containers/string.h>
25 #include <base/containers/string_view.h>
26 #include <base/containers/type_traits.h>
27 #include <base/containers/unique_ptr.h>
28 #include <base/math/quaternion.h>
29 #include <base/math/vector.h>
30 #include <base/namespace.h>
31 #include <base/util/uid.h>
32 #include <core/ecs/entity.h>
33 #include <core/ecs/intf_ecs.h>
34 #include <core/ecs/intf_system.h>
35 #include <core/ecs/intf_system_graph_loader.h>
36 #include <core/io/intf_file.h>
37 #include <core/io/intf_file_manager.h>
38 #include <core/log.h>
39 #include <core/namespace.h>
40 #include <core/plugin/intf_plugin.h>
41 #include <core/plugin/intf_plugin_register.h>
42 #include <core/property/intf_property_api.h>
43 #include <core/property/intf_property_handle.h>
44 #include <core/property/property.h>
45 #include <core/property/property_types.h>
46 
47 #define JSON_IMPL
48 #include <core/json/json.h>
49 
50 #include "json_util.h"
51 
52 CORE_BEGIN_NAMESPACE()
53 using BASE_NS::array_view;
54 using BASE_NS::string;
55 using BASE_NS::string_view;
56 using BASE_NS::Uid;
57 using BASE_NS::Math::Quat;
58 using BASE_NS::Math::Vec2;
59 using BASE_NS::Math::Vec3;
60 using BASE_NS::Math::Vec4;
61 
62 namespace {
63 constexpr size_t VERSION_SIZE { 5u };
64 constexpr uint32_t VERSION_MAJOR { 22u };
65 
66 template<class TYPEINFO>
FindTypeInfo(const string_view name,const array_view<const ITypeInfo * const> & container)67 const TYPEINFO* FindTypeInfo(const string_view name, const array_view<const ITypeInfo* const>& container)
68 {
69     for (const auto& info : container) {
70         if (info && info->typeUid == TYPEINFO::UID && (static_cast<const TYPEINFO*>(info)->typeName == name)) {
71             return static_cast<const TYPEINFO*>(info);
72         }
73     }
74 
75     return nullptr;
76 }
77 
78 template<class TYPEINFO>
FindTypeInfo(const Uid & uid,const array_view<const ITypeInfo * const> & container)79 const TYPEINFO* FindTypeInfo(const Uid& uid, const array_view<const ITypeInfo* const>& container)
80 {
81     for (const auto& info : container) {
82         if (static_cast<const TYPEINFO* const>(info)->uid == uid) {
83             return static_cast<const TYPEINFO*>(info);
84         }
85     }
86 
87     return nullptr;
88 }
89 
90 struct PropertyValue {
91     const IPropertyHandle* handle;
92     void* offset;
93     const Property* info;
94     template<typename Type>
Get__anonc6812f130111::PropertyValue95     Type& Get() const
96     {
97         return *static_cast<Type*>(offset);
98     }
99 };
100 
101 // For primitive types..
102 template<typename ElementType>
ReadArrayPropertyValue(const json::value & jsonData,const PropertyValue & propertyData,string & error)103 void ReadArrayPropertyValue(const json::value& jsonData, const PropertyValue& propertyData, string& error)
104 {
105     ElementType* output = &propertyData.Get<ElementType>();
106     if (propertyData.info->type.isArray) {
107         // expecting array data.
108         if (auto const array = jsonData.find(propertyData.info->name); array) {
109             auto outputView = array_view<ElementType>(output, propertyData.info->count);
110             from_json(*array, outputView);
111         }
112     } else {
113         // expecting single value
114         ElementType result;
115         if (SafeGetJsonValue(jsonData, propertyData.info->name, error, result)) {
116             *output = result;
117         }
118     }
119 }
120 
121 // Specialization for char types (strings).. (null terminate the arrays)
122 template<>
ReadArrayPropertyValue(const json::value & jsonData,const PropertyValue & propertyData,string & error)123 void ReadArrayPropertyValue<char>(const json::value& jsonData, const PropertyValue& propertyData, string& error)
124 {
125     char* output = &propertyData.Get<char>();
126     string_view result;
127     if (SafeGetJsonValue(jsonData, propertyData.info->name, error, result)) {
128         if (propertyData.info->type.isArray) {
129             const auto end = result.copy(output, propertyData.info->count - 1, 0);
130             output[end] = 0;
131         } else {
132             *output = result[0];
133         }
134     }
135 }
136 
137 template<class HandleType>
ReadHandlePropertyValue(const json::value & jsonData,const PropertyValue & propertyData,string & error)138 void ReadHandlePropertyValue(const json::value& jsonData, const PropertyValue& propertyData, string& error)
139 {
140     decltype(HandleType::id) result;
141     if (SafeGetJsonValue(jsonData, propertyData.info->name, error, result)) {
142         auto& handle = propertyData.Get<HandleType>();
143         handle.id = result;
144     }
145 }
146 
147 template<class VecType, size_t n>
ReadVecPropertyValue(const json::value & jsonData,const PropertyValue & propertyData,string &)148 void ReadVecPropertyValue(const json::value& jsonData, const PropertyValue& propertyData, string& /* error */)
149 {
150     if (auto const array = jsonData.find(propertyData.info->name); array) {
151         auto& result = propertyData.Get<VecType>();
152         from_json(*array, result.data);
153     }
154 }
155 
ResolveComponentDependencies(IEcs & ecs,array_view<const Uid> dependencies,const array_view<const ITypeInfo * const> componentMetadata)156 bool ResolveComponentDependencies(
157     IEcs& ecs, array_view<const Uid> dependencies, const array_view<const ITypeInfo* const> componentMetadata)
158 {
159     for (const Uid& dependencyUid : dependencies) {
160         // default constructed UID is used as a wildcard for dependecies not known at compile time.
161         if (dependencyUid == Uid {}) {
162             continue;
163         }
164         // See if this component type exists in ecs
165         const IComponentManager* componentManager = ecs.GetComponentManager(dependencyUid);
166         if (componentManager) {
167             continue;
168         }
169         // Find component type and create such manager.
170         const auto* componentTypeInfo = FindTypeInfo<ComponentManagerTypeInfo>(dependencyUid, componentMetadata);
171         if (componentTypeInfo) {
172             ecs.CreateComponentManager(*componentTypeInfo);
173         } else {
174             // Could not find this component manager, unable to continue.
175             return false;
176         }
177     }
178 
179     return true;
180 }
181 
ReadPropertyValue(const json::value & jsonData,const PropertyValue & property,string & error)182 void ReadPropertyValue(const json::value& jsonData, const PropertyValue& property, string& error)
183 {
184     if (property.info) {
185         switch (property.info->type) {
186             case PropertyType::BOOL_T:
187             case PropertyType::BOOL_ARRAY_T:
188                 ReadArrayPropertyValue<bool>(jsonData, property, error);
189                 break;
190 
191             case PropertyType::CHAR_T:
192             case PropertyType::CHAR_ARRAY_T:
193                 ReadArrayPropertyValue<char>(jsonData, property, error);
194                 break;
195 
196             case PropertyType::INT8_T:
197             case PropertyType::INT8_ARRAY_T:
198                 ReadArrayPropertyValue<int8_t>(jsonData, property, error);
199                 break;
200 
201             case PropertyType::INT16_T:
202             case PropertyType::INT16_ARRAY_T:
203                 ReadArrayPropertyValue<int16_t>(jsonData, property, error);
204                 break;
205 
206             case PropertyType::INT32_T:
207             case PropertyType::INT32_ARRAY_T:
208                 ReadArrayPropertyValue<int32_t>(jsonData, property, error);
209                 break;
210 
211             case PropertyType::INT64_T:
212             case PropertyType::INT64_ARRAY_T:
213                 ReadArrayPropertyValue<int64_t>(jsonData, property, error);
214                 break;
215 
216             case PropertyType::UINT8_T:
217             case PropertyType::UINT8_ARRAY_T:
218                 ReadArrayPropertyValue<uint8_t>(jsonData, property, error);
219                 break;
220 
221             case PropertyType::UINT16_T:
222             case PropertyType::UINT16_ARRAY_T:
223                 ReadArrayPropertyValue<uint16_t>(jsonData, property, error);
224                 break;
225 
226             case PropertyType::UINT32_T:
227             case PropertyType::UINT32_ARRAY_T:
228                 ReadArrayPropertyValue<uint32_t>(jsonData, property, error);
229                 break;
230 
231             case PropertyType::UINT64_T:
232             case PropertyType::UINT64_ARRAY_T:
233                 ReadArrayPropertyValue<uint64_t>(jsonData, property, error);
234                 break;
235 
236             case PropertyType::DOUBLE_T:
237             case PropertyType::DOUBLE_ARRAY_T:
238                 ReadArrayPropertyValue<double>(jsonData, property, error);
239                 break;
240 
241             case PropertyType::ENTITY_T:
242                 ReadHandlePropertyValue<Entity>(jsonData, property, error);
243                 break;
244 
245             case PropertyType::VEC2_T:
246                 ReadVecPropertyValue<Vec2, BASE_NS::extent_v<decltype(BASE_NS::Math::Vec2::data)>>(
247                     jsonData, property, error);
248                 break;
249             case PropertyType::VEC3_T:
250                 ReadVecPropertyValue<Vec3, BASE_NS::extent_v<decltype(BASE_NS::Math::Vec3::data)>>(
251                     jsonData, property, error);
252                 break;
253             case PropertyType::VEC4_T:
254                 ReadVecPropertyValue<Vec4, BASE_NS::extent_v<decltype(BASE_NS::Math::Vec4::data)>>(
255                     jsonData, property, error);
256                 break;
257             case PropertyType::QUAT_T:
258                 ReadVecPropertyValue<Quat, BASE_NS::extent_v<decltype(BASE_NS::Math::Quat::data)>>(
259                     jsonData, property, error);
260                 break;
261             case PropertyType::MAT4X4_T:
262                 // NOTE: Implement.
263                 break;
264 
265             case PropertyType::FLOAT_T:
266             case PropertyType::FLOAT_ARRAY_T:
267                 ReadArrayPropertyValue<float>(jsonData, property, error);
268                 break;
269 
270             case PropertyType::STRING_T:
271                 ReadArrayPropertyValue<string>(jsonData, property, error);
272                 break;
273 
274             case PropertyType::ENTITY_ARRAY_T:
275             case PropertyType::VEC2_ARRAY_T:
276             case PropertyType::VEC3_ARRAY_T:
277             case PropertyType::VEC4_ARRAY_T:
278             case PropertyType::QUAT_ARRAY_T:
279             case PropertyType::MAT4X4_ARRAY_T:
280             case PropertyType::INVALID:
281                 // NOTE: Implement.
282                 break;
283         }
284     }
285 }
286 
ParseProperties(const json::value & jsonData,ISystem & system,string & error)287 void ParseProperties(const json::value& jsonData, ISystem& system, string& error)
288 {
289     const json::value* propertiesIt = jsonData.find("properties");
290     if (!propertiesIt) {
291         return;
292     }
293     auto systemPropertyHandle = system.GetProperties();
294     if (!systemPropertyHandle) {
295         return;
296     }
297     if (auto offset = systemPropertyHandle->WLock(); offset) {
298         const IPropertyApi* propertyApi = systemPropertyHandle->Owner();
299         for (size_t i = 0U, count = propertyApi->PropertyCount(); i < count; ++i) {
300             if (auto* prop = propertyApi->MetaData(i)) {
301                 PropertyValue property { systemPropertyHandle, static_cast<uint8_t*>(offset) + prop->offset, prop };
302                 ReadPropertyValue(*propertiesIt, property, error);
303             }
304         }
305     }
306     systemPropertyHandle->WUnlock();
307     system.SetProperties(*systemPropertyHandle); // notify that the properties HAVE changed.
308 }
309 
ParseSystem(const json::value & jsonData,const array_view<const ITypeInfo * const> & componentMetadata,const array_view<const ITypeInfo * const> & systemMetadata,IEcs & ecs,string & error)310 bool ParseSystem(const json::value& jsonData, const array_view<const ITypeInfo* const>& componentMetadata,
311     const array_view<const ITypeInfo* const>& systemMetadata, IEcs& ecs, string& error)
312 {
313     string typeName;
314     SafeGetJsonValue(jsonData, "typeName", error, typeName);
315 
316     bool optional = false;
317     SafeGetJsonValue(jsonData, "optional", error, optional);
318 
319     // Look up this system type from metadata.
320     const auto* typeInfo = FindTypeInfo<SystemTypeInfo>(typeName, systemMetadata);
321     if (typeInfo) {
322         // Ensure we have all components required by this system.
323         if (!ResolveComponentDependencies(ecs, typeInfo->componentDependencies, componentMetadata)) {
324             error += "Failed to resolve component dependencies: (" + typeName + ".\n";
325             return false;
326         }
327         if (!ResolveComponentDependencies(ecs, typeInfo->readOnlyComponentDependencies, componentMetadata)) {
328             error += "Failed to resolve read-only component dependencies: (" + typeName + ".\n";
329             return false;
330         }
331 
332         // Create system and read properties.
333         ISystem* system = ecs.CreateSystem(*typeInfo);
334         ParseProperties(jsonData, *system, error);
335 
336         return true;
337     }
338     CORE_LOG_W("Cannot find system: %s (optional: %s)", typeName.c_str(), (optional ? "true" : "false"));
339     if (!optional) {
340         error += "Cannot find system: " + typeName + ".\n";
341     }
342 
343     return optional;
344 }
345 
ParseSystemGraphVersion(const json::value & jsonData)346 SystemGraphLoader::LoadResult ParseSystemGraphVersion(const json::value& jsonData)
347 {
348     SystemGraphLoader::LoadResult finalResult;
349     string ver;
350     string type;
351     uint32_t verMajor { ~0u };
352     uint32_t verMinor { ~0u };
353     if (const json::value* iter = jsonData.find("compatibility_info"); iter) {
354         SafeGetJsonValue(*iter, "type", finalResult.error, type);
355         SafeGetJsonValue(*iter, "version", finalResult.error, ver);
356         if (ver.size() == VERSION_SIZE) {
357             const auto delim = ver.find('.');
358             if ((delim != string::npos) && (delim < (ver.size() - 1U))) {
359                 std::from_chars(ver.data(), ver.data() + delim, verMajor);
360                 std::from_chars(ver.data() + delim + 1, ver.data() + ver.size(), verMinor);
361             }
362         }
363     }
364     if ((type != "systemgraph") || (verMajor != VERSION_MAJOR)) {
365         // NOTE: we're still loading the system graph
366         CORE_LOG_W("DEPRECATED SYSTEM GRAPH: invalid system graph type (%s) and / or invalid version (%s).",
367             type.c_str(), ver.c_str());
368     }
369     return finalResult;
370 }
371 
LoadFromNullTerminated(const string_view jsonString,IEcs & ecs)372 ISystemGraphLoader::LoadResult LoadFromNullTerminated(const string_view jsonString, IEcs& ecs)
373 {
374     const auto json = json::parse(jsonString.data());
375     if (!json) {
376         return ISystemGraphLoader::LoadResult("Invalid json file.");
377     }
378     ISystemGraphLoader::LoadResult finalResult = ParseSystemGraphVersion(json);
379     const auto& systemsArrayIt = json.find("systems");
380     if (systemsArrayIt && systemsArrayIt->is_array()) {
381         auto& pluginRegister = GetPluginRegister();
382         auto componentMetadata = pluginRegister.GetTypeInfos(ComponentManagerTypeInfo::UID);
383         auto systemMetadata = pluginRegister.GetTypeInfos(SystemTypeInfo::UID);
384         for (const auto& systemJson : systemsArrayIt->array_) {
385             if (!ParseSystem(systemJson, componentMetadata, systemMetadata, ecs, finalResult.error)) {
386                 break;
387             }
388         }
389     }
390 
391     finalResult.success = finalResult.error.empty();
392 
393     return finalResult;
394 }
395 } // namespace
396 
Load(const string_view uri,IEcs & ecs)397 SystemGraphLoader::LoadResult SystemGraphLoader::Load(const string_view uri, IEcs& ecs)
398 {
399     IFile::Ptr file = fileManager_.OpenFile(uri);
400     if (!file) {
401         CORE_LOG_D("Error loading '%s'", string(uri).c_str());
402         return LoadResult("Failed to open file.");
403     }
404 
405     const uint64_t byteLength = file->GetLength();
406 
407     string raw(static_cast<size_t>(byteLength), string::value_type());
408     if (file->Read(raw.data(), byteLength) != byteLength) {
409         CORE_LOG_D("Error loading '%s'", string(uri).c_str());
410         return LoadResult("Failed to read file.");
411     }
412 
413     return LoadFromNullTerminated(raw, ecs);
414 }
415 
LoadString(const string_view jsonString,IEcs & ecs)416 SystemGraphLoader::LoadResult SystemGraphLoader::LoadString(const string_view jsonString, IEcs& ecs)
417 {
418     // make sure the input is zero terminated before parsing.
419     const auto asString = string(jsonString);
420     return LoadFromNullTerminated(asString, ecs);
421 }
422 
SystemGraphLoader(IFileManager & fileManager)423 SystemGraphLoader::SystemGraphLoader(IFileManager& fileManager) : fileManager_ { fileManager } {}
424 
Destroy()425 void SystemGraphLoader::Destroy()
426 {
427     delete this;
428 }
429 
430 // SystemGraphLoader factory
Create(IFileManager & fileManager)431 ISystemGraphLoader::Ptr SystemGraphLoaderFactory::Create(IFileManager& fileManager)
432 {
433     return ISystemGraphLoader::Ptr { new SystemGraphLoader(fileManager) };
434 }
435 
GetInterface(const Uid & uid) const436 const IInterface* SystemGraphLoaderFactory::GetInterface(const Uid& uid) const
437 {
438     if ((uid == ISystemGraphLoaderFactory::UID) || (uid == IInterface::UID)) {
439         return this;
440     }
441     return nullptr;
442 }
443 
GetInterface(const Uid & uid)444 IInterface* SystemGraphLoaderFactory::GetInterface(const Uid& uid)
445 {
446     if ((uid == ISystemGraphLoaderFactory::UID) || (uid == IInterface::UID)) {
447         return this;
448     }
449     return nullptr;
450 }
451 
Ref()452 void SystemGraphLoaderFactory::Ref() {}
453 
Unref()454 void SystemGraphLoaderFactory::Unref() {}
455 CORE_END_NAMESPACE()
456