/// Create a type object. /// /// @param[in] name Type name. /// @param[in] pTypePackage Package in which the template object should be stored. /// @param[in] pParent Parent type. /// @param[in] pTemplate Template object. /// @param[in] flags Type flags. /// /// @return Pointer to the type object if created successfully, null if not. /// /// @see Unregister() const GameObjectType* GameObjectType::Create( Name name, Package* pTypePackage, const GameObjectType* pParent, GameObject* pTemplate, RELEASE_STATIC_TYPE_CALLBACK* pReleaseStaticTypeCallback, uint32_t flags ) { HELIUM_ASSERT( !name.IsEmpty() ); HELIUM_ASSERT( pTypePackage ); HELIUM_ASSERT( pTemplate ); HELIUM_ASSERT( pReleaseStaticTypeCallback ); // Register the template object with the object system. if( !GameObject::RegisterObject( pTemplate ) ) { HELIUM_TRACE( TRACE_ERROR, TXT( "GameObjectType::Initialize(): Failed to register type \"%s\" template object.\n" ), *name ); return false; } // Set up the template object name, and set this object as its parent. GameObject::RenameParameters nameParameters; nameParameters.name = name; nameParameters.spOwner = pTypePackage; if( !pTemplate->Rename( nameParameters ) ) { HELIUM_TRACE( TRACE_ERROR, TXT( "GameObjectType::Initialize(): Failed to set type \"%s\" template object name and owner.\n" ), *name ); GameObject::UnregisterObject( pTemplate ); return false; } // Flag the object as the default template object for the type being created. pTemplate->SetFlags( GameObject::FLAG_DEFAULT_TEMPLATE ); // If the parent type is null, default to Reflect::Object, as the type should be deriving from it directly. const Reflect::Class* pBaseClass = pParent; if( !pBaseClass ) { pBaseClass = Reflect::Object::s_Class; HELIUM_ASSERT( pBaseClass ); } // Create the type object and store its parameters. GameObjectType* pType = new GameObjectType; HELIUM_ASSERT( pType ); pType->m_Name = *name; pType->m_Size = static_cast< uint32_t >( pTemplate->GetInstanceSize() ); pType->m_Base = pBaseClass; pType->Composite::m_Default = pType->m_Default = pTemplate; pType->m_cachedName = name; pType->m_pReleaseStaticTypeCallback = pReleaseStaticTypeCallback; pType->m_flags = flags; if( pParent ) { pParent->AddDerived( pType ); } // Lazily initialize the lookup map. Note that this is not inherently thread-safe, but there should always be // at least one type registered before any sub-threads are spawned. if( !sm_pLookupMap ) { sm_pLookupMap = new LookupMap; HELIUM_ASSERT( sm_pLookupMap ); } // Register the type (note that a type with the same name should not already exist in the lookup map). LookupMap::Iterator typeIterator; HELIUM_VERIFY( sm_pLookupMap->Insert( typeIterator, KeyValue< Name, GameObjectTypePtr >( pType->GetName(), pType ) ) ); Reflect::Registry* pRegistry = Reflect::Registry::GetInstance(); HELIUM_ASSERT( pRegistry ); pRegistry->RegisterType( pType ); return pType; }
/// Tick the object deserialization process for the given object load request. /// /// @param[in] pRequest Load request. /// /// @return True if the deserialization process has completed, false if it still needs time to process. bool CachePackageLoader::TickDeserialize( LoadRequest* pRequest ) { HELIUM_ASSERT( pRequest ); HELIUM_ASSERT( !( pRequest->flags & LOAD_FLAG_PRELOADED ) ); GameObject* pObject = pRequest->spObject; const Cache::Entry* pCacheEntry = pRequest->pEntry; HELIUM_ASSERT( pCacheEntry ); // Wait for the template and owner objects to load. GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance(); HELIUM_ASSERT( pObjectLoader ); if( IsValid( pRequest->templateLinkIndex ) ) { HELIUM_ASSERT( pRequest->templateLinkIndex < pRequest->objectLinkTable.GetSize() ); size_t templateLoadId = pRequest->objectLinkTable[ pRequest->templateLinkIndex ]; if( IsValid( templateLoadId ) && !pObjectLoader->TryFinishLoad( templateLoadId, pRequest->spTemplate ) ) { return false; } SetInvalid( pRequest->templateLinkIndex ); if( !pRequest->spTemplate ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to load template object for \"%s\".\n" ), *pCacheEntry->path.ToString() ); if( pObject ) { pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); } DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } GameObject* pTemplate = pRequest->spTemplate; if( IsValid( pRequest->ownerLinkIndex ) ) { HELIUM_ASSERT( pRequest->ownerLinkIndex < pRequest->objectLinkTable.GetSize() ); size_t ownerLoadId = pRequest->objectLinkTable[ pRequest->ownerLinkIndex ]; if( IsValid( ownerLoadId ) && !pObjectLoader->TryFinishLoad( ownerLoadId, pRequest->spOwner ) ) { return false; } SetInvalid( pRequest->ownerLinkIndex ); if( !pRequest->spOwner ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to load owner object for \"%s\".\n" ), *pCacheEntry->path.ToString() ); if( pObject ) { pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); } DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } GameObject* pOwner = pRequest->spOwner; HELIUM_ASSERT( !pOwner || pOwner->IsFullyLoaded() ); HELIUM_ASSERT( !pTemplate || pTemplate->IsFullyLoaded() ); GameObjectType* pType = pRequest->spType; HELIUM_ASSERT( pType ); // If we already had an existing object, make sure the type and template match. if( pObject ) { const GameObjectType* pExistingType = pObject->GetGameObjectType(); HELIUM_ASSERT( pExistingType ); if( pExistingType != pType ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "CachePackageLoader: Cannot load \"%s\" using the existing object as the types do not " ) TXT( "match (existing type: \"%s\"; serialized type: \"%s\".\n" ) ), *pCacheEntry->path.ToString(), *pExistingType->GetName(), *pType->GetName() ); pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } else { // Create the object. if( !GameObject::CreateObject( pRequest->spObject, pType, pCacheEntry->path.GetName(), pOwner, pTemplate ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to create \"%s\" during loading.\n" ), *pCacheEntry->path.ToString() ); DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } pObject = pRequest->spObject; HELIUM_ASSERT( pObject ); } Reflect::ObjectPtr cached_object = Cache::ReadCacheObjectFromBuffer(pRequest->pSerializedData, 0, pRequest->pPropertyStreamEnd - pRequest->pSerializedData); if (!cached_object.ReferencesObject()) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to deserialize object \"%s\".\n" ), *pCacheEntry->path.ToString() ); // Clear out object references (object can now be considered fully loaded as well). // pmd - Not sure that we need to do this.. but if we do, just use this visitor //ClearLinkIndicesFromObject clifo_visitor; //pObject->Accept(clifo_visitor); pObject->SetFlags( GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); pRequest->flags |= LOAD_FLAG_ERROR; } else { cached_object->CopyTo(pObject); if( !pObject->IsDefaultTemplate() ) { // Load persistent resource data. Resource* pResource = Reflect::SafeCast< Resource >( pObject ); if( pResource ) { Reflect::ObjectPtr cached_prd = Cache::ReadCacheObjectFromBuffer( pRequest->pPropertyStreamEnd, 0, (pRequest->pPersistentResourceStreamEnd - pRequest->pPropertyStreamEnd)); if (!cached_prd.ReferencesObject()) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "CachePackageLoader: Failed to deserialize persistent resource " ) TXT( "data for \"%s\".\n" ) ), *pCacheEntry->path.ToString() ); } else { pResource->LoadPersistentResourceObject(cached_prd); } } } } DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pObject->SetFlags( GameObject::FLAG_PRELOADED ); pRequest->flags |= LOAD_FLAG_PRELOADED; // GameObject is now preloaded. return true; }