· 7 years ago · Jan 01, 2019, 03:32 AM
1#include "DreamEngine.h"
2#include "../Headers/Systems/Serialization/Serializer.h"
3#include "../Headers/DreamEngines/Level.h"
4#include <sstream>
5
6//todo: refactor, alot of code here performs the same thing
7
8namespace Serializer
9{
10 void savePtrTable(DataObject& dObj, const std::map<void*, int>& ptrTable)
11 {
12 DataObject& child = dObj.createChild();
13 child.name = "PointerTable";
14 for (auto& iter : ptrTable)
15 {
16 const void * address = static_cast<const void*>(iter.first);
17 std::stringstream ss;
18 ss << address;
19 child.set(std::to_string(iter.second), ss.str());
20 }
21 child.set("count", std::to_string(ptrTable.size()));
22 }
23
24 void loadPtrTable(const DataObject& dObj, std::map<void*, int>& ptrTable)
25 {
26 for (auto& child : dObj.getChildren())
27 {
28 if (child->name == "PointerTable")
29 {
30 auto sz = std::stoul(child->get("count"));
31 for (size_t i = 0; i < sz; ++i)
32 {
33 INT64 val = std::stoll(child->get(std::to_string(i), "0"),0, 16);
34 ptrTable[(void*)val] = (int)i;
35 }
36 return;
37 }
38 }
39 }
40
41 void updateWeakPtrs(const std::map<void*, int> oldPtrTable, const std::map<int, void*> newPtrTable, const std::list<void**> weakPtrsToUpdate)
42 {
43 for (auto& ptr : weakPtrsToUpdate)
44 {
45 void* val = *ptr;
46 if (oldPtrTable.count(val) > 0)
47 {
48 int id = oldPtrTable.at(*ptr);
49 if (newPtrTable.count(id) > 0)
50 {
51 *ptr = newPtrTable.at(id);
52 }
53 else *ptr = nullptr;
54 }
55 else *ptr = nullptr;
56 }
57 }
58
59 int assignIDToPtr(void* ptr, std::map<void*, int>& ptrTable)
60 {
61 if (ptr == nullptr) return -1;
62 if (ptrTable.count(ptr) > 0) return ptrTable[ptr];
63 int id = ptrTable.size();
64 ptrTable[ptr] = id;
65 return id;
66 }
67
68 void assignPtrToId(void* ptr, int id, std::map<int, void*>& ptrTable)
69 {
70 if (id == -1) return;
71 if (ptr == nullptr) return;
72 if (ptrTable.count(id) > 0) ptrTable.erase(id);
73 ptrTable[id] = ptr;
74 }
75
76 void* getPtr(int id, const std::map<void*, int>& ptrTable)
77 {
78 if (id == -1) return nullptr;
79 for (auto& iter : ptrTable)
80 {
81 if (iter.second == id) return iter.first;
82 }
83 return nullptr;
84 }
85
86 bool saveMiscVarsToFile(const std::list<SerializableVar>& vars, const std::string& file, bool saveAsHumanReadable, bool saveWeakPtrs)
87 {
88 assert(file.empty() == false);
89 bool res = true;
90 DataObject dObj;
91 std::map<void*, int > ptrTable;
92 std::map<void*, int >* tablePtr = &ptrTable;
93 if (saveWeakPtrs == false) tablePtr = nullptr;
94 for (auto& _var : vars)
95 {
96 auto& child = dObj.createChild();
97 child.name = _var.name;
98 bool thisRes = serializeVar(_var.var, _var.name, child, *_var.typeData, tablePtr);
99 if (thisRes == false) res = false;
100 }
101 if (saveAsHumanReadable == true) res = dObj.saveAsXml(file, true);
102 else res = dObj.saveToFile(file, true, false);
103 return res;
104 }
105
106 bool readMiscVarsFromFile(const std::list<SerializableVar>& vars, const std::string& file, bool unserializeWeakPtrs)
107 {
108 assert(file.empty() == false);
109 DataObject dObj;
110 if (FileIO::fileExists(file) == false) return false;
111 if (file.back() == 'l') dObj.readAsXml(file);
112 else dObj.readFromFile(file);
113
114 std::map<void*, int> oldPtrTable;
115 std::map<int, void*> newPtrTable;
116 std::list<void**> weakPtrs;
117 std::map<int, void*>* newTablePtr = &newPtrTable;
118 std::list<void**>* weakPtrsPtr = &weakPtrs;
119 if (unserializeWeakPtrs == false)
120 {
121 newTablePtr = nullptr;
122 weakPtrsPtr = nullptr;
123 }
124 if (unserializeWeakPtrs) loadPtrTable(dObj, oldPtrTable);
125 bool res = true;
126 for (auto& var : vars)
127 {
128 for (auto& child : dObj.getChildren())
129 {
130 if (child->name == var.name)
131 {
132 bool thisRes = unserializeVar(var.var, var.name, *child, *var.typeData, newTablePtr, weakPtrsPtr);
133 if (thisRes == false) res = false;
134 break;
135 }
136 }
137 }
138 if (unserializeWeakPtrs) updateWeakPtrs(oldPtrTable, newPtrTable, weakPtrs);
139 return res;
140 }
141
142 bool saveLvlToFile(const Level& lvl, const std::string& file, bool saveAsHumanReadable, bool saveWeakPtrs)
143 {
144 assert(file.empty() == false);
145 assert(&lvl != nullptr);
146 bool res = true;
147 DataObject dObj;
148 std::map<void*, int > ptrTable;
149 if (saveWeakPtrs) res = serializeLvl(lvl, dObj, &ptrTable);
150 else res = serializeLvl(lvl, dObj, nullptr);
151 if (res == false) return false;
152 if (saveWeakPtrs) savePtrTable(dObj, ptrTable);
153 if (saveAsHumanReadable == true) res = dObj.saveAsXml(file, true);
154 else res = dObj.saveToFile(file, true, false);
155 return res;
156 }
157
158 bool saveGameObjectToFile(const GameObject& obj, const std::string& file, bool saveAsHumanReadable, bool saveWeakPtrs)
159 {
160 assert(file.empty() == false);
161 assert(&obj != nullptr);
162 bool res = true;
163 DataObject dObj;
164 std::map<void*, int > ptrTable;
165 if (saveWeakPtrs) res = serializeGameObject(obj, dObj, &ptrTable);
166 else res = serializeGameObject(obj, dObj, nullptr);
167 if (res == false) return false;
168 if (saveWeakPtrs) savePtrTable(dObj, ptrTable);
169 if (saveAsHumanReadable == true) res = dObj.saveAsXml(file, true);
170 else res = dObj.saveToFile(file, true, false);
171 return res;
172 }
173
174 bool saveClassToFile(void* obj, const ClassData& classData, const std::string& file, bool saveAsHumanReadable, bool saveWeakPtrs)
175 {
176 assert(file.empty() == false);
177 assert(&obj != nullptr);
178 bool res = true;
179 DataObject dObj;
180 std::map<void*, int > ptrTable;
181 if (saveWeakPtrs) res = serializeClass(obj, dObj, classData, &ptrTable);
182 else res = serializeClass(obj, dObj, classData, nullptr);
183 if (res == false) return false;
184 if (saveWeakPtrs) savePtrTable(dObj, ptrTable);
185 if (saveAsHumanReadable == true) res = dObj.saveAsXml(file, true);
186 else res = dObj.saveToFile(file, true, false);
187 return res;
188 }
189
190 bool readLvlFromFile(Level*& lvl, const std::string& file, bool unserializeWeakPtrs)
191 {
192 assert(file.empty() == false);
193 lvl = (Level*)(static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<Level>()).allocateObj());
194 if (lvl == nullptr) return false;
195 DataObject dObj;
196 if (FileIO::fileExists(file) == false) return false;
197 if (file.back() == 'l') dObj.readAsXml(file);
198 else dObj.readFromFile(file);
199 const DataObject* lvlObj = &dObj;
200 if (dObj.name == "MultiLevel") lvlObj = dObj.getChildren()[0];
201 std::map<void*, int> oldPtrTable;
202 std::map<int, void*> newPtrTable;
203 std::list<void**> weakPtrs;
204 if (unserializeWeakPtrs) loadPtrTable(*lvlObj, oldPtrTable);
205 bool res = false;
206 if (unserializeWeakPtrs) res = unserializeLvl(*lvl, *lvlObj, &newPtrTable, &weakPtrs);
207 else res = unserializeLvl(*lvl, *lvlObj, &newPtrTable, nullptr);
208 if (unserializeWeakPtrs) updateWeakPtrs(oldPtrTable, newPtrTable, weakPtrs);
209 return res;
210 }
211
212 Level* readLvlFromFile(const std::string& file, bool unserializeWeakPtrs)
213 {
214 assert(file.empty() == false);
215 const TypeData& typeData = *DreamEngine::RTTISys().getTypeData<Level>();
216 Level* lvl = (Level*)typeData.allocateObj();
217 if (lvl == nullptr) return nullptr;
218 if (FileIO::fileExists(file) == false) return nullptr;
219 bool res = readLvlFromFile(lvl, file, unserializeWeakPtrs);
220 return lvl;
221 }
222
223 bool readGameObjectFromFile(GameObject*& obj, const std::string& file, bool unserializeWeakPtrs)
224 {
225 assert(file.empty() == false);
226 DataObject dObj;
227 std::map<void*, int> oldPtrTable;
228 std::map<int, void*> newPtrTable;
229 std::list<void**> weakPtrs;
230 if (FileIO::fileExists(file) == false) return false;
231 if (file.back() - 2 == 'x') dObj.readAsXml(file);
232 else dObj.readFromFile(file);
233 if (unserializeWeakPtrs) loadPtrTable(dObj, oldPtrTable);
234 const ClassData* gameObjData = static_cast<ClassData*>(DreamEngine::RTTISys().getTypeData(dObj.get("type_name")));
235 if (gameObjData == nullptr) gameObjData = static_cast<ClassData*>(DreamEngine::RTTISys().getTypeData(dObj.get("hash_code")));
236 if (obj == nullptr) obj = (GameObject*)gameObjData->allocateObj();
237 if (obj == nullptr) return false;
238 bool res = false;
239 if (unserializeWeakPtrs) res = unserializeGameObject(*obj, dObj, &newPtrTable, &weakPtrs);
240 else res = unserializeGameObject(*obj, dObj, nullptr, nullptr);
241 if (unserializeWeakPtrs) updateWeakPtrs(oldPtrTable, newPtrTable, weakPtrs);
242 return res;
243 }
244
245 bool readClassFromFile(void* obj, const std::string& file, bool unserializeWeakPtrs)
246 {
247 assert(file.empty() == false);
248 DataObject dObj;
249 std::map<void*, int> oldPtrTable;
250 std::map<int, void*> newPtrTable;
251 std::list<void**> weakPtrs;
252 if (FileIO::fileExists(file) == false) return false;
253 if (file.back() - 2 == 'x') dObj.readAsXml(file);
254 else dObj.readFromFile(file);
255 if (unserializeWeakPtrs) loadPtrTable(dObj, oldPtrTable);
256 if (obj == nullptr) obj = (static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData(dObj.get("type_name"))).allocateObj());
257 if (obj == nullptr) return false;
258 bool res = false;
259 if (unserializeWeakPtrs) res = unserializeClass((void*)obj, dObj, static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData(dObj.get("type_name"))), &newPtrTable, &weakPtrs);
260 else res = unserializeClass((void*)obj, dObj, static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData(dObj.get("type_name"))));
261 if (unserializeWeakPtrs) updateWeakPtrs(oldPtrTable, newPtrTable, weakPtrs);
262 return res;
263 }
264
265 void callOnSerialize(void* obj, const ClassData& typeData, DataObject& dObj)
266 {
267 assert(&typeData != nullptr);
268 assert(obj != nullptr);
269 for (auto& fn : typeData.getAllMemberFunctions())
270 {
271 if (fn->getName() == "onSerialize")
272 {
273 ((GenesisClass*)obj)->onSerialize(dObj);
274 return;
275 }
276 }
277 }
278 void callOnPreserialize(void* obj, const ClassData& typeData, DataObject& dObj)
279 {
280 assert(&typeData != nullptr);
281 assert(obj != nullptr);
282 for (auto& fn : typeData.getAllMemberFunctions())
283 {
284 if (fn->getName() == "onPreserialize")
285 {
286 GenesisClass* ptr = ((GenesisClass*)obj);
287 ptr->onPreserialize(dObj);
288 return;
289 }
290 }
291 }
292
293 void callOnUnserialize(void* obj, const ClassData& typeData, const DataObject& dObj)
294 {
295 assert(obj != nullptr);
296 assert(&typeData != nullptr);
297 for (auto& fn : typeData.getAllMemberFunctions())
298 {
299 if (fn->getName() == "onUnserialize")
300 {
301 ((GenesisClass*)obj)->onUnserialize(dObj);
302 return;
303 }
304 }
305 }
306
307
308 void setLevelPtr(Level& lvl, const GameObject& obj)
309 {
310 assert(&obj != nullptr);
311 ClassData& gameObjTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<GameObject>());
312 for (auto& mem : gameObjTypeData.getAllMemberVars())
313 {
314 if (mem->getName() == "currentLevel")
315 {
316 *(Level**)((char*)&obj + mem->getOffset()) = &lvl;
317 return;
318 }
319 }
320 }
321
322 void copyLevelAndParentPtr(const GameObject& from, const GameObject& to)
323 {
324 assert(&from != nullptr);
325 assert(&to != nullptr);
326 ClassData& gameObjTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<GameObject>());
327 for (auto& mem : gameObjTypeData.getAllMemberVars())
328 {
329 if (mem->getName() == "currentLevel")
330 {
331 *(Level**)((char*)&to + mem->getOffset()) = *(Level**)((char*)&from + mem->getOffset());
332 return;
333 }
334 if (mem->getName() == "parent")
335 {
336 *(GameObject**)((char*)&to + mem->getOffset()) = *(GameObject**)((char*)&from + mem->getOffset());
337 return;
338 }
339 }
340 }
341
342 void setGameObjectPtr(GameObject& gObj, const Component& cmp)
343 {
344 assert(&cmp != nullptr);
345 ClassData& cmpTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<Component>());
346 for (auto& mem : cmpTypeData.getAllMemberVars())
347 {
348 if (mem->getName() == "gameobject")
349 {
350 *(GameObject**)((char*)&cmp + mem->getOffset()) = &gObj;
351 return;
352 }
353 }
354 }
355
356 void copyGameObjectPtr(const Component& from, const Component& to)
357 {
358 assert(&from != nullptr);
359 assert(&to != nullptr);
360 ClassData& cmpTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<Component>());
361 for (auto& mem : cmpTypeData.getAllMemberVars())
362 {
363 if (mem->getName() == "gameobject")
364 {
365 *(GameObject**)((char*)&to + mem->getOffset()) = *(GameObject**)((char*)&from + mem->getOffset());
366 return;
367 }
368 }
369 }
370
371 bool serializeOwnedPtr(DataObject& dObj, const std::string& memName, void* base, size_t offset, const TypeData& derefTypeData, std::map<void*, int>* ptrTable = nullptr)
372 {
373 assert(base != nullptr);
374 assert(&derefTypeData != nullptr);
375 bool res = true;
376 TypeOfType derefType = derefTypeData.getType();
377 void* ptr = ((char*)base + offset);
378 if (ptr == nullptr) return false;
379 ptr = (*(void**)ptr);
380 if (ptr == nullptr) return false;
381 if (derefType == TypeOfType::type_base || derefType == TypeOfType::type_enum)
382 {
383 dObj.set(memName, derefTypeData.toString(ptr));
384 if (ptrTable != nullptr)
385 {
386 dObj.set(memName + "_id", std::to_string(assignIDToPtr(ptr, *ptrTable)));
387 }
388 }
389 else if (derefType == TypeOfType::type_iterable_array || derefType == TypeOfType::type_iterable_class)
390 {
391 const ArrayData& arrayData = static_cast<const ArrayData&>(derefTypeData);
392 DataObject& child = dObj.createChild();
393 child.name = memName;
394 res = serializeArray(ptr, child, arrayData, true, ptrTable);
395 }
396 else if (derefType == TypeOfType::type_class)
397 {
398 DataObject& child = dObj.createChild();
399 child.name = memName;
400 if (derefTypeData.getTypeHash() == typeid(GameObject).hash_code())
401 {
402 res = serializeGameObject(*(GameObject*)ptr, child, ptrTable);
403 }
404 else res = serializeClass(ptr, child, static_cast<const ClassData&>(derefTypeData), ptrTable);
405 }
406 else if (derefType == TypeOfType::type_ptr)
407 {
408 //not handling ptrs to ptrs for now
409 }
410 return res;
411 }
412
413
414 bool unserializeOwnedPtr(const DataObject& dObj, const std::string& memName, void* base, size_t offset, const TypeData& derefTypeData, std::map<int, void*>* ptrTable = nullptr, std::list<void**>* weakPtrsToUpdate = nullptr)
415 {
416 /*If this causes a crash,
417 this might be because the pointer being unserialized right now
418 is set to a non-nullptr value.
419
420 The unserializer then assumes memory has already been allocated
421 for the object pointed to by the pointer (maybe in the constructor for this class),
422 or the pointer now points to some object in global memory or on the stack.
423
424 However if the pointer value is actually simply uninitialized,
425 then the unserialization will likely write to out-of-bounds memory.
426 So make sure your class constructors set pointers to nullptr!
427 */
428 assert(base != nullptr);
429 assert(&derefTypeData != nullptr);
430 (weakPtrsToUpdate);
431 TypeOfType derefType = derefTypeData.getType();
432 void** ptr = (void**)((char*)base + offset);
433 if (derefType == TypeOfType::type_base || derefType == TypeOfType::type_enum)
434 {
435 /*todo:
436 sometimes the elem ptr passed to unserialize here may be of a different
437 derived type then the type indicated in dObj.
438 best way to handle?
439 */
440 void* obj;
441 if (*ptr == nullptr) obj = derefTypeData.allocateObj();
442 else obj = *ptr;
443 if (obj != nullptr)
444 {
445 derefTypeData.fromString(obj, dObj.get(memName));
446 *ptr = obj;
447 }
448 if (ptrTable != nullptr)
449 {
450 assignPtrToId(*ptr, std::stoi(dObj.get(memName + "_id", "-1")), *ptrTable);
451 }
452 }
453 else if (derefType == TypeOfType::type_iterable_array || derefType == TypeOfType::type_iterable_class)
454 {
455 void* obj;
456 if (*ptr == nullptr) obj = derefTypeData.allocateObj();
457 else obj = *ptr;
458 if (obj != nullptr)
459 {
460 for (auto& child : dObj.getChildren())
461 {
462 if (child->name == memName)
463 {
464 unserializeArray(obj, *child, static_cast<const ArrayData&>(derefTypeData), true, ptrTable, weakPtrsToUpdate);
465 *ptr = obj;
466 break;
467 }
468 }
469 }
470 }
471 else if (derefType == TypeOfType::type_class)
472 {
473 const ClassData* derefClassData = static_cast<const ClassData*>(&derefTypeData);
474 void* obj;
475 for (auto& child : dObj.getChildren())
476 {
477 if (child->name == memName)
478 {
479 if (*ptr == nullptr) obj = static_cast<const ClassData*>(DreamEngine::RTTISys().getTypeData(child->get("type_name")))->allocateObj();
480 else obj = *ptr;
481 if (obj != nullptr)
482 {
483 if (derefClassData->getTypeHash() == DreamEngine::RTTISys().getTypeData<GameObject>()->getTypeHash())
484 {
485 unserializeGameObject(*(GameObject*)obj, *child, ptrTable, weakPtrsToUpdate);
486 }
487 else unserializeClass(obj, *child, *derefClassData, ptrTable, weakPtrsToUpdate);
488 *ptr = obj;
489 }
490 break;
491 }
492 }
493 }
494 else if (derefType == TypeOfType::type_ptr)
495 {
496 //not handling ptrs to ptrs for now
497 }
498 return true;
499 }
500
501 bool unserializeClass(void* obj, const DataObject& dObj, const ClassData& objTypeData, std::map<int, void*>* ptrTable, std::list<void**>* weakPtrsToUpdate)
502 {
503 assert(obj != nullptr);
504 assert(&objTypeData != nullptr);
505 if (dObj.get("type_name") != objTypeData.getName()) return false; //types no longer match, do not attempt unserialization
506 bool res = true;
507 if (ptrTable != nullptr)
508 {
509 assignPtrToId(obj, std::stoi(dObj.get("this_id", "-1")), *ptrTable);
510 }
511 for (const auto& mem : objTypeData.getAllMemberVars())
512 {
513 if (mem->getIsSerializable() == false) continue;
514 TypeOfType type = mem->getTypeData().getType();
515 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
516 {
517 if (dObj.exists(mem->getName())) mem->fromString((void*)obj, dObj.get(mem->getName(), "0"));
518 if (ptrTable != nullptr)
519 {
520 assignPtrToId((char*)obj + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
521 }
522 }
523 else if (type == TypeOfType::type_class)
524 {
525 for (auto& child : dObj.getChildren())
526 {
527 if (child->name == mem->getName())
528 {
529 if (mem->getTypeData().getTypeHash() == typeid(GameObject).hash_code())
530 {
531 unserializeGameObject((GameObject&)*((char*)obj + mem->getOffset()), *child, ptrTable, weakPtrsToUpdate);
532 }
533 else unserializeClass((void*)((char*)obj + mem->getOffset()), *child, static_cast<const ClassData&>(mem->getTypeData()), ptrTable, weakPtrsToUpdate);
534 break;
535 }
536 }
537 }
538 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
539 {
540 for (auto& child : dObj.getChildren())
541 {
542 if (child->name == mem->getName())
543 {
544 unserializeArray((void*)((char*)obj + mem->getOffset()), *child, static_cast<const ArrayData&>(mem->getTypeData()), mem->getHasPtrOwnership(), ptrTable, weakPtrsToUpdate);
545 break;
546 }
547 }
548 }
549 else if (type == TypeOfType::type_ptr && mem->getHasPtrOwnership() == true)
550 {
551 bool foundType = false;
552 for (auto& child : dObj.getChildren())
553 {
554 if (child->name == mem->getName())
555 {
556 if (child->get("type_name", "") != "")
557 {
558 unserializeOwnedPtr(dObj, mem->getName(), (void*)obj, mem->getOffset(), *objTypeData.getSystem().getTypeData(child->get("type_name")), ptrTable, weakPtrsToUpdate);
559 foundType = true;
560 }
561 }
562 }
563 if (*(void**)mem->get((void*)obj) != nullptr && foundType == false)
564 unserializeOwnedPtr(dObj, mem->getName(), (void*)obj, mem->getOffset(), *static_cast<const PtrData&>(mem->getTypeData()).getDerivedTypeData(*(void**)mem->get((void*)obj)), ptrTable, weakPtrsToUpdate);
565 }
566 else if (type == TypeOfType::type_ptr)
567 {
568 if (ptrTable != nullptr)
569 {
570 assignPtrToId((char*)obj + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
571 }
572 if (weakPtrsToUpdate != nullptr)
573 {
574 void* ptrToMem = ((char*)obj + mem->getOffset());
575 INT64 val = std::stoll(dObj.get(mem->getName(), "0"), 0, 16);
576 *(void**)ptrToMem = (void*)val;
577 weakPtrsToUpdate->push_back((void**)ptrToMem);
578 }
579 }
580 }
581 callOnUnserialize((void*)obj, objTypeData, dObj);
582 return res;
583 }
584
585 Level* unserializeLvl(const DataObject& dObj, std::map<int, void*>* ptrTable, std::list<void**>* weakPtrsToUpdate)
586 {
587 const TypeData& typeData = *DreamEngine::RTTISys().getTypeData<Level>();
588 Level* lvl = (Level*)typeData.allocateObj();
589 if (lvl == nullptr) return nullptr;
590 bool res = unserializeLvl(*lvl, dObj, ptrTable, weakPtrsToUpdate);
591 if (res == false)
592 {
593 typeData.deallocateObj((void*)lvl);
594 return nullptr;
595 }
596 else return lvl;
597 }
598
599 bool unserializeLvl(Level& lvl, const DataObject& dObj, std::map<int, void*>* ptrTable, std::list<void**>* weakPtrsToUpdate)
600 {
601 assert(&lvl != nullptr);
602 ClassData& lvlTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<Level>());
603
604 if (dObj.get("type_name") != lvlTypeData.getName()) return false; //types no longer match, do not attempt unserialization
605 if (ptrTable != nullptr)
606 {
607 assignPtrToId((void*)&lvl, std::stoi(dObj.get("this__id", "-1")), *ptrTable);
608 }
609 for (auto& child : dObj.getChildren())
610 {
611 if (child->name == "GraphicEngine")
612 {
613 const ClassData& graphicEngineTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<GraphicEngine>());
614 GraphicEngine& gEngine = *GraphicEngine::GetGraphicEngine();
615 for (auto& mem : graphicEngineTypeData.getAllMemberVars())
616 if (mem->getName() == "m_ModelMap")
617 {
618 for (auto& child2 : child->getChildren())
619 {
620 if (child2->name == mem->getName())
621 {
622 for (auto& attrib : child2->getAttributes())
623 {
624 if (gEngine.GetModel(attrib.second.c_str()) == nullptr)
625 {
626 Model* model = AssetEngine::Load<Model>(attrib.second);
627 /*gEngine.LoadModel(attrib.first.c_str(), attrib.second.c_str());
628 Model* model = gEngine.GetModel(attrib.first.c_str());*/
629 if (model != nullptr) model->onUnserialize(*child2);
630 }
631 }
632 break;
633 }
634 }
635 }
636 //else if (mem->getName() == "m_globalTLoaded")
637 //{
638 // for (auto& child2 : child->getChildren())
639 // {
640 // if (child2->name == mem->getName())
641 // {
642 // for (auto& attrib : child2->getAttributes())
643 // {
644 // if (gEngine.GetTexture(attrib.first.c_str()) == nullptr)
645 // {
646 // Texture texture;
647 // texture.filename = attrib.second;
648 // LoadTextureFile(texture.filename.c_str(), "", texture.id);
649 // gEngine.AddTexture(texture);
650 // }
651 // }
652 // break;
653 // }
654 // }
655 //}
656 else if (mem->getName() == "m_LightList")
657 {
658 /*
659 std::list<Light*> * lightList = (std::list<Light*> *)((char*)&gEngine + mem->getOffset());
660 for (auto& child2 : child->getChildren())
661 {
662 if (child2->name == mem->getName())
663 {
664 std::list<DataObject*> lightDObjs;
665 for (auto& child3 : child2->getChildren())
666 {
667 if (child3->name == mem->getName())
668 {
669 lightDObjs.push_back(child3);
670 }
671 }
672 //todo: permanent implementation
673 //temporary implementation:
674 //The lighting system exists independently of the level hierachy
675 //so its impossible to unserialize the lights in a level without
676 //actively changing the current lights in the current level on screen
677 //light system should be refactored so lights are components
678
679 gEngine.DeleteAllLights();
680 lightList->resize(std::stoul(child2->get("size")));
681 auto dObjIter = lightDObjs.begin();
682 for (auto& iter : *lightList)
683 {
684 auto typeData = DreamEngine::RTTISys().getTypeData((*dObjIter)->get("type_name"));
685 if (typeData != nullptr && typeData->getType() == TypeOfType::type_class)
686 {
687 void * obj = static_cast<const ClassData&>(*typeData).allocateObj();
688 if (obj != nullptr)
689 {
690 unserializeClass(obj, **dObjIter, static_cast<const ClassData&>(*typeData));
691 iter = (Light*)obj;
692 }
693 }
694 ++dObjIter;
695 }
696 break;
697 }
698 }*/
699 }
700 else if (mem->getName() == "m_shaderMap")
701 {
702 /*std::map<SHADER_TYPE, Shader> * shaderMap = (std::map<SHADER_TYPE, Shader> *)((char*)&gEngine + mem->getOffset());
703 DataObject& shaderMapChild = gEngineChild.createChild();
704 shaderMapChild.name = mem->getName();
705 for (auto& iter : *shaderMap)
706 {
707 (iter);
708 //shaderMapChild.set(std::to_string(iter.first), iter.second.filename);
709 }*/
710 }
711 else if (mem->getName() == "m_gamma")
712 {
713 mem->fromString((void*)&gEngine, child->get(mem->getName()));
714 }
715 break;
716 }
717 }
718 for (const auto& mem : lvlTypeData.getAllMemberVars())
719 {
720 if (mem->getIsSerializable() == false) continue;
721 TypeOfType type = mem->getTypeData().getType();
722 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
723 {
724 if (dObj.exists(mem->getName())) mem->fromString((void*)&lvl, dObj.get(mem->getName()));
725 if (ptrTable != nullptr)
726 {
727 assignPtrToId((char*)&lvl + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
728 }
729 }
730 else if (type == TypeOfType::type_class)
731 {
732 if (mem->getName() == "root")
733 {
734 for (auto& child : dObj.getChildren())
735 {
736 if (child->name == mem->getName())
737 {
738 setLevelPtr(lvl, *(GameObject*)((char*)&lvl + mem->getOffset()));
739 unserializeGameObject(*(GameObject*)((char*)&lvl + mem->getOffset()), *child, ptrTable, weakPtrsToUpdate);
740 break;
741 }
742 }
743 }
744 else
745 {
746 for (auto& child : dObj.getChildren())
747 {
748 if (child->name == mem->getName())
749 {
750 unserializeClass((void*)((char*)&lvl + mem->getOffset()), *child, static_cast<const ClassData&>(mem->getTypeData()), ptrTable, weakPtrsToUpdate);
751 break;
752 }
753 }
754 }
755 }
756 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
757 {
758 if (mem->getName() == "levelPath")
759 {
760 mem->fromString((void*)&lvl, dObj.get(mem->getName()));
761 if (ptrTable != nullptr)
762 {
763 assignPtrToId((char*)&lvl + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
764 }
765 continue;
766 }
767 for (auto& child : dObj.getChildren())
768 {
769 if (child->name == mem->getName())
770 {
771 unserializeArray((void*)((char*)&lvl + mem->getOffset()), *child, static_cast<const ArrayData&>(mem->getTypeData()), mem->getHasPtrOwnership(), ptrTable, weakPtrsToUpdate);
772 break;
773 }
774 }
775 }
776 else if (type == TypeOfType::type_ptr && mem->getHasPtrOwnership() == true)
777 {
778 bool foundType = false;
779 for (auto& child : dObj.getChildren())
780 {
781 if (child->name == mem->getName())
782 {
783 if (child->get("type_name", "") != "")
784 {
785 unserializeOwnedPtr(dObj, mem->getName(), (void*)&lvl, mem->getOffset(), *lvlTypeData.getSystem().getTypeData(child->get("type_name")), ptrTable, weakPtrsToUpdate);
786 foundType = true;
787 }
788 }
789 }
790 if (*(void**)mem->get((void*)&lvl) != nullptr && foundType == false)
791 unserializeOwnedPtr(dObj, mem->getName(), (void*)&lvl, mem->getOffset(), *static_cast<const PtrData&>(mem->getTypeData()).getDerivedTypeData(*(void**)mem->get((void*)&lvl)), ptrTable, weakPtrsToUpdate);
792 }
793 else if (type == TypeOfType::type_ptr)
794 {
795 if (ptrTable != nullptr)
796 {
797 assignPtrToId((char*)&lvl + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
798 }
799 if (weakPtrsToUpdate != nullptr)
800 {
801 void* ptrToMem = ((char*)&lvl + mem->getOffset());
802 INT64 val = std::stoll(dObj.get(mem->getName(), "0"), 0, 16);
803 *(void**)ptrToMem = (void*)val;
804 weakPtrsToUpdate->push_back((void**)ptrToMem);
805 }
806 }
807
808 }
809 callOnUnserialize((void*)&lvl, lvlTypeData, dObj);
810 return true;
811 }
812
813 bool serializeLvl(const Level& lvl, DataObject& dObj, std::map<void*, int>* ptrTable)
814 {
815 assert(&lvl != nullptr);
816 bool res = true;
817 ClassData& lvlTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<Level>());
818 dObj.name = lvl.GetName();
819 dObj.set("hash_code", std::to_string(lvlTypeData.getTypeHash()));
820 dObj.set("type_name", lvlTypeData.getName());
821 callOnPreserialize((void*)&lvl, lvlTypeData, dObj);
822 if (ptrTable != nullptr)
823 {
824 dObj.set("this_id", std::to_string(assignIDToPtr((void*)&lvl, *ptrTable)));
825 }
826 for (const auto& mem : lvlTypeData.getAllMemberVars())
827 {
828 if (mem->getName() == "levelPath")
829 {
830 dObj.set("levelPath", mem->toString((void*)&lvl));
831 if (ptrTable != nullptr)
832 {
833 dObj.set("levelPath_id", std::to_string(assignIDToPtr((char*)&lvl + mem->getOffset(), *ptrTable)));
834 }
835 }
836 else if (mem->getName() == "root")
837 {
838 DataObject& child = dObj.createChild();
839 child.name = mem->getName();
840 const GameObject& obj = mem->get<GameObject>((void*)&lvl);
841 if (serializeGameObject(obj, child, ptrTable) == false) res = false;
842 }
843 else
844 {
845 if (mem->getIsSerializable() == false) continue;
846 TypeOfType type = mem->getTypeData().getType();
847 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
848 {
849 dObj.set(mem->getName(), mem->toString((void*)&lvl));
850 if (ptrTable != nullptr)
851 {
852 dObj.set(mem->getName() + "_id", std::to_string(assignIDToPtr((char*)&lvl + mem->getOffset(), *ptrTable)));
853 }
854 }
855 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
856 {
857 const ArrayData& arrayData = static_cast<const ArrayData&>(mem->getTypeData());
858 DataObject& child = dObj.createChild();
859 child.name = mem->getName();
860 res = serializeArray((void*)((char*)&lvl + mem->getOffset()), child, arrayData, mem->getHasPtrOwnership(), ptrTable);
861 }
862 else if (type == TypeOfType::type_class)
863 {
864 DataObject& child = dObj.createChild();
865 child.name = mem->getName();
866 res = serializeClass((void*)((char*)&lvl + mem->getOffset()), dObj, static_cast<const ClassData&>(mem->getTypeData()), ptrTable);
867 }
868 else if (type == TypeOfType::type_ptr)
869 {
870 if (mem->getHasPtrOwnership() == true && (void*)((char*)&lvl + mem->getOffset()) != nullptr)
871 {
872 serializeOwnedPtr(dObj, mem->getName(), (void*)&lvl, mem->getOffset(), *static_cast<const PtrData&>(mem->getTypeData()).getDerivedTypeData(*(void**)mem->get((void*)&lvl)), ptrTable);
873 }
874 else if (ptrTable != nullptr)
875 {
876 dObj.set(mem->getName(), mem->toString((void*)&lvl));
877 dObj.set(mem->getName() + "_id", std::to_string(assignIDToPtr((char*)&lvl + mem->getOffset(), *ptrTable)));
878 }
879 }
880 }
881 }
882 DataObject& gEngineChild = dObj.createChild();
883 gEngineChild.name = "GraphicEngine";
884 const ClassData& graphicEngineTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData<GraphicEngine>());
885 const GraphicEngine& gEngine = *GraphicEngine::GetGraphicEngine();
886 for (auto& mem : graphicEngineTypeData.getAllMemberVars())
887 {
888 if (mem->getName() == "m_ModelMap")
889 {
890 std::map<std::string, Model*>* modelMap = (std::map<std::string, Model*>*)((char*)&gEngine + mem->getOffset());
891 DataObject& modelMapChild = gEngineChild.createChild();
892 modelMapChild.name = mem->getName();
893 size_t ctr = 0;
894 for (auto& iter : *modelMap)
895 {
896 modelMapChild.set(std::to_string(ctr), iter.second->GetModelFilename());
897 iter.second->onSerialize(modelMapChild);
898 ++ctr;
899 }
900 }
901 else if (mem->getName() == "m_globalTLoaded")
902 {
903 //std::map<std::string, Texture>* textureMap = (std::map<std::string, Texture>*)((char*)&gEngine + mem->getOffset());
904 //DataObject& textureMapChild = gEngineChild.createChild();
905 //textureMapChild.name = mem->getName();
906 //for (auto& iter : *textureMap)
907 //{
908 // textureMapChild.set(iter.first, iter.second.GetFilePath());
909 //}
910 }
911 else if (mem->getName() == "m_LightList")
912 {
913 /*std::list<Light*> * lightList = (std::list<Light*> *)((char*)&gEngine + mem->getOffset());
914 DataObject& lightListChild = gEngineChild.createChild();
915 lightListChild.name = mem->getName();
916 size_t i = 0;
917 lightListChild.set("size", std::to_string(lightList->size()));
918 for (auto& iter : *lightList)
919 {
920 DataObject& lightChild = lightListChild.createChild();
921 lightChild.name = mem->getName();
922 lightChild.set("index", std::to_string(i));
923 serializeClass(iter, lightChild, static_cast<const ClassData&>(*DreamEngine::RTTISys().getTypeData(typeid(*iter))));
924 ++i;
925 }*/
926 }
927 else if (mem->getName() == "m_shaderMap")
928 {
929 std::map<SHADER_TYPE, Shader> * shaderMap = (std::map<SHADER_TYPE, Shader> *)((char*)&gEngine + mem->getOffset());
930 DataObject& shaderMapChild = gEngineChild.createChild();
931 shaderMapChild.name = mem->getName();
932 for (auto& iter : *shaderMap)
933 {
934 //todo: serializing shaders?
935 //proper shader loading pipeline is not really in place yet anyways
936 (iter);
937 //shaderMapChild.set(std::to_string(iter.first), iter.second.filename);
938 }
939 }
940 else if (mem->getName() == "m_gamma")
941 {
942 gEngineChild.set(mem->getName(), std::to_string(mem->get<float>((void*)&gEngine)));
943 }
944 }
945 callOnSerialize((void*)&lvl, lvlTypeData, dObj);
946 return res;
947 }
948
949 //todo: test
950 //todo: implement callbacks for the various classes
951 //todo: unserialize graphic engine, mostly done
952 //todo: serialize graphic engine, done
953 //todo: set gameobject ptr for components, done
954 //todo: set currentLvl ptr, done
955 //todo: onSerialize, onUnserialize callback fns, done
956 bool unserializeGameObject(GameObject& gObj, const DataObject& dObj, std::map<int, void*>* ptrTable, std::list<void**>* weakPtrsToUpdate)
957 {
958 /*NOTE:
959 Calling unserialize on an existing 'initialized' game object
960 can result in losing pointers to existing components and child gameobjects!
961 see todos below.
962 */
963 assert(&gObj != nullptr);
964
965 bool res = true;
966 const ClassData& baseTypeData = static_cast<const ClassData&>(*DreamEngine::RTTISys().getTypeData<GameObject>());
967 ClassData& gameObjTypeData = static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData(dObj.get("type_name", "class GameObject")));
968 void* obj = (void*)&gObj;
969 for (auto& i : gameObjTypeData.getInheritances())
970 {
971 if (i.className == baseTypeData.getName())
972 {
973 obj = i.getDerivedPtrFromBase(obj);
974 break;
975 }
976 }
977 if (ptrTable != nullptr)
978 {
979 assignPtrToId((void*)&gObj, std::stoi(dObj.get("this_id", "-1")), *ptrTable);
980 }
981 for (const auto& mem : gameObjTypeData.getAllMemberVars())
982 {
983 if (mem->getName() == "name")
984 {
985 mem->fromString((void*)obj, dObj.get(mem->getName(), ""));
986 if (ptrTable != nullptr)
987 {
988 assignPtrToId((char*)&gObj + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
989 }
990 }
991 else if (mem->getName() == "components")
992 {
993 if (ptrTable != nullptr)
994 {
995 assignPtrToId((char*)&gObj + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
996 }
997 std::list<Component*>& components = mem->get<std::list<Component*>>((void*)obj);
998 std::list<DataObject*> componentsDObjs;
999 for (auto& child : dObj.getChildren())
1000 {
1001 if (child->name == mem->getName())
1002 {
1003 for (auto& child2 : child->getChildren())
1004 {
1005 componentsDObjs.push_back(child2);
1006 }
1007 break;
1008 }
1009 }
1010 if (componentsDObjs.size() <= 0) continue;
1011 static_cast<const ArrayData&>(mem->getTypeData()).resize((void*)((char*)obj + mem->getOffset()), componentsDObjs.size());
1012
1013 auto iter = components.begin();
1014 for (auto& child1 : componentsDObjs)
1015 {
1016 DataObject* child = child1;
1017 if (child->exists("type_name") == false) child = child->getChildren()[0];
1018 TypeData* typeData = nullptr;
1019 typeData = gameObjTypeData.getRTTISystem().getTypeData(child->get("type_name"));
1020 if (typeData == nullptr) gameObjTypeData.getRTTISystem().getTypeData((size_t)std::stoul(child->get("hash_code")));
1021 if (typeData != nullptr)
1022 {
1023 void* cmp = *iter;
1024 if (*iter == nullptr || typeid(**iter).hash_code() != typeData->getTypeHash())
1025 cmp = static_cast<ClassData*>(typeData)->allocateObj();
1026 else
1027 {
1028 //TODO: delete existing component of different type
1029 }
1030 if (cmp != nullptr)
1031 {
1032 setGameObjectPtr(gObj, *(Component*)cmp);
1033 unserializeClass(cmp, *child, *static_cast<ClassData*>(typeData), ptrTable, weakPtrsToUpdate);
1034 *iter = (Component*)cmp;
1035 }
1036 else *iter = nullptr;
1037 }
1038 ++iter;
1039 }
1040 }
1041 else if (mem->getName() == "childrens" || mem->getName() == "children")
1042 {
1043 if (ptrTable != nullptr)
1044 {
1045 assignPtrToId((char*)&gObj + mem->getOffset(), std::stoi(dObj.get("childrens_id", "-1")), *ptrTable);
1046 }
1047 std::list<GameObject*>& children = mem->get<std::list<GameObject*>>((void*)obj);
1048 std::list<DataObject*> childrenDObjs;
1049 for (auto& child : dObj.getChildren())
1050 {
1051 if (child->name == mem->getName())
1052 {
1053 for (auto& child2 : child->getChildren())
1054 {
1055 childrenDObjs.push_back(child2);
1056 }
1057 break;
1058 }
1059 }
1060 if (childrenDObjs.size() <= 0) continue;
1061 static_cast<const ArrayData&>(mem->getTypeData()).resize((void*)((char*)obj + mem->getOffset()), childrenDObjs.size());
1062
1063 auto iter = children.begin();
1064 for (auto& child : childrenDObjs)
1065 {
1066 TypeData* typeData = nullptr;
1067 typeData = gameObjTypeData.getRTTISystem().getTypeData(child->get("type_name"));
1068 if (typeData == nullptr) gameObjTypeData.getRTTISystem().getTypeData((size_t)std::stoul(child->get("hash_code")));
1069 if (typeData != nullptr)
1070 {
1071 void* newObj = *iter;
1072 if (*iter == nullptr || typeid(**iter).hash_code() != typeData->getTypeHash())
1073 newObj = static_cast<ClassData*>(typeData)->allocateObj();
1074 else
1075 {
1076 //TODO: delete existing gameobject of different type
1077 }
1078 if (newObj != nullptr)
1079 {
1080 for (auto& i : static_cast<const ClassData&>(*typeData).getInheritances())
1081 {
1082 if (i.className == baseTypeData.getName())
1083 {
1084 newObj = i.getBasePtrFromDerived(newObj);
1085 break;
1086 }
1087 }
1088 GameObject* newGObj = (GameObject*)newObj;
1089 copyLevelAndParentPtr(gObj, *newGObj);
1090 unserializeGameObject(*newGObj, *child, ptrTable, weakPtrsToUpdate);
1091 *iter = newGObj;
1092 }
1093 else *iter = nullptr;
1094 }
1095 ++iter;
1096 }
1097 }
1098
1099 else
1100 {
1101 if (mem->getIsSerializable() == false) continue;
1102 TypeOfType type = mem->getTypeData().getType();
1103 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
1104 {
1105 if (dObj.exists(mem->getName())) mem->fromString((void*)obj, dObj.get(mem->getName(), "0"));
1106 if (ptrTable != nullptr)
1107 {
1108 assignPtrToId((char*)&obj + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
1109 }
1110 }
1111 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
1112 {
1113 for (auto& child : dObj.getChildren())
1114 {
1115 if (child->name == mem->getName())
1116 {
1117 res = unserializeArray((void*)((char*)obj + mem->getOffset()), *child, static_cast<const ArrayData&>(mem->getTypeData()), mem->getHasPtrOwnership(), ptrTable, weakPtrsToUpdate);
1118 break;
1119 }
1120 }
1121 }
1122 else if (type == TypeOfType::type_class)
1123 {
1124 for (auto& child : dObj.getChildren())
1125 {
1126 if (child->name == mem->getName())
1127 {
1128 res = unserializeClass((void*)((char*)obj + mem->getOffset()), *child, static_cast<const ClassData&>(mem->getTypeData()), ptrTable, weakPtrsToUpdate);
1129 break;
1130 }
1131 }
1132 }
1133 else if (type == TypeOfType::type_ptr && mem->getHasPtrOwnership() == true)
1134 {
1135 bool foundType = false;
1136 for (auto& child : dObj.getChildren())
1137 {
1138 if (child->name == mem->getName())
1139 {
1140 if (child->get("type_name", "") != "")
1141 {
1142 unserializeOwnedPtr(dObj, mem->getName(), (void*)obj, mem->getOffset(), *gameObjTypeData.getSystem().getTypeData(child->get("type_name")), ptrTable, weakPtrsToUpdate);
1143 foundType = true;
1144 }
1145 }
1146 }
1147 if (*(void**)mem->get((void*)obj) != nullptr && foundType == false)
1148 unserializeOwnedPtr(dObj, mem->getName(), (void*)obj, mem->getOffset(), *static_cast<const PtrData&>(mem->getTypeData()).getDerivedTypeData(*(void**)mem->get((void*)obj)), ptrTable, weakPtrsToUpdate);
1149 }
1150 else if (type == TypeOfType::type_ptr)
1151 {
1152 if (ptrTable != nullptr)
1153 {
1154 assignPtrToId((char*)&gObj + mem->getOffset(), std::stoi(dObj.get(mem->getName() + "_id", "-1")), *ptrTable);
1155 }
1156 if (weakPtrsToUpdate != nullptr)
1157 {
1158 void* ptrToMem = ((char*)obj + mem->getOffset());
1159 INT64 val = std::stoll(dObj.get(mem->getName(), "0"), 0, 16);
1160 *(void**)ptrToMem = (void*)val;
1161 weakPtrsToUpdate->push_back((void**)ptrToMem);
1162 }
1163 }
1164 }
1165 }
1166 callOnUnserialize((void*)obj, gameObjTypeData, dObj);
1167 return res;
1168 }
1169
1170 bool serializeGameObject(const GameObject& gObj, DataObject& dObj, std::map<void*, int>* ptrTable)
1171 {
1172 assert(&gObj != nullptr);
1173 void* obj = (void*)&gObj;
1174 bool res = true;
1175 const PtrData& basePtrData = static_cast<PtrData&>(*DreamEngine::RTTISys().getTypeData<GameObject*>());
1176 const ClassData& baseTypeData = static_cast<const ClassData&>(*DreamEngine::RTTISys().getTypeData<GameObject>());
1177 const ClassData& gameObjTypeData = static_cast<const ClassData&>(*basePtrData.getDerivedTypeData((void*)&gObj));
1178 for (auto& i : gameObjTypeData.getInheritances())
1179 {
1180 if (i.className == baseTypeData.getName())
1181 {
1182 obj = i.getDerivedPtrFromBase(obj);
1183 break;
1184 }
1185 }
1186
1187 dObj.set("hash_code", std::to_string(gameObjTypeData.getTypeHash()));
1188 dObj.set("type_name", gameObjTypeData.getName());
1189 callOnPreserialize((void*)obj, gameObjTypeData, dObj);
1190 if (ptrTable != nullptr)
1191 {
1192 dObj.set("this_id", std::to_string(assignIDToPtr((void*)obj, *ptrTable)));
1193 }
1194 for (const auto& mem : gameObjTypeData.getAllMemberVars())
1195 {
1196 //void* ptr = mem->getParent().getde
1197 if (mem->getName() == "name")
1198 {
1199 dObj.set("name", mem->toString((void*)obj));
1200 if (ptrTable != nullptr)
1201 {
1202 dObj.set("name_id", std::to_string(assignIDToPtr((char*)obj + mem->getOffset(), *ptrTable)));
1203 }
1204 }
1205 else if (mem->getName() == "components")
1206 {
1207 const std::list<Component*>& components = mem->get<std::list<Component*>>((void*)obj);
1208 size_t i = 0;
1209 DataObject& componentChild = dObj.createChild();
1210 componentChild.name = mem->getName();
1211 componentChild.set("hash_code", std::to_string(mem->getTypeData().getTypeHash()));
1212 componentChild.set("type_name", mem->getTypeData().getName());
1213 if (ptrTable != nullptr)
1214 {
1215 dObj.set("components_id", std::to_string(assignIDToPtr((char*)obj + mem->getOffset(), *ptrTable)));
1216 }
1217 for (const auto& comp : components)
1218 {
1219 DataObject& child = componentChild.createChild();
1220 child.name = mem->getName();
1221 child.set("index", std::to_string(i));
1222 if (comp == nullptr) continue;
1223 if (serializeClass((void*)comp, child, static_cast<ClassData&>(*DreamEngine::RTTISys().getTypeData(typeid(*comp))), ptrTable) == false) res = false;
1224 ++i;
1225 }
1226 }
1227 else if (mem->getName() == "childrens" || mem->getName() == "children")
1228 {
1229 const std::list<GameObject*>& children = mem->get<std::list<GameObject*>>((void*)obj);
1230 size_t i = 0;
1231 DataObject& childrenChild = dObj.createChild();
1232 childrenChild.name = mem->getName();
1233 childrenChild.set("hash_code", std::to_string(mem->getTypeData().getTypeHash()));
1234 childrenChild.set("type_name", mem->getTypeData().getName());
1235 if (ptrTable != nullptr)
1236 {
1237 dObj.set("childrens_id", std::to_string(assignIDToPtr((char*)obj + mem->getOffset(), *ptrTable)));
1238 }
1239 for (const auto& childObj : children)
1240 {
1241 DataObject& child = childrenChild.createChild();
1242 if (childObj == nullptr) continue;
1243 child.name = mem->getName();
1244 child.set("index", std::to_string(i));
1245 if (serializeGameObject(*childObj, child, ptrTable) == false) res = false;
1246 ++i;
1247 }
1248 }
1249
1250 else
1251 {
1252 if (mem->getIsSerializable() == false) continue;
1253 TypeOfType type = mem->getTypeData().getType();
1254 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
1255 {
1256 dObj.set(mem->getName(), mem->toString((void*)obj));
1257 if (ptrTable != nullptr)
1258 {
1259 dObj.set(mem->getName() + "_id", std::to_string(assignIDToPtr((char*)obj + mem->getOffset(), *ptrTable)));
1260 }
1261 }
1262 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
1263 {
1264 const ArrayData& arrayData = static_cast<const ArrayData&>(mem->getTypeData());
1265 DataObject& child = dObj.createChild();
1266 child.name = mem->getName();
1267 res = serializeArray((void*)((char*)obj + mem->getOffset()), child, arrayData, mem->getHasPtrOwnership(), ptrTable);
1268 }
1269 else if (type == TypeOfType::type_ptr)
1270 {
1271 if (mem->getHasPtrOwnership() == true && (void*)((char*)obj + mem->getOffset()) != nullptr)
1272 {
1273 serializeOwnedPtr(dObj, mem->getName(), (void*)obj, mem->getOffset(), *static_cast<const PtrData&>(mem->getTypeData()).getDerivedTypeData(*(void**)mem->get((void*)obj)), ptrTable);
1274 }
1275 else if (ptrTable != nullptr)
1276 {
1277 dObj.set(mem->getName(), mem->toString(obj));
1278 dObj.set(mem->getName() + "_id", std::to_string(assignIDToPtr((char*)obj + mem->getOffset(), *ptrTable)));
1279 }
1280 }
1281 else if (type == TypeOfType::type_class)
1282 {
1283 DataObject& child = dObj.createChild();
1284 child.name = mem->getName();
1285 res = serializeClass((void*)((char*)obj + mem->getOffset()), child, static_cast<const ClassData&>(mem->getTypeData()), ptrTable);
1286 }
1287 }
1288 }
1289 callOnSerialize((void*)obj, gameObjTypeData, dObj);
1290 return res;
1291 }
1292
1293 bool serializeClass(void* obj, DataObject& dObj, const ClassData& classData, std::map<void*, int>* ptrTable)
1294 {
1295 assert(obj != nullptr);
1296 assert(&classData != nullptr);
1297 bool res = true;
1298 dObj.set("hash_code", std::to_string(classData.getTypeHash()));
1299 dObj.set("type_name", classData.getName());
1300 callOnPreserialize((void*)obj, classData, dObj);
1301 if (ptrTable != nullptr)
1302 {
1303 dObj.set("this_id", std::to_string(assignIDToPtr((void*)obj, *ptrTable)));
1304 }
1305 for (const auto& member : classData.getAllMemberVars())
1306 {
1307 if (member->getIsSerializable() == false) continue;
1308 const TypeData& memberTypeData = member->getTypeData();
1309 TypeOfType type = memberTypeData.getType();
1310 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
1311 {
1312 dObj.set(member->getName(), member->toString(obj));
1313 if (ptrTable != nullptr)
1314 {
1315 dObj.set(member->getName() + "_id", std::to_string(assignIDToPtr((char*)obj + member->getOffset(), *ptrTable)));
1316 }
1317 }
1318 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
1319 {
1320 const ArrayData& arrayData = static_cast<const ArrayData&>(memberTypeData);
1321 DataObject& child = dObj.createChild();
1322 child.name = member->getName();
1323 res = serializeArray((void*)((char*)obj + member->getOffset()), child, arrayData, member->getHasPtrOwnership(), ptrTable);
1324 }
1325 else if (type == TypeOfType::type_class)
1326 {
1327 //todo: handles classes that inherit from gameobject
1328 if (memberTypeData.getTypeHash() == typeid(GameObject).hash_code())
1329 {
1330 DataObject& child = dObj.createChild();
1331 child.name = member->getName();
1332 res = serializeGameObject(*(GameObject*)((char*)obj + member->getOffset()), child, ptrTable);
1333 }
1334 else
1335 {
1336 DataObject& child = dObj.createChild();
1337 child.name = member->getName();
1338 res = serializeClass((void*)((char*)obj + member->getOffset()), child, static_cast<const ClassData&>(memberTypeData), ptrTable);
1339 }
1340 }
1341 else if (type == TypeOfType::type_ptr)
1342 {
1343 if (member->getHasPtrOwnership() == true && *(void**)((char*)obj + member->getOffset()) != nullptr)
1344 {
1345 void** memberObj = (void**)((char*)obj + member->getOffset());
1346 serializeOwnedPtr(dObj, member->getName(), (void*)obj, member->getOffset(), *static_cast<const PtrData&>(member->getTypeData()).getDerivedTypeData(*memberObj), ptrTable);
1347 }
1348 else if (ptrTable != nullptr)
1349 {
1350 dObj.set(member->getName(), member->toString(obj));
1351 dObj.set(member->getName() + "_id", std::to_string(assignIDToPtr((char*)obj + member->getOffset(), *ptrTable)));
1352 }
1353 }
1354 }
1355 callOnSerialize((void*)obj, classData, dObj);
1356 return res;
1357 }
1358
1359 bool unserializeArray(void* obj, const DataObject& dObj, const ArrayData& arrayData, bool ownPtrs, std::map<int, void*>* ptrTable, std::list<void**>* weakPtrsToUpdate)
1360 {
1361 assert(obj != nullptr);
1362 assert(&arrayData != nullptr);
1363 if (dObj.get("type_name") != arrayData.getName()) return false; //types no longer match, do not attempt unserialization
1364 bool res = true;
1365 const TypeData* elemTypeData = &arrayData.getElemTypeData();
1366 TypeOfType elemType = elemTypeData->getType();
1367 if (ptrTable != nullptr)
1368 {
1369 assignPtrToId(obj, std::stoi(dObj.get("this_id", "-1")), *ptrTable);
1370 }
1371 while (elemType == TypeOfType::type_iterable_array || elemType == TypeOfType::type_iterable_class)
1372 {
1373 //find root type
1374 elemTypeData = &(static_cast<const ArrayData&>(*elemTypeData).getElemTypeData());
1375 elemType = elemTypeData->getType();
1376 }
1377 if (elemType == TypeOfType::type_base || elemType == TypeOfType::type_enum)
1378 {
1379 size_t sz = std::stoul(dObj.get("size"));
1380 arrayData.resize(obj, sz);
1381 arrayData.fromString(obj, dObj.get("value"));
1382 if (ptrTable != nullptr)
1383 {
1384 for (size_t i = 0; i < sz; ++i)
1385 {
1386 assignPtrToId(arrayData.getElemPtr(obj, i), std::stoi(dObj.get(std::to_string(i) + "_id", "-1")), *ptrTable);
1387 }
1388 }
1389 }
1390 else
1391 {
1392 elemTypeData = &arrayData.getElemTypeData();
1393 elemType = elemTypeData->getType();
1394 auto& children = dObj.getChildren();
1395 arrayData.resize(obj, children.size());
1396 for (size_t i = 0; i < children.size(); ++i)
1397 {
1398 if (elemType == TypeOfType::type_iterable_array || elemType == TypeOfType::type_iterable_class)
1399 {
1400 res = unserializeArray(arrayData.getElemPtr(obj, i), *(children[i]), static_cast<const ArrayData&>(*elemTypeData), ownPtrs, ptrTable, weakPtrsToUpdate);
1401 }
1402 else if (elemType == TypeOfType::type_class)
1403 {
1404 res = unserializeClass(arrayData.getElemPtr(obj, i), *(children[i]), static_cast<const ClassData&>(*elemTypeData), ptrTable, weakPtrsToUpdate);
1405 }
1406 else if (elemType == TypeOfType::type_ptr && ownPtrs == true)
1407 {
1408
1409 //res = unserializeOwnedPtr(*(children[i]), (children[i])->name, arrayData.getElemPtr(obj, i), 0, *static_cast<const PtrData&>(*elemTypeData).getDerivedTypeData(*(void**)arrayData.getElemPtr(obj, i)), ptrTable, weakPtrsToUpdate);
1410 std::string typeName = children[i]->get("type_name");
1411 if (typeName.empty() && children[i]->getChildren().size() > 0) typeName = children[i]->getChildren()[0]->get("type_name");
1412 if(typeName.empty() == false) res = unserializeOwnedPtr(*(children[i]), (children[i])->name, arrayData.getElemPtr(obj, i), 0, *elemTypeData->getSystem().getTypeData(typeName), ptrTable, weakPtrsToUpdate);
1413 else res = false;
1414 }
1415 else if (elemType == TypeOfType::type_ptr)
1416 {
1417 if (ptrTable != nullptr) assignPtrToId(arrayData.getElemPtr(obj, i), std::stoi(dObj.get(std::to_string(i) + "_id", "-1")), *ptrTable);
1418 if (weakPtrsToUpdate != nullptr)
1419 {
1420 void* ptrToMem = arrayData.getElemPtr(obj, i);
1421 long long val = std::stoll(children[i]->get(std::to_string(i), "0"), 0, 16);
1422 *(void**)ptrToMem = (void*)val;
1423 weakPtrsToUpdate->push_back((void**)arrayData.getElemPtr(obj, i));
1424 }
1425 }
1426 }
1427 }
1428 return res;
1429 }
1430
1431 bool serializeArray(void* obj, DataObject& dObj, const ArrayData& arrayData, bool ownsPtrs, std::map<void*, int>* ptrTable)
1432 {
1433 assert(obj != nullptr);
1434 assert(&arrayData != nullptr);
1435 bool res = true;
1436 const TypeData* elemTypeData = &arrayData.getElemTypeData();
1437 TypeOfType elemType = elemTypeData->getType();
1438 dObj.set("hash_code", std::to_string(arrayData.getTypeHash()));
1439 dObj.set("type_name", arrayData.getName());
1440 if (ptrTable != nullptr)
1441 {
1442 dObj.set("this_id", std::to_string(assignIDToPtr((void*)obj, *ptrTable)));
1443 }
1444 while (elemType == TypeOfType::type_iterable_array || elemType == TypeOfType::type_iterable_class)
1445 {
1446 //find root type
1447 elemTypeData = &(static_cast<const ArrayData&>(*elemTypeData).getElemTypeData());
1448 elemType = elemTypeData->getType();
1449 }
1450 if (elemType == TypeOfType::type_base || elemType == TypeOfType::type_enum)
1451 {
1452 dObj.set("value", arrayData.toString(obj));
1453 dObj.set("size", std::to_string(arrayData.size(obj)));
1454 if (ptrTable != nullptr)
1455 {
1456 size_t sz = arrayData.size(obj);
1457 for (size_t i = 0; i < sz; ++i)
1458 {
1459 const void * address = static_cast<const void*>(arrayData.getElemPtr(obj, i));
1460 std::stringstream ss;
1461 ss << address;
1462 dObj.set(std::to_string(i), ss.str());
1463 dObj.set(std::to_string(i) + "_id", std::to_string(assignIDToPtr(arrayData.getElemPtr(obj, i), *ptrTable)));
1464 }
1465 }
1466
1467 }
1468 else
1469 {
1470 elemTypeData = &arrayData.getElemTypeData();
1471 elemType = elemTypeData->getType();
1472 if (elemType == TypeOfType::type_iterable_array || elemType == TypeOfType::type_iterable_class)
1473 {
1474 size_t size = arrayData.size(obj);
1475 for (size_t i = 0; i < size; ++i)
1476 {
1477 DataObject& child = dObj.createChild();
1478 child.name = dObj.name;
1479 child.set("index", std::to_string(i));
1480 res = serializeArray(arrayData.getElemPtr(obj, i), child, static_cast<const ArrayData&>(*elemTypeData), ownsPtrs, ptrTable);
1481 }
1482 }
1483 else if (elemType == TypeOfType::type_class)
1484 {
1485 size_t size = arrayData.size(obj);
1486 for (size_t i = 0; i < size; ++i)
1487 {
1488 DataObject& child = dObj.createChild();
1489 child.name = dObj.name;
1490 child.set("index", std::to_string(i));
1491 res = serializeClass(arrayData.getElemPtr(obj, i), child, static_cast<const ClassData&>(*elemTypeData), ptrTable);
1492 }
1493 }
1494 else if (elemType == TypeOfType::type_ptr && ownsPtrs == true)
1495 {
1496 size_t size = arrayData.size(obj);
1497 for (size_t i = 0; i < size; ++i)
1498 {
1499 DataObject& child = dObj.createChild();
1500 child.name = dObj.name;
1501 child.set("index", std::to_string(i));
1502 res = serializeOwnedPtr(child, child.name, arrayData.getElemPtr(obj, i), 0, *static_cast<const PtrData&>(*elemTypeData).getDerivedTypeData(*(void**)arrayData.getElemPtr(obj, i)), ptrTable);
1503 }
1504 }
1505 else if (elemType == TypeOfType::type_ptr && ownsPtrs == false)
1506 {
1507 if (ptrTable != nullptr)
1508 {
1509 size_t size = arrayData.size(obj);
1510 for (size_t i = 0; i < size; ++i)
1511 {
1512 DataObject& child = dObj.createChild();
1513 const void * address = static_cast<const void*>(*(void**)arrayData.getElemPtr(obj, i));
1514 std::stringstream ss;
1515 ss << address;
1516 child.name = std::to_string(i);
1517 child.set(std::to_string(i), ss.str());
1518 child.set(std::to_string(i) + "_id", std::to_string(assignIDToPtr((void*)address, *ptrTable)));
1519 }
1520 }
1521 }
1522 }
1523 return res;
1524 }
1525
1526 /*bool serializeVar(void* ptr, const std::string& name, DataObject& dObj, const TypeData& typeData, std::map<void*, int>* ptrTable)
1527 {
1528 assert(ptr != nullptr);
1529 assert(&typeData != nullptr);
1530 TypeOfType type = typeData.getType();
1531 bool res = true;
1532 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
1533 {
1534 dObj.set(name, typeData.toString(ptr));
1535 if (ptrTable != nullptr)
1536 {
1537 dObj.set(name + "_id", std::to_string(assignIDToPtr((char*)ptr, *ptrTable)));
1538 }
1539 }
1540 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
1541 {
1542 const ArrayData& arrayData = static_cast<const ArrayData&>(typeData);
1543 DataObject& child = dObj.createChild();
1544 child.name = name;
1545 res = serializeArray(ptr, child, arrayData, true, ptrTable);
1546 }
1547 else if (type == TypeOfType::type_class)
1548 {
1549 if (typeData.getTypeHash() == typeid(GameObject).hash_code())
1550 {
1551 DataObject& child = dObj.createChild();
1552 child.name = name;
1553 res = serializeGameObject(typeData.get<GameObject>(ptr), child, ptrTable);
1554 }
1555 else
1556 {
1557 DataObject& child = dObj.createChild();
1558 child.name = name;
1559 res = serializeClass(ptr, child, static_cast<const ClassData&>(typeData), ptrTable);
1560 }
1561 }
1562 else if (type == TypeOfType::type_ptr)
1563 {
1564 if (ptr != nullptr)
1565 {
1566 res = serializeOwnedPtr(dObj, name, (void*)ptr, 0, *static_cast<const PtrData&>(typeData).getDerivedTypeData(*(void**)ptr), ptrTable);
1567 }
1568 }
1569 return res;
1570 }
1571 */
1572 bool unserializeVar(void* ptr, const std::string& name, const DataObject& dObj, const TypeData& typeData, std::map<int, void*>* ptrTable, std::list<void**>* weakPtrsToUpdate)
1573 {
1574 assert(ptr != nullptr);
1575 assert(&typeData != nullptr);
1576
1577 bool res = true;
1578 TypeOfType type = typeData.getType();
1579 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
1580 {
1581 if (dObj.exists(name)) typeData.fromString(ptr, dObj.get(name));
1582 if (ptrTable != nullptr)
1583 {
1584 assignPtrToId(ptr, std::stoi(dObj.get(name + "_id", "-1")), *ptrTable);
1585 }
1586 }
1587 else if (type == TypeOfType::type_class)
1588 {
1589 for (auto& child : dObj.getChildren())
1590 {
1591 if (child->name == name)
1592 {
1593 res = unserializeClass(ptr, *child, static_cast<const ClassData&>(typeData), ptrTable, weakPtrsToUpdate);
1594 break;
1595 }
1596 }
1597 }
1598 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
1599 {
1600 for (auto& child : dObj.getChildren())
1601 {
1602 if (child->name == name)
1603 {
1604 res = unserializeArray(ptr, *child, static_cast<const ArrayData&>(typeData), true, ptrTable, weakPtrsToUpdate);
1605 break;
1606 }
1607 }
1608 }
1609 else if (type == TypeOfType::type_ptr)
1610 {
1611 res = unserializeOwnedPtr(dObj, name, ptr, 0, *static_cast<const PtrData&>(typeData).getDerivedTypeData(*(void**)ptr), ptrTable, weakPtrsToUpdate);
1612 }
1613 return res;
1614 }
1615
1616 bool serializeVar(void* ptr, const std::string& name, DataObject& dObj, const TypeData& typeData, bool ownsPtrs, std::map<void*, int>* ptrTable)
1617 {
1618 assert(ptr != nullptr);
1619 assert(&typeData != nullptr);
1620 TypeOfType type = typeData.getType();
1621 bool res = true;
1622 if (type == TypeOfType::type_base || type == TypeOfType::type_enum)
1623 {
1624 dObj.set(name, typeData.toString(ptr));
1625 if (ptrTable != nullptr)
1626 {
1627 dObj.set(name + "_id", std::to_string(assignIDToPtr((char*)ptr, *ptrTable)));
1628 }
1629 }
1630 else if (type == TypeOfType::type_iterable_array || type == TypeOfType::type_iterable_class)
1631 {
1632 const ArrayData& arrayData = static_cast<const ArrayData&>(typeData);
1633 DataObject& child = dObj.createChild();
1634 child.name = name;
1635 const TypeData* elemTypeData = &arrayData.getElemTypeData();
1636 TypeOfType elemType = elemTypeData->getType();
1637 child.set("hash_code", std::to_string(arrayData.getTypeHash()));
1638 child.set("type_name", arrayData.getName());
1639 if (ptrTable != nullptr)
1640 {
1641 child.set("this_id", std::to_string(assignIDToPtr((void*)ptr, *ptrTable)));
1642 }
1643 while (elemType == TypeOfType::type_iterable_array || elemType == TypeOfType::type_iterable_class)
1644 {
1645 //find root type for arrays of arrays of arrays...
1646 elemTypeData = &(static_cast<const ArrayData&>(*elemTypeData).getElemTypeData());
1647 elemType = elemTypeData->getType();
1648 }
1649 if (elemType == TypeOfType::type_base || elemType == TypeOfType::type_enum)
1650 {
1651 //if root type is base type, store contigously within single key/value pair
1652 child.set("value", arrayData.toString(ptr));
1653 child.set("size", std::to_string(arrayData.size(ptr)));
1654 if (ptrTable != nullptr)
1655 {
1656 size_t sz = arrayData.size(ptr);
1657 for (size_t i = 0; i < sz; ++i)
1658 {
1659 const void* addr = static_cast<const void*>(arrayData.getElemPtr(ptr, i));
1660 std::stringstream ss;
1661 ss << addr;
1662 child.set(std::to_string(i), ss.str());
1663 child.set(std::to_string(i) + "_id", std::to_string(assignIDToPtr(arrayData.getElemPtr(ptr, i), *ptrTable)));
1664 }
1665 }
1666 }
1667 else
1668 {
1669 //for owned ptrs, serialize the objects, for non-owned ptrs, add to ptr table
1670 elemTypeData = &arrayData.getElemTypeData();
1671 elemType = elemTypeData->getType();
1672 if (elemType == TypeOfType::type_ptr)
1673 {
1674 if (ownsPtrs == true)
1675 {
1676 size_t sz = arrayData.size(ptr);
1677 for (size_t i = 0; i < sz; ++i)
1678 {
1679 DataObject& thisChild = child.createChild();
1680 thisChild.name = child.name;
1681 thisChild.set("index", std::to_string(i));
1682
1683 void* base = arrayData.getElemPtr(ptr, i);
1684 const TypeData& derefTypeData = *static_cast<const PtrData&>(*elemTypeData).getDerivedTypeData(*(void**)arrayData.getElemPtr(ptr, i));
1685
1686 void* elemPtr = ((char*)base); //this is a ptr to the elemt in the container
1687 if (elemPtr == nullptr) continue;
1688 elemPtr = (*(void**)elemPtr); //perform dereference on ptr to get the actual ptr to the object
1689 if (elemPtr == nullptr) continue;
1690 bool thisRes = serializeVar(elemPtr, thisChild.name, thisChild, derefTypeData, ownsPtrs, ptrTable);
1691 if (thisRes == false) res = false;
1692 }
1693 }
1694 else
1695 {
1696 if (ptrTable != nullptr)
1697 {
1698 size_t sz = arrayData.size(ptr);
1699 for (size_t i = 0; i < sz; ++i)
1700 {
1701 DataObject& thisChild = child.createChild();
1702 const void * address = static_cast<const void*>(*(void**)arrayData.getElemPtr(ptr, i));
1703 std::stringstream ss;
1704 ss << address;
1705 thisChild.name = std::to_string(i);
1706 thisChild.set(std::to_string(i), ss.str());
1707 thisChild.set(std::to_string(i) + "_id", std::to_string(assignIDToPtr((void*)address, *ptrTable)));
1708 }
1709 }
1710 }
1711 }
1712 else
1713 {
1714 //for non base type elements, create new node for each element
1715 size_t sz = arrayData.size(ptr);
1716 for (size_t i = 0; i < sz; ++i)
1717 {
1718 DataObject& thisChild = child.createChild();
1719 thisChild.name = child.name;
1720 thisChild.set("index", std::to_string(i));
1721 bool thisRes = serializeVar(arrayData.getElemPtr(ptr, i), thisChild.name, thisChild, *elemTypeData, ownsPtrs, ptrTable);
1722 if (thisRes == false) res = false;
1723 }
1724 }
1725 }
1726 }
1727 else if (type == TypeOfType::type_ptr)
1728 {
1729 if (ptr != nullptr)
1730 {
1731 if (ownsPtrs == true)
1732 {
1733 const TypeData& derefTypeData = *static_cast<const PtrData&>(typeData).getDerivedTypeData(*(void**)ptr);
1734
1735 void* elemPtr = ((char*)elemPtr); //this is a ptr to the elemt in the container
1736 if (elemPtr == nullptr) return false;
1737 elemPtr = (*(void**)elemPtr); //perform dereference on ptr to get the actual ptr to the object
1738 if (elemPtr == nullptr) return false;
1739 bool thisRes = serializeVar(elemPtr, name, dObj, derefTypeData, ownsPtrs, ptrTable);
1740 if (thisRes == false) res = false;
1741 }
1742 else
1743 {
1744 const void * address = static_cast<const void*>(*(void**)ptr);
1745 std::stringstream ss;
1746 ss << address;
1747 dObj.name = name;
1748 dObj.set(name, ss.str());
1749 dObj.set(name + "_id", std::to_string(assignIDToPtr((void*)address, *ptrTable)));
1750 }
1751 }
1752 }
1753 else if (type == TypeOfType::type_class)
1754 {
1755 if (typeData.getTypeHash() == typeid(GameObject).hash_code())
1756 {
1757
1758 }
1759 else if (typeData.getTypeHash() == typeid(Level).hash_code())
1760 {
1761
1762 }
1763 else
1764 {
1765
1766 }
1767 }
1768 }
1769
1770
1771 /*void serializeWeakPtrs(DataObject& root, const std::list<void*>& ptrs)
1772 {
1773 DataObject& child = root.createChild();
1774 child.name = "PointerTable";
1775 size_t ctr = 0;
1776 for (auto& ptr : ptrs)
1777 {
1778 const void * address = static_cast<const void*>(ptr);
1779 std::stringstream ss;
1780 ss << address;
1781 std::string name = ss.str();
1782 child.set(std::to_string(ctr), ss.str());
1783 ++ctr;
1784 }
1785 child.set("count", std::to_string(ctr));
1786 }
1787
1788 void unserializeWeakPtrs(const DataObject& root, std::vector<void*>& ptrs)
1789 {
1790 ptrs.clear();
1791 for (auto& child : root.getChildren())
1792 {
1793 if (child->name == "PointerTable")
1794 {
1795 assert(child->exists("count"));
1796 size_t count = std::stoi(child->get("count"));
1797 ptrs.reserve(count);
1798 }
1799 }
1800 }*/
1801}