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