//********************************** Banshee Engine (www.banshee3d.com) **************************************************// //**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************// #include "Serialization/BsManagedSerializableObject.h" #include "RTTI/BsManagedSerializableObjectRTTI.h" #include "Serialization/BsManagedSerializableObjectInfo.h" #include "Serialization/BsManagedSerializableField.h" #include "Serialization/BsScriptAssemblyManager.h" #include "BsMonoField.h" #include "BsMonoClass.h" #include "BsMonoUtil.h" namespace bs { inline size_t ManagedSerializableObject::Hash::operator()(const ManagedSerializableFieldKey& x) const { size_t seed = 0; hash_combine(seed, (UINT32)x.mFieldId); hash_combine(seed, (UINT32)x.mTypeId); return seed; } inline bool ManagedSerializableObject::Equals::operator()(const ManagedSerializableFieldKey& a, const ManagedSerializableFieldKey& b) const { return a.mFieldId == b.mFieldId && a.mTypeId == b.mTypeId; } ManagedSerializableObject::ManagedSerializableObject(const ConstructPrivately& dummy) { } ManagedSerializableObject::ManagedSerializableObject(const ConstructPrivately& dummy, SPtr objInfo, MonoObject* managedInstance) :mObjInfo(objInfo) { mGCHandle = MonoUtil::newGCHandle(managedInstance, false); } ManagedSerializableObject::~ManagedSerializableObject() { if(mGCHandle != 0) { MonoUtil::freeGCHandle(mGCHandle); mGCHandle = 0; } } SPtr ManagedSerializableObject::createFromExisting(MonoObject* managedInstance) { if(managedInstance == nullptr) return nullptr; String elementNs; String elementTypeName; MonoUtil::getClassName(managedInstance, elementNs, elementTypeName); SPtr objInfo; if(!ScriptAssemblyManager::instance().getSerializableObjectInfo(elementNs, elementTypeName, objInfo)) return nullptr; return bs_shared_ptr_new(ConstructPrivately(), objInfo, managedInstance); } SPtr ManagedSerializableObject::createNew(const SPtr& type) { SPtr currentObjInfo = nullptr; // See if this type even still exists if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(type->mTypeNamespace, type->mTypeName, currentObjInfo)) return nullptr; return bs_shared_ptr_new(ConstructPrivately(), currentObjInfo, createManagedInstance(type)); } MonoObject* ManagedSerializableObject::createManagedInstance(const SPtr& type) { SPtr currentObjInfo = nullptr; // See if this type even still exists if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(type->mTypeNamespace, type->mTypeName, currentObjInfo)) return nullptr; if(!currentObjInfo->mTypeInfo->mFlags.isSet(ScriptTypeFlag::Serializable)) return nullptr; const bool construct = currentObjInfo->mMonoClass->getMethod(".ctor", 0) != nullptr; return currentObjInfo->mMonoClass->createInstance(construct); } SPtr ManagedSerializableObject::createEmpty() { return bs_shared_ptr_new(ConstructPrivately()); } MonoObject* ManagedSerializableObject::getManagedInstance() const { if(mGCHandle != 0) return MonoUtil::getObjectFromGCHandle(mGCHandle); return nullptr; } void ManagedSerializableObject::serialize() { if(mGCHandle == 0) return; mCachedData.clear(); SPtr curType = mObjInfo; while (curType != nullptr) { for (auto& field : curType->mFields) { if (field.second->isSerializable()) { ManagedSerializableFieldKey key(field.second->mParentTypeId, field.second->mFieldId); mCachedData[key] = getFieldData(field.second); } } curType = curType->mBaseClass; } // Serialize children for (auto& fieldEntry : mCachedData) fieldEntry.second->serialize(); MonoUtil::freeGCHandle(mGCHandle); mGCHandle = 0; } MonoObject* ManagedSerializableObject::deserialize() { // See if this type even still exists SPtr currentObjInfo = nullptr; if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mObjInfo->mTypeInfo->mTypeNamespace, mObjInfo->mTypeInfo->mTypeName, currentObjInfo)) { return nullptr; } MonoObject* managedInstance = createManagedInstance(currentObjInfo->mTypeInfo); deserialize(managedInstance, currentObjInfo); return managedInstance; } void ManagedSerializableObject::deserialize(MonoObject* instance, const SPtr& objInfo) { if (instance == nullptr) return; // Deserialize children for (auto& fieldEntry : mCachedData) fieldEntry.second->deserialize(); // Scan all fields and ensure the fields still exist UINT32 i = 0; SPtr curType = mObjInfo; while (curType != nullptr) { for (auto& field : curType->mFields) { if (field.second->isSerializable()) { UINT32 fieldId = field.second->mFieldId; UINT32 typeID = field.second->mParentTypeId; ManagedSerializableFieldKey key(typeID, fieldId); SPtr matchingFieldInfo = objInfo->findMatchingField(field.second, curType->mTypeInfo); if (matchingFieldInfo != nullptr) matchingFieldInfo->setValue(instance, mCachedData[key]->getValue(matchingFieldInfo->mTypeInfo)); i++; } } curType = curType->mBaseClass; } } void ManagedSerializableObject::setFieldData(const SPtr& fieldInfo, const SPtr& val) { if (mGCHandle != 0) { MonoObject* managedInstance = MonoUtil::getObjectFromGCHandle(mGCHandle); fieldInfo->setValue(managedInstance, val->getValue(fieldInfo->mTypeInfo)); } else { ManagedSerializableFieldKey key(fieldInfo->mParentTypeId, fieldInfo->mFieldId); mCachedData[key] = val; } } SPtr ManagedSerializableObject::getFieldData(const SPtr& fieldInfo) const { if (mGCHandle != 0) { MonoObject* managedInstance = MonoUtil::getObjectFromGCHandle(mGCHandle); MonoObject* fieldValue = fieldInfo->getValue(managedInstance); return ManagedSerializableFieldData::create(fieldInfo->mTypeInfo, fieldValue); } else { ManagedSerializableFieldKey key(fieldInfo->mParentTypeId, fieldInfo->mFieldId); auto iterFind = mCachedData.find(key); if (iterFind != mCachedData.end()) return iterFind->second; return nullptr; } } RTTITypeBase* ManagedSerializableObject::getRTTIStatic() { return ManagedSerializableObjectRTTI::instance(); } RTTITypeBase* ManagedSerializableObject::getRTTI() const { return ManagedSerializableObject::getRTTIStatic(); } }