/// Tick the async loading of binary serialized data from the object cache for the given load request. /// /// @param[in] pRequest Load request. /// /// @return True if the cache load process has completed, false if it still requires processing. bool CachePackageLoader::TickCacheLoad( LoadRequest* pRequest ) { HELIUM_ASSERT( pRequest ); HELIUM_ASSERT( !( pRequest->flags & LOAD_FLAG_PRELOADED ) ); AsyncLoader& rAsyncLoader = AsyncLoader::GetStaticInstance(); size_t bytesRead = 0; if( !rAsyncLoader.TrySyncRequest( pRequest->asyncLoadId, bytesRead ) ) { return false; } SetInvalid( pRequest->asyncLoadId ); if( bytesRead == 0 || IsInvalid( bytesRead ) ) { HELIUM_ASSERT( pRequest->pEntry ); HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader: Failed to read cache data for object \"%s\".\n" ), *pRequest->pEntry->path.ToString() ); } else { uint8_t* pBufferEnd = pRequest->pAsyncLoadBuffer + bytesRead; pRequest->pPropertyStreamEnd = pBufferEnd; pRequest->pPersistentResourceStreamEnd = pBufferEnd; if( DeserializeLinkTables( pRequest ) ) { return true; } } // An error occurred attempting to load the property data, so mark any existing object as fully loaded (nothing // else will be done with the object itself from here on out). DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; GameObject* pObject = pRequest->spObject; if( pObject ) { pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); } pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; }
/// Update loading finalization for the given object load request. /// /// @param[in] pRequest Load request to update. /// /// @return True if load finalization has completed, false if not. bool GameObjectLoader::TickFinalizeLoad( LoadRequest* pRequest ) { HELIUM_ASSERT( pRequest ); GameObject* pObject = pRequest->spObject; if( pObject ) { pObject->ConditionalFinalizeLoad(); } // Loading now complete. OnLoadComplete( pRequest->path, pObject, pRequest->pPackageLoader ); AtomicOrRelease( pRequest->stateFlags, LOAD_FLAG_LOADED ); return true; }
/// 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; }