1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Serialization/BsSerializedObject.h"
4#include "Private/RTTI/BsSerializedObjectRTTI.h"
5
6namespace bs
7{
8 namespace detail
9 {
10 /** Helper class for performing SerializedObject <-> IReflectable encoding & decoding. */
11 class BS_UTILITY_EXPORT IntermediateSerializer
12 {
13 public:
14 IntermediateSerializer();
15
16 /** Encodes an IReflectable object into an intermediate representation. */
17 SPtr<SerializedObject> encode(IReflectable* object, bool shallow = false,
18 SerializationContext* context = nullptr);
19
20 /** Decodes an intermediate representation of a serialized object into the actual object. */
21 SPtr<IReflectable> decode(const SerializedObject* serializedObject,
22 SerializationContext* context = nullptr);
23
24 private:
25 struct ObjectToDecode
26 {
27 ObjectToDecode(const SPtr<IReflectable>& _object, const SerializedObject* serializedObject)
28 :object(_object), serializedObject(serializedObject)
29 { }
30
31 SPtr<IReflectable> object;
32 const SerializedObject* serializedObject;
33 bool isDecoded = false;
34 bool decodeInProgress = false; // Used for error reporting circular references
35 };
36
37 /** Decodes a single IReflectable object. */
38 void decodeEntry(const SPtr<IReflectable>& object, const SerializedObject* serializableObject);
39
40 /** Encodes a single IReflectable object. */
41 SPtr<SerializedObject> encodeEntry(IReflectable* object, bool shallow);
42
43 UnorderedMap<const SerializedObject*, ObjectToDecode> mObjectMap;
44 SerializationContext* mContext = nullptr;
45 FrameAlloc* mAlloc = nullptr;
46 };
47
48 IntermediateSerializer::IntermediateSerializer()
49 :mAlloc(&gFrameAlloc())
50 { }
51
52 SPtr<IReflectable> IntermediateSerializer::decode(const SerializedObject* serializedObject,
53 SerializationContext* context)
54 {
55 mContext = context;
56
57 mAlloc->markFrame();
58 mObjectMap.clear();
59
60 SPtr<IReflectable> output;
61 RTTITypeBase* type = IReflectable::_getRTTIfromTypeId(serializedObject->getRootTypeId());
62 if (type != nullptr)
63 {
64 output = type->newRTTIObject();
65 auto iterNewObj = mObjectMap.insert(std::make_pair(serializedObject, ObjectToDecode(output, serializedObject)));
66
67 iterNewObj.first->second.decodeInProgress = true;
68 decodeEntry(output, serializedObject);
69 iterNewObj.first->second.decodeInProgress = false;
70 iterNewObj.first->second.isDecoded = true;
71 }
72
73 // Go through the remaining objects (should be only ones with weak refs)
74 for (auto iter = mObjectMap.begin(); iter != mObjectMap.end(); ++iter)
75 {
76 ObjectToDecode& objToDecode = iter->second;
77
78 if (objToDecode.isDecoded)
79 continue;
80
81 objToDecode.decodeInProgress = true;
82 decodeEntry(objToDecode.object, objToDecode.serializedObject);
83 objToDecode.decodeInProgress = false;
84 objToDecode.isDecoded = true;
85 }
86
87 mObjectMap.clear();
88 mAlloc->clear();
89
90 return output;
91 }
92
93 SPtr<SerializedObject> IntermediateSerializer::encode(IReflectable* object, bool shallow,
94 SerializationContext* context)
95 {
96 mContext = context;
97
98 return encodeEntry(object, shallow);
99 }
100
101 void IntermediateSerializer::decodeEntry(const SPtr<IReflectable>& object, const SerializedObject* serializableObject)
102 {
103 UINT32 numSubObjects = (UINT32)serializableObject->subObjects.size();
104 if (numSubObjects == 0)
105 return;
106
107 FrameStack<RTTITypeBase*> rttiInstances;
108 for (INT32 subObjectIdx = numSubObjects - 1; subObjectIdx >= 0; subObjectIdx--)
109 {
110 const SerializedSubObject& subObject = serializableObject->subObjects[subObjectIdx];
111
112 RTTITypeBase* rtti = IReflectable::_getRTTIfromTypeId(subObject.typeId);
113 if (rtti == nullptr)
114 continue;
115
116 RTTITypeBase* rttiInstance = rtti->_clone(*mAlloc);
117 rttiInstance->onDeserializationStarted(object.get(), mContext);
118 rttiInstances.push(rttiInstance);
119
120 UINT32 numFields = rtti->getNumFields();
121 for (UINT32 fieldIdx = 0; fieldIdx < numFields; fieldIdx++)
122 {
123 RTTIField* curGenericField = rtti->getField(fieldIdx);
124
125 auto iterFindFieldData = subObject.entries.find(curGenericField->mUniqueId);
126 if (iterFindFieldData == subObject.entries.end())
127 continue;
128
129 SPtr<SerializedInstance> entryData = iterFindFieldData->second.serialized;
130 if (curGenericField->isArray())
131 {
132 SPtr<SerializedArray> arrayData = std::static_pointer_cast<SerializedArray>(entryData);
133
134 UINT32 arrayNumElems = (UINT32)arrayData->numElements;
135 curGenericField->setArraySize(rttiInstance, object.get(), arrayNumElems);
136
137 switch (curGenericField->mType)
138 {
139 case SerializableFT_ReflectablePtr:
140 {
141 RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
142
143 for (auto& arrayElem : arrayData->entries)
144 {
145 SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
146 RTTITypeBase* childRtti = nullptr;
147
148 if (arrayElemData != nullptr)
149 childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId());
150
151 if (childRtti != nullptr)
152 {
153 auto findObj = mObjectMap.find(arrayElemData.get());
154 if (findObj == mObjectMap.end())
155 {
156 SPtr<IReflectable> newObject = childRtti->newRTTIObject();
157 findObj = mObjectMap.insert(std::make_pair(arrayElemData.get(),
158 ObjectToDecode(newObject, arrayElemData.get()))).first;
159 }
160
161 ObjectToDecode& objToDecode = findObj->second;
162
163 bool needsDecoding = !curField->getInfo().flags.isSet(RTTIFieldFlag::WeakRef) && !objToDecode.isDecoded;
164 if (needsDecoding)
165 {
166 if (objToDecode.decodeInProgress)
167 {
168 LOGWRN("Detected a circular reference when decoding. Referenced object fields " \
169 "will be resolved in an undefined order (i.e. one of the objects will not " \
170 "be fully deserialized when assigned to its field). Use RTTI_Flag_WeakRef to " \
171 "get rid of this warning and tell the system which of the objects is allowed " \
172 "to be deserialized after it is assigned to its field.");
173 }
174 else
175 {
176 objToDecode.decodeInProgress = true;
177 decodeEntry(objToDecode.object, objToDecode.serializedObject);
178 objToDecode.decodeInProgress = false;
179 objToDecode.isDecoded = true;
180 }
181 }
182
183 curField->setArrayValue(rttiInstance, object.get(), arrayElem.first, objToDecode.object);
184 }
185 else
186 {
187 curField->setArrayValue(rttiInstance, object.get(), arrayElem.first, nullptr);
188 }
189 }
190 }
191 break;
192 case SerializableFT_Reflectable:
193 {
194 RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
195
196 for (auto& arrayElem : arrayData->entries)
197 {
198 SPtr<SerializedObject> arrayElemData = std::static_pointer_cast<SerializedObject>(arrayElem.second.serialized);
199 RTTITypeBase* childRtti = nullptr;
200
201 if (arrayElemData != nullptr)
202 childRtti = IReflectable::_getRTTIfromTypeId(arrayElemData->getRootTypeId());
203
204 if (childRtti != nullptr)
205 {
206 SPtr<IReflectable> newObject = childRtti->newRTTIObject();
207 decodeEntry(newObject, arrayElemData.get());
208 curField->setArrayValue(rttiInstance, object.get(), arrayElem.first, *newObject);
209 }
210 }
211 break;
212 }
213 case SerializableFT_Plain:
214 {
215 RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
216
217 for (auto& arrayElem : arrayData->entries)
218 {
219 SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(arrayElem.second.serialized);
220 if (fieldData != nullptr)
221 {
222 curField->arrayElemFromBuffer(rttiInstance, object.get(), arrayElem.first, fieldData->value);
223 }
224 }
225 }
226 break;
227 default:
228 break;
229 }
230 }
231 else
232 {
233 switch (curGenericField->mType)
234 {
235 case SerializableFT_ReflectablePtr:
236 {
237 RTTIReflectablePtrFieldBase* curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
238
239 SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
240 RTTITypeBase* childRtti = nullptr;
241
242 if (fieldObjectData != nullptr)
243 childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId());
244
245 if (childRtti != nullptr)
246 {
247 auto findObj = mObjectMap.find(fieldObjectData.get());
248 if (findObj == mObjectMap.end())
249 {
250 SPtr<IReflectable> newObject = childRtti->newRTTIObject();
251 findObj = mObjectMap.insert(std::make_pair(fieldObjectData.get(),
252 ObjectToDecode(newObject, fieldObjectData.get()))).first;
253 }
254
255 ObjectToDecode& objToDecode = findObj->second;
256
257 bool needsDecoding = !curField->getInfo().flags.isSet(RTTIFieldFlag::WeakRef) && !objToDecode.isDecoded;
258 if (needsDecoding)
259 {
260 if (objToDecode.decodeInProgress)
261 {
262 LOGWRN("Detected a circular reference when decoding. Referenced object's fields " \
263 "will be resolved in an undefined order (i.e. one of the objects will not " \
264 "be fully deserialized when assigned to its field). Use RTTI_Flag_WeakRef to " \
265 "get rid of this warning and tell the system which of the objects is allowed " \
266 "to be deserialized after it is assigned to its field.");
267 }
268 else
269 {
270 objToDecode.decodeInProgress = true;
271 decodeEntry(objToDecode.object, objToDecode.serializedObject);
272 objToDecode.decodeInProgress = false;
273 objToDecode.isDecoded = true;
274 }
275 }
276
277 curField->setValue(rttiInstance, object.get(), objToDecode.object);
278 }
279 else
280 {
281 curField->setValue(rttiInstance, object.get(), nullptr);
282 }
283 }
284 break;
285 case SerializableFT_Reflectable:
286 {
287 RTTIReflectableFieldBase* curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
288
289 SPtr<SerializedObject> fieldObjectData = std::static_pointer_cast<SerializedObject>(entryData);
290 RTTITypeBase* childRtti = nullptr;
291
292 if (fieldObjectData != nullptr)
293 childRtti = IReflectable::_getRTTIfromTypeId(fieldObjectData->getRootTypeId());
294
295 if (childRtti != nullptr)
296 {
297 SPtr<IReflectable> newObject = childRtti->newRTTIObject();
298 decodeEntry(newObject, fieldObjectData.get());
299 curField->setValue(rttiInstance, object.get(), *newObject);
300 }
301 break;
302 }
303 case SerializableFT_Plain:
304 {
305 RTTIPlainFieldBase* curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
306
307 SPtr<SerializedField> fieldData = std::static_pointer_cast<SerializedField>(entryData);
308 if (fieldData != nullptr)
309 {
310 curField->fromBuffer(rttiInstance, object.get(), fieldData->value);
311 }
312 }
313 break;
314 case SerializableFT_DataBlock:
315 {
316 RTTIManagedDataBlockFieldBase* curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
317
318 SPtr<SerializedDataBlock> fieldData = std::static_pointer_cast<SerializedDataBlock>(entryData);
319 if (fieldData != nullptr)
320 {
321 fieldData->stream->seek(fieldData->offset);
322 curField->setValue(rttiInstance, object.get(), fieldData->stream, fieldData->size);
323 }
324
325 break;
326 }
327 }
328 }
329 }
330 }
331
332 while (!rttiInstances.empty())
333 {
334 RTTITypeBase* rttiInstance = rttiInstances.top();
335 rttiInstance->onDeserializationEnded(object.get(), mContext);
336 mAlloc->destruct(rttiInstance);
337
338 rttiInstances.pop();
339 }
340 }
341
342 SPtr<SerializedObject> IntermediateSerializer::encodeEntry(IReflectable* object, bool shallow)
343 {
344 FrameStack<RTTITypeBase*> rttiInstances;
345 RTTITypeBase* rtti = object->getRTTI();
346
347 const auto cleanup = [&]()
348 {
349 while (!rttiInstances.empty())
350 {
351 RTTITypeBase* rttiInstance = rttiInstances.top();
352 rttiInstance->onSerializationEnded(object, mContext);
353 mAlloc->destruct(rttiInstance);
354
355 rttiInstances.pop();
356 }
357 };
358
359 SPtr<SerializedObject> output = bs_shared_ptr_new<SerializedObject>();
360
361 // If an object has base classes, we need to iterate through all of them
362 do
363 {
364 RTTITypeBase* rttiInstance = rtti->_clone(*mAlloc);
365 rttiInstances.push(rttiInstance);
366
367 rttiInstance->onSerializationStarted(object, mContext);
368
369 output->subObjects.push_back(SerializedSubObject());
370 SerializedSubObject& subObject = output->subObjects.back();
371 subObject.typeId = rtti->getRTTIId();
372
373 const UINT32 numFields = rtti->getNumFields();
374 for (UINT32 i = 0; i < numFields; i++)
375 {
376 SPtr<SerializedInstance> serializedEntry;
377
378 RTTIField* curGenericField = rtti->getField(i);
379 if (curGenericField->mIsVectorType)
380 {
381 const UINT32 arrayNumElems = curGenericField->getArraySize(rttiInstance, object);
382
383 const SPtr<SerializedArray> serializedArray = bs_shared_ptr_new<SerializedArray>();
384 serializedArray->numElements = arrayNumElems;
385
386 serializedEntry = serializedArray;
387
388 switch (curGenericField->mType)
389 {
390 case SerializableFT_ReflectablePtr:
391 {
392 auto curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
393
394 for (UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
395 {
396 SPtr<SerializedObject> serializedChildObj = nullptr;
397
398 if (!shallow)
399 {
400 SPtr<IReflectable> childObject = curField->getArrayValue(rttiInstance, object, arrIdx);
401
402 if (childObject)
403 serializedChildObj = encodeEntry(childObject.get(), shallow);
404 }
405
406 SerializedArrayEntry arrayEntry;
407 arrayEntry.serialized = serializedChildObj;
408 arrayEntry.index = arrIdx;
409
410 serializedArray->entries[arrIdx] = arrayEntry;
411 }
412
413 break;
414 }
415 case SerializableFT_Reflectable:
416 {
417 auto curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
418
419 for (UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
420 {
421 IReflectable& childObject = curField->getArrayValue(rttiInstance, object, arrIdx);
422
423 const SPtr<SerializedObject> serializedChildObj = encodeEntry(&childObject, shallow);
424
425 SerializedArrayEntry arrayEntry;
426 arrayEntry.serialized = serializedChildObj;
427 arrayEntry.index = arrIdx;
428
429 serializedArray->entries[arrIdx] = arrayEntry;
430 }
431
432 break;
433 }
434 case SerializableFT_Plain:
435 {
436 auto curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
437
438 for (UINT32 arrIdx = 0; arrIdx < arrayNumElems; arrIdx++)
439 {
440 UINT32 typeSize = 0;
441 if (curField->hasDynamicSize())
442 typeSize = curField->getArrayElemDynamicSize(rttiInstance, object, arrIdx);
443 else
444 typeSize = curField->getTypeSize();
445
446 const auto serializedField = bs_shared_ptr_new<SerializedField>();
447 serializedField->value = (UINT8*)bs_alloc(typeSize);
448 serializedField->ownsMemory = true;
449 serializedField->size = typeSize;
450
451 curField->arrayElemToBuffer(rttiInstance, object, arrIdx, serializedField->value);
452
453 SerializedArrayEntry arrayEntry;
454 arrayEntry.serialized = serializedField;
455 arrayEntry.index = arrIdx;
456
457 serializedArray->entries[arrIdx] = arrayEntry;
458 }
459
460 break;
461 }
462 default:
463 BS_EXCEPT(InternalErrorException,
464 "Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) +
465 ", Is array: " + toString(curGenericField->mIsVectorType));
466 }
467 }
468 else
469 {
470 switch (curGenericField->mType)
471 {
472 case SerializableFT_ReflectablePtr:
473 {
474 auto curField = static_cast<RTTIReflectablePtrFieldBase*>(curGenericField);
475
476 if (!shallow)
477 {
478 SPtr<IReflectable> childObject = curField->getValue(rttiInstance, object);
479
480 if (childObject)
481 serializedEntry = encodeEntry(childObject.get(), shallow);
482 }
483
484 break;
485 }
486 case SerializableFT_Reflectable:
487 {
488 auto curField = static_cast<RTTIReflectableFieldBase*>(curGenericField);
489 IReflectable& childObject = curField->getValue(rttiInstance, object);
490
491 serializedEntry = encodeEntry(&childObject, shallow);
492
493 break;
494 }
495 case SerializableFT_Plain:
496 {
497 auto curField = static_cast<RTTIPlainFieldBase*>(curGenericField);
498
499 UINT32 typeSize = 0;
500 if (curField->hasDynamicSize())
501 typeSize = curField->getDynamicSize(rttiInstance, object);
502 else
503 typeSize = curField->getTypeSize();
504
505 const auto serializedField = bs_shared_ptr_new<SerializedField>();
506 serializedField->value = (UINT8*)bs_alloc(typeSize);
507 serializedField->ownsMemory = true;
508 serializedField->size = typeSize;
509
510 curField->toBuffer(rttiInstance, object, serializedField->value);
511
512 serializedEntry = serializedField;
513
514 break;
515 }
516 case SerializableFT_DataBlock:
517 {
518 auto curField = static_cast<RTTIManagedDataBlockFieldBase*>(curGenericField);
519
520 UINT32 dataBlockSize = 0;
521 SPtr<DataStream> blockStream = curField->getValue(rttiInstance, object, dataBlockSize);
522
523 auto dataBlockBuffer = (UINT8*)bs_alloc(dataBlockSize);
524 blockStream->read(dataBlockBuffer, dataBlockSize);
525
526 SPtr<DataStream> stream = bs_shared_ptr_new<MemoryDataStream>(dataBlockBuffer, dataBlockSize);
527
528 SPtr<SerializedDataBlock> serializedDataBlock = bs_shared_ptr_new<SerializedDataBlock>();
529 serializedDataBlock->stream = stream;
530 serializedDataBlock->offset = 0;
531
532 serializedDataBlock->size = dataBlockSize;
533 serializedEntry = serializedDataBlock;
534
535 break;
536 }
537 default:
538 BS_EXCEPT(InternalErrorException,
539 "Error encoding data. Encountered a type I don't know how to encode. Type: " + toString(UINT32(curGenericField->mType)) +
540 ", Is array: " + toString(curGenericField->mIsVectorType));
541 }
542 }
543
544 SerializedEntry entry;
545 entry.fieldId = curGenericField->mUniqueId;
546 entry.serialized = serializedEntry;
547
548 subObject.entries.insert(std::make_pair(curGenericField->mUniqueId, entry));
549 }
550
551 rtti = rtti->getBaseClass();
552
553 } while (rtti != nullptr); // Repeat until we reach the top of the inheritance hierarchy
554
555 cleanup();
556
557 return output;
558 }
559 }
560
561 SPtr<SerializedObject> SerializedObject::create(IReflectable& obj, bool shallow, SerializationContext* context)
562 {
563 detail::IntermediateSerializer is;
564 return is.encode(&obj, shallow, context);
565
566 }
567
568 SPtr<IReflectable> SerializedObject::decode(SerializationContext* context) const
569 {
570 detail::IntermediateSerializer is;
571 return is.decode(this, context);
572 }
573
574 SPtr<SerializedInstance> SerializedObject::clone(bool cloneData)
575 {
576 SPtr<SerializedObject> copy = bs_shared_ptr_new<SerializedObject>();
577 copy->subObjects = Vector<SerializedSubObject>(subObjects.size());
578
579 UINT32 i = 0;
580 for (auto& subObject : subObjects)
581 {
582 copy->subObjects[i].typeId = subObject.typeId;
583
584 for (auto& entryPair : subObject.entries)
585 {
586 SerializedEntry entry = entryPair.second;
587
588 if (entry.serialized != nullptr)
589 entry.serialized = entry.serialized->clone(cloneData);
590
591 copy->subObjects[i].entries[entryPair.first] = entry;
592 }
593
594 i++;
595 }
596
597 return copy;
598 }
599
600 SPtr<SerializedInstance> SerializedField::clone(bool cloneData)
601 {
602 SPtr<SerializedField> copy = bs_shared_ptr_new<SerializedField>();
603 copy->size = size;
604
605 if (cloneData)
606 {
607 copy->value = (UINT8*)bs_alloc(size);
608 memcpy(copy->value, value, size);
609 copy->ownsMemory = true;
610 }
611 else
612 {
613 copy->value = value;
614 copy->ownsMemory = false;
615 }
616
617 return copy;
618 }
619
620 SPtr<SerializedInstance> SerializedDataBlock::clone(bool cloneData)
621 {
622 SPtr<SerializedDataBlock> copy = bs_shared_ptr_new<SerializedDataBlock>();
623 copy->size = size;
624
625 if (cloneData)
626 {
627 if(stream->isFile())
628 LOGWRN("Cloning a file stream. Streaming is disabled and stream data will be loaded into memory.");
629
630 UINT8* data = (UINT8*)bs_alloc(size);
631 stream->read(data, size);
632
633 copy->stream = bs_shared_ptr_new<MemoryDataStream>(data, size);
634 copy->offset = 0;
635 }
636 else
637 {
638 copy->stream = stream;
639 copy->offset = offset;
640 }
641
642 return copy;
643 }
644
645 SPtr<SerializedInstance> SerializedArray::clone(bool cloneData)
646 {
647 SPtr<SerializedArray> copy = bs_shared_ptr_new<SerializedArray>();
648 copy->numElements = numElements;
649
650 for (auto& entryPair : entries)
651 {
652 SerializedArrayEntry entry = entryPair.second;
653 entry.serialized = entry.serialized->clone(cloneData);
654
655 copy->entries[entryPair.first] = entry;
656 }
657
658 return copy;
659 }
660
661 RTTITypeBase* SerializedInstance::getRTTIStatic()
662 {
663 return SerializedInstanceRTTI::instance();
664 }
665
666 RTTITypeBase* SerializedInstance::getRTTI() const
667 {
668 return SerializedInstance::getRTTIStatic();
669 }
670
671 RTTITypeBase* SerializedDataBlock::getRTTIStatic()
672 {
673 return SerializedDataBlockRTTI::instance();
674 }
675
676 RTTITypeBase* SerializedDataBlock::getRTTI() const
677 {
678 return SerializedDataBlock::getRTTIStatic();
679 }
680
681 RTTITypeBase* SerializedField::getRTTIStatic()
682 {
683 return SerializedFieldRTTI::instance();
684 }
685
686 RTTITypeBase* SerializedField::getRTTI() const
687 {
688 return SerializedField::getRTTIStatic();
689 }
690
691 UINT32 SerializedObject::getRootTypeId() const
692 {
693 if(subObjects.size() > 0)
694 return subObjects[0].typeId;
695
696 return 0;
697 }
698
699 RTTITypeBase* SerializedObject::getRTTIStatic()
700 {
701 return SerializedObjectRTTI::instance();
702 }
703
704 RTTITypeBase* SerializedObject::getRTTI() const
705 {
706 return SerializedObject::getRTTIStatic();
707 }
708
709 RTTITypeBase* SerializedArray::getRTTIStatic()
710 {
711 return SerializedArrayRTTI::instance();
712 }
713
714 RTTITypeBase* SerializedArray::getRTTI() const
715 {
716 return SerializedArray::getRTTIStatic();
717 }
718
719 RTTITypeBase* SerializedSubObject::getRTTIStatic()
720 {
721 return SerializedSubObjectRTTI::instance();
722 }
723
724 RTTITypeBase* SerializedSubObject::getRTTI() const
725 {
726 return SerializedSubObject::getRTTIStatic();
727 }
728
729 RTTITypeBase* SerializedEntry::getRTTIStatic()
730 {
731 return SerializedEntryRTTI::instance();
732 }
733
734 RTTITypeBase* SerializedEntry::getRTTI() const
735 {
736 return SerializedEntry::getRTTIStatic();
737 }
738
739 RTTITypeBase* SerializedArrayEntry::getRTTIStatic()
740 {
741 return SerializedArrayEntryRTTI::instance();
742 }
743
744 RTTITypeBase* SerializedArrayEntry::getRTTI() const
745 {
746 return SerializedArrayEntry::getRTTIStatic();
747 }
748}