Cogs.Core
EntityReader.cpp
1#include "EntityReader.h"
2
3#include "Types.h"
4#include "EntityStore.h"
5#include "ReaderCommon.h"
6#include "ResourceReader.h"
7
8#include "Utilities/Parsing.h"
9
10#include "Foundation/Logging/Logger.h"
11#include "Foundation/HashFunctions.h"
12
13#include <glm/glm.hpp>
14#include <glm/gtx/quaternion.hpp>
15
16namespace
17{
18 Cogs::Logging::Log logger = Cogs::Logging::getLogger("EntityReader");
19}
20
21namespace Cogs::Core
22{
23 void readMaterialInstanceField(Context * context, const Value & value, FieldValue & fieldValue, ExpressionContext * ec)
24 {
25 fieldValue.type = DefaultValueType::MaterialInstance;
26
27 static_assert(sizeof(MaterialInstanceDefinition) <= sizeof(fieldValue.storage));
28 auto & materialInstance = *(new (fieldValue.storage) MaterialInstanceDefinition());
29 materialInstance.type = ResourceTypes::MaterialInstance;
30
31 if (value.IsString()) {
32 std::string v = toString(value);
33
34 if (v[0] == '$') {
35 materialInstance.reference = v.substr(1);
36 } else {
37 // Just the type indicated, all other properties default.
38 materialInstance.material = v;
39 }
40 } else if (value.IsObject()) {
41 ReaderContext rc{ context, ec, nullptr };
42 readMaterialInstanceDefinition(&rc, value, materialInstance);
43 }
44 }
45}
46
47void Cogs::Core::readEntityDefaults(Context * context, const Value & value, std::vector<FieldValue> & defaultValues, ExpressionContext * ec)
48{
49 if (value.IsArray()) {
50 for (auto & d : value.GetArray()) {
51 readFieldValues(context, d.MemberBegin()->value, toKey(d.MemberBegin()->name), defaultValues, ec);
52 }
53 }
54 else if (value.IsObject()) {
55 for (auto & d : value.GetObject()) {
56 readFieldValues(context, d.value, toKey(d.name), defaultValues, ec);
57 }
58 }
59}
60
61bool Cogs::Core::readFieldValue(Context * context, const Value & jsonValue, const Reflection::Type & type, const StringView & fieldName, std::vector<FieldValue>& fieldValues, ExpressionContext * ec)
62{
63 const auto field = type.getField(fieldName.to_string());
64
65 if (!field) {
66 LOG_ERROR(logger, "Field \"%.*s\" not found in type %s.", StringViewFormat(fieldName), type.getName().c_str());
67
68 return false;
69 }
70
71 if (jsonValue.IsNull()) {
72 return false;
73 }
74
75 const auto & fieldType = Reflection::TypeDatabase::getType(field->getTypeId());
76
77 FieldValue value = {};
78 value.componentId = type.getTypeId();
79 value.fieldId = type.getFieldId(field);
80
81 if (fieldType.isEnum()) {
82 if (jsonValue.IsString()) {
83 if (fieldType.isEnumFlags()) {
84 value.intValue = parseEnumFlags(toKey(jsonValue), fieldType, value.intValue);
85 }
86 else {
87 value.intValue = parseEnum(toKey(jsonValue), fieldType, value.intValue);
88 }
89 value.type = DefaultValueType::Enum;
90 }
91 else if (jsonValue.IsNumber()) {
92 value.type = DefaultValueType::Enum;
93 if (jsonValue.IsInt()) {
94 value.intValue = jsonValue.GetInt();
95 }
96 else {
97 value.intValue = (int)jsonValue.GetDouble();
98 }
99 }
100 else {
101 LOG_ERROR(logger, "Invalid enum of field: %.*s of type %s.", StringViewFormat(fieldName), type.getName().c_str());
102 }
103 }
104 else if (fieldType == Reflection::TypeDatabase::getType<bool>()) {
105 if (jsonValue.IsBool()) {
106 value.boolValue = jsonValue.GetBool();
107 value.type = DefaultValueType::Bool;
108 }
109 else if (jsonValue.IsString()) {
110 value.boolValue = readValue<bool>(jsonValue, ec);
111 value.type = DefaultValueType::Bool;
112 }
113 else {
114 LOG_ERROR(logger, "Invalid bool of field: %.*s of type %s.", StringViewFormat(fieldName), type.getName().c_str());
115 }
116 }
117 else if (fieldType == Reflection::TypeDatabase::getType<glm::vec2>()) {
118 readArray(jsonValue, value.float2, ec);
119 value.type = DefaultValueType::Vec2;
120 }
121 else if (fieldType == Reflection::TypeDatabase::getType<glm::vec3>()) {
122 readArray(jsonValue, value.float3, ec);
123 value.type = DefaultValueType::Vec3;
124 }
125 else if (fieldType == Reflection::TypeDatabase::getType<glm::vec4>()) {
126 readArray(jsonValue, value.float4, ec);
127 value.type = DefaultValueType::Vec4;
128 }
129 else if (fieldType == Reflection::TypeDatabase::getType<glm::mat4>()) {
130 readArray(jsonValue, glm::value_ptr(value.mat4), 16, ec);
131 value.type = DefaultValueType::Mat4;
132 }
133 else if (fieldType == Reflection::TypeDatabase::getType<glm::dvec2>()) {
134 readArray(jsonValue, value.double2, ec);
135 value.type = DefaultValueType::DVec2;
136 }
137 else if (fieldType == Reflection::TypeDatabase::getType<glm::dvec3>()) {
138 readArray(jsonValue, value.double3, ec);
139 value.type = DefaultValueType::DVec3;
140 }
141 else if (fieldType == Reflection::TypeDatabase::getType<glm::dvec4>()) {
142 readArray(jsonValue, value.double4, ec);
143 value.type = DefaultValueType::DVec4;
144 }
145 else if (fieldType == Reflection::TypeDatabase::getType<glm::quat>()) {
146 bool success = false;
147 auto arr = jsonValue.GetArray();
148 if (arr.Size() == 2) {
149 if (arr[0].IsArray()) {
150 auto A0 = arr[0].GetArray();
151 if (A0.Size() == 3) {
152 if (arr[1].IsArray()) {
153 auto A1 = arr[1].GetArray();
154 if (A1.Size() == 3) {
155 // Vector-to-vector form
156 glm::vec3 src, dst;
157 readArray(arr[0], src, ec);
158 readArray(arr[1], dst, ec);
159 value.quat = glm::rotation(glm::normalize(src), glm::normalize(dst));
160 success = true;
161 }
162 } else if (arr[1].IsNumber() || arr[1].IsString()) {
163 // Axis-angle form
164 glm::vec3 axisValue;
165 readArray(arr[0], axisValue, ec);
166 float angleValue = readValue(arr[1], 1.0f, ec);
167 value.quat = glm::angleAxis(angleValue, axisValue);
168 success = true;
169 }
170 }
171 }
172 }
173 else if (arr.Size() == 4) {
174 // Raw quaternion form
175 readArray(jsonValue, value.float4, ec);
176 success = true;
177 }
178 value.type = DefaultValueType::Quaternion;
179 if (success == false) {
180 LOG_ERROR(logger, "Failed to parse quaternion of field: %.*s of type %s.", StringViewFormat(fieldName), type.getName().c_str());
181 }
182 } else if (fieldType == Reflection::TypeDatabase::getType<MaterialInstanceHandle>()) {
183 readMaterialInstanceField(context, jsonValue, value, ec);
184 } else if (fieldType == Reflection::TypeDatabase::getType<ModelHandle>()) {
185 value.type = DefaultValueType::Model;
186 value.value = jsonValue.GetString();
187 } else if (fieldType == Reflection::TypeDatabase::getType<AssetHandle>()) {
188 value.type = DefaultValueType::Asset;
189 value.value = jsonValue.GetString();
190 }else if (fieldType == Reflection::TypeDatabase::getType<GuiDocumentHandle>()) {
191 value.type = DefaultValueType::Gui;
192 value.value = jsonValue.GetString();
193 } else if (fieldType == Reflection::TypeDatabase::getType<MeshHandle>()) {
194 value.type = DefaultValueType::Mesh;
195 if (jsonValue.IsString()) {
196 auto meshName = toString(jsonValue);
197 if (meshName.size() < 2 || meshName[0] != '$') {
198 LOG_ERROR(logger, "Mesh field must be set to existing field resource using $Name syntax.");
199 return false;
200 }
201 value.value = meshName.substr(1);
202 } else {
203 ResourceDefinition def;
204 value.value = readMesh(context, def, jsonValue).to_string();
205 }
206 } else if (fieldType == Reflection::TypeDatabase::getType<TextureHandle>()) {
207 value.type = DefaultValueType::Texture;
208 value.value = toString(jsonValue);
209 } else if (fieldType == Reflection::TypeDatabase::getType<std::string>()) {
210 value.type = DefaultValueType::String;
211 value.value = toString(jsonValue);
212 } else if (fieldType == Reflection::TypeDatabase::getType<std::vector<std::string>>()) {
213 value.type = DefaultValueType::MultiString;
214 auto arr = jsonValue.GetArray();
215 for (auto & element : arr) {
216 value.values.push_back(toString(element));
217 }
218 } else if (fieldType == Reflection::TypeDatabase::getType<std::vector<int>>()) {
219 value.type = DefaultValueType::IntArray;
220 auto arr = jsonValue.GetArray();
221 for (auto & element : arr) {
222 value.intValues.push_back(element.GetInt());
223 }
224 } else if (fieldType == Reflection::TypeDatabase::getType<std::vector<float>>()) {
225 value.type = DefaultValueType::FloatArray;
226 auto arr = jsonValue.GetArray();
227 for (auto & element : arr) {
228 value.floatValues.push_back(element.GetFloat());
229 }
230 } else if (fieldType == Reflection::TypeDatabase::getType<std::vector<glm::vec2>>()) {
231 value.type = DefaultValueType::Vec2Array;
232 auto arr = jsonValue.GetArray();
233 if (!arr.Empty()) {
234 const auto & first = arr.Begin();
235
236 if (first->IsArray()) {
237 for (auto & a : arr) {
238 glm::vec2 v{};
239 if (readArray(a, v, ec) != 2) {
240 LOG_WARNING(logger, "Vector length mismatch in %s.", field->getName().c_str());
241 }
242
243 value.vec2Values.push_back(v);
244 }
245 } else if ((arr.Size() % 2) == 0) {
246 for (unsigned int indx = 0; indx < arr.Size(); indx += 2) {
247 value.vec2Values.push_back(glm::vec2{ readValue(arr[indx], 0.0f, ec), readValue(arr[indx + 1], 0.0f, ec) });
248 }
249 } else {
250 LOG_ERROR(logger, "Invalid length of %s in entity type %s.",
251 field->getName().c_str(),
252 type.getName().c_str());
253 }
254 }
255 } else if (fieldType == Reflection::TypeDatabase::getType<std::vector<glm::vec3>>()) {
256 value.type = DefaultValueType::Vec3Array;
257 auto arr = jsonValue.GetArray();
258 if (!arr.Empty()) {
259 const auto & first = arr.Begin();
260
261 if (first->IsArray()) {
262 for (auto & a : arr) {
263 glm::vec3 v{};
264 if (readArray(a, v, ec) != 3) {
265 LOG_WARNING(logger, "Vector length mismatch in %s.", field->getName().c_str());
266 }
267
268 value.vec3Values.push_back(v);
269 }
270 } else if ((arr.Size() % 3) == 0) {
271 for (unsigned int indx = 0; indx < arr.Size(); indx += 3) {
272 value.vec3Values.push_back(glm::vec3{ readValue(arr[indx], 0.0f, ec), readValue(arr[indx + 1], 0.0f, ec), readValue(arr[indx + 2], 0.0f, ec) });
273 }
274 } else {
275 LOG_ERROR(logger, "Invalid length of %s in entity type %s.",
276 field->getName().c_str(),
277 type.getName().c_str());
278 }
279 }
280 } else if (fieldType == Reflection::TypeDatabase::getType<std::vector<glm::vec4>>()) {
281 value.type = DefaultValueType::Vec4Array;
282 auto arr = jsonValue.GetArray();
283 if (!arr.Empty()) {
284 const auto & first = arr.Begin();
285
286 if (first->IsArray()) {
287 for (auto & a : arr) {
288 glm::vec4 v{};
289 if (readArray(a, v, ec) != 4) {
290 LOG_WARNING(logger, "Vector length mismatch in %s.", field->getName().c_str());
291 }
292
293 value.vec4Values.push_back(v);
294 }
295 } else if ((arr.Size() % 4) == 0) {
296 for (unsigned int indx = 0; indx < arr.Size(); indx += 4) {
297 value.vec4Values.push_back(glm::vec4{ readValue(arr[indx], 0.0f, ec), readValue(arr[indx + 1], 0.0f, ec), readValue(arr[indx + 2], 0.0f, ec), readValue(arr[indx + 3], 0.0f, ec) });
298 }
299 } else {
300 LOG_ERROR(logger, "Invalid length of %s in entity type %s.",
301 field->getName().c_str(),
302 type.getName().c_str());
303 }
304 }
305 } else if (fieldType == Reflection::TypeDatabase::getType<EntityPtr>() || fieldType == Reflection::TypeDatabase::getType<WeakEntityPtr>()) {
306 value.type = DefaultValueType::Entity;
307 value.value = toString(jsonValue);
308 } else if (fieldType == Reflection::TypeDatabase::getType<std::vector<EntityPtr>>() || fieldType == Reflection::TypeDatabase::getType<std::vector<WeakEntityPtr>>()) {
309 value.type = DefaultValueType::EntityArray;
310 auto arr = jsonValue.GetArray();
311 for (auto & element : arr) {
312 value.values.push_back(toString(element));
313 }
314 } else {
315 auto ext = getExtensionReader(fieldType.getTypeId());
316
317 if (ext) {
318 value.type = DefaultValueType::Extension;
319 value.value = toString(jsonValue);
320 } else if (fieldType == Reflection::TypeDatabase::getType<float>()) {
321 value.type = DefaultValueType::Float;
322 value.floatValue = readValue<float>(jsonValue, 0.0f, ec);
323 } else if (fieldType == Reflection::TypeDatabase::getType<uint32_t>()) {
324 value.type = DefaultValueType::Int;
325 value.intValue = readValue<int>(jsonValue, ec);
326 }
327 else if (fieldType == Reflection::TypeDatabase::getType<int32_t>()) {
328 value.type = DefaultValueType::Int;
329 value.intValue = readValue<int>(jsonValue, ec);
330 }
331 else {
332 LOG_WARNING(logger, "Value defined for Field: %s, Component type: %s Unsupported.",
333 field->getName().c_str(),
334 type.getName().c_str());
335 return false;
336 }
337 }
338
339 if (value.fieldId != Reflection::NoField) {
340 fieldValues.push_back(value);
341 } else {
342 LOG_ERROR(logger, "Value defined for field %s which was not found on entity type %s.",
343 field->getName().c_str(),
344 type.getName().c_str());
345 }
346
347 return true;
348}
349
350bool Cogs::Core::readFieldValues(Context * context, const Value & jsonFieldValues, const StringView & typeName, std::vector<FieldValue> & fieldValues, ExpressionContext * ec)
351{
352 const auto & type = Reflection::TypeDatabase::getType(typeName);
353
354 if (!type.isValid()) {
355 LOG_ERROR(logger, "Type \"%.*s\" invalid.", StringViewFormat(typeName));
356
357 return false;
358 }
359
360 if (!jsonFieldValues.IsObject()) return false;
361
362 auto valuesObject = jsonFieldValues.GetObject();
363
364 if (valuesObject.ObjectEmpty()) {
365 FieldValue value = {};
366 value.componentId = type.getTypeId();
367
368 fieldValues.push_back(value);
369 }
370
371 bool success = true;
372 for (auto & member : valuesObject) {
373 const auto fieldName = toKey(member.name);
374
375 if (!fieldName.size()) {
376 LOG_ERROR(logger, "Field name cannot be empty.");
377
378 continue;
379 }
380
381 success &= readFieldValue(context, member.value, type, fieldName, fieldValues, ec);
382 }
383
384 return success;
385}
386
387void Cogs::Core::readEntityDefinition(EntityStore * store, const StringView & name, const Value & value)
388{
389 EntityDefinition definition;
390
391 readEntityDefinition(store, name, value, definition);
392
393 if (!definition.name.empty()) {
394 store->addEntityDefinition(definition);
395 } else {
396 LOG_WARNING(logger, "Discarding anonymous entity definition.");
397 }
398}
399
400bool Cogs::Core::readEntityDefinition(EntityStore * store, const StringView & name, const Value & value, EntityDefinition & definition)
401{
402 if (name.size()) definition.name = name.to_string();
403
404 if (value.IsString()) {
405 StringView aliasedName(value.GetString(), value.GetStringLength());
406 auto aliasedDefinition = store->getEntityDefinition(aliasedName);
407
408 if (!aliasedDefinition) {
409 LOG_ERROR(logger, "Cannot alias unknown enitity definition %.*s.", StringViewFormat(aliasedName));
410
411 return false;
412 }
413
414 definition.components = aliasedDefinition->components;
415 definition.defaultValues = aliasedDefinition->defaultValues;
416
417 return true;
418 } else if (!value.IsObject()) {
419 LOG_ERROR(logger, "Invalid JSON value structure.");
420 return false;
421 }
422
423 ExpressionContext ec;
424 ec.add("true", 1);
425 ec.add("false", 0);
426
427 for (const auto & member : value.GetObject()) {
428 auto key = StringView(member.name.GetString());
429
430 if (key == "name") {
431 definition.name = member.value.GetString();
432 } else if (key == "description") {
433#if !defined( EMSCRIPTEN )
434 definition.description = member.value.GetString();
435#endif
436 } else if (key == "components") {
437 auto arr = member.value.GetArray();
438
439 if (!arr.Size()) {
440 LOG_WARNING(logger, "Entity definition created for %s with zero components defined.", definition.name.c_str());
441 }
442
443 for (auto & m : arr) {
444 definition.components.push_back(m.GetString());
445 }
446 } else if (key == "defaults") {
447 readEntityDefaults(store->getContext(), member.value, definition.defaultValues, &ec);
448 } else if (key == "inherits") {
449 StringView inheritedName(member.value.GetString(), member.value.GetStringLength());
450 auto inheritedDefinition = store->getEntityDefinition(inheritedName);
451
452 if (!inheritedDefinition) {
453 LOG_ERROR(logger, "Cannot inherit unknown enitity definition %.*s.", StringViewFormat(inheritedName));
454
455 return false;
456 }
457
458 for (auto & c : inheritedDefinition->components) {
459 definition.components.push_back(c);
460 }
461
462 for (auto & d : inheritedDefinition->defaultValues) {
463 definition.defaultValues.push_back(d);
464 }
465 } else {
466 readFieldValues(store->getContext(), member.value, key, definition.defaultValues, &ec);
467 }
468 }
469
470 return !definition.name.empty();
471}
472
473void Cogs::Core::readEntityDefinition(const StringView & content, EntityStore * entityStore)
474{
475 auto document = parseJson(content, JsonParseFlags::NoCachedContent);
476
477 readEntityDefinition(entityStore, "", document);
478}
Stores top level entities for the engine.
Definition: EntityStore.h:50
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
std::string to_string() const
String conversion method.
Definition: StringView.cpp:9
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180