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