/// Update resource precaching for the given object load request. /// /// @param[in] pRequest Load request to update. /// /// @return True if resource precaching still requires processing, false if not. bool GameObjectLoader::TickPrecache( LoadRequest* pRequest ) { HELIUM_ASSERT( pRequest ); HELIUM_ASSERT( !( pRequest->stateFlags & LOAD_FLAG_LOADED ) ); GameObject* pObject = pRequest->spObject; if( pObject ) { // Wait for all link dependencies to fully load first. DynArray< LinkEntry >& rLinkTable = pRequest->linkTable; size_t linkTableSize = rLinkTable.GetSize(); for( size_t linkIndex = 0; linkIndex < linkTableSize; ++linkIndex ) { LinkEntry& rLinkEntry = rLinkTable[ linkIndex ]; if( IsValid( rLinkEntry.loadId ) ) { if( !TryFinishLoad( rLinkEntry.loadId, rLinkEntry.spObject ) ) { return false; } SetInvalid( rLinkEntry.loadId ); rLinkEntry.spObject.Release(); } } rLinkTable.Resize( 0 ); // Perform any pre-precaching work (note that we don't precache anything for the default template object for // a given type). OnPrecacheReady( pObject, pRequest->pPackageLoader ); if( !pObject->GetAnyFlagSet( GameObject::FLAG_BROKEN ) && !pObject->IsDefaultTemplate() && pObject->NeedsPrecacheResourceData() ) { if( !( pRequest->stateFlags & LOAD_FLAG_PRECACHE_STARTED ) ) { if( !pObject->BeginPrecacheResourceData() ) { HELIUM_TRACE( TRACE_ERROR, TXT( "GameObjectLoader: Failed to begin precaching object \"%s\".\n" ), *pObject->GetPath().ToString() ); pObject->SetFlags( GameObject::FLAG_PRECACHED | GameObject::FLAG_BROKEN ); AtomicOrRelease( pRequest->stateFlags, LOAD_FLAG_PRECACHED | LOAD_FLAG_ERROR ); return true; } AtomicOrRelease( pRequest->stateFlags, LOAD_FLAG_PRECACHE_STARTED ); } if( !pObject->TryFinishPrecacheResourceData() ) { return false; } } pObject->SetFlags( GameObject::FLAG_PRECACHED ); } AtomicOrRelease( pRequest->stateFlags, LOAD_FLAG_PRECACHED ); return true; }
/// @copydoc PackageLoader::BeginLoadObject() size_t CachePackageLoader::BeginLoadObject( GameObjectPath path ) { HELIUM_ASSERT( m_pCache ); // Don't load packages from the cache, but instead create them dynamically. if( path.IsPackage() ) { HELIUM_TRACE( TraceLevels::Debug, TXT( "CachePackageLoader::BeginLoadObject(): \"%s\" is a package, resolving immediately.\n" ), *path.ToString() ); LoadRequest* pRequest = m_loadRequestPool.Allocate(); HELIUM_ASSERT( pRequest ); pRequest->pEntry = NULL; ResolvePackage( pRequest->spObject, path ); HELIUM_ASSERT( pRequest->spObject ); SetInvalid( pRequest->asyncLoadId ); pRequest->pAsyncLoadBuffer = NULL; pRequest->pSerializedData = NULL; pRequest->pPropertyStreamEnd = NULL; pRequest->pPersistentResourceStreamEnd = NULL; HELIUM_ASSERT( pRequest->typeLinkTable.IsEmpty() ); HELIUM_ASSERT( pRequest->objectLinkTable.IsEmpty() ); HELIUM_ASSERT( !pRequest->spType ); HELIUM_ASSERT( !pRequest->spTemplate ); HELIUM_ASSERT( !pRequest->spOwner ); SetInvalid( pRequest->templateLinkIndex ); SetInvalid( pRequest->ownerLinkIndex ); pRequest->flags = LOAD_FLAG_PRELOADED; size_t requestId = m_loadRequests.Add( pRequest ); return requestId; } const Cache::Entry* pEntry = m_pCache->FindEntry( path, 0 ); if( !pEntry ) { HELIUM_TRACE( TraceLevels::Debug, ( TXT( "CachePackageLoader::BeginLoadObject(): \"%s\" is not cached in this package. No load " ) TXT( "request added.\n" ) ), *path.ToString() ); return Invalid< size_t >(); } #ifndef NDEBUG size_t loadRequestSize = m_loadRequests.GetSize(); for( size_t loadRequestIndex = 0; loadRequestIndex < loadRequestSize; ++loadRequestIndex ) { if( !m_loadRequests.IsElementValid( loadRequestIndex ) ) { continue; } LoadRequest* pRequest = m_loadRequests[ loadRequestIndex ]; HELIUM_ASSERT( pRequest ); HELIUM_ASSERT( pRequest->pEntry != pEntry ); if( pRequest->pEntry == pEntry ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "CachePackageLoader::BeginLoadObject(): Duplicate load request of \"%s\". No load " ) TXT( "request added.\n" ) ), *path.ToString() ); return Invalid< size_t >(); } } #endif LoadRequest* pRequest = m_loadRequestPool.Allocate(); HELIUM_ASSERT( pRequest ); pRequest->pEntry = pEntry; HELIUM_ASSERT( !pRequest->spObject ); SetInvalid( pRequest->asyncLoadId ); pRequest->pAsyncLoadBuffer = NULL; pRequest->pSerializedData = NULL; pRequest->pPropertyStreamEnd = NULL; pRequest->pPersistentResourceStreamEnd = NULL; HELIUM_ASSERT( pRequest->typeLinkTable.IsEmpty() ); HELIUM_ASSERT( pRequest->objectLinkTable.IsEmpty() ); HELIUM_ASSERT( !pRequest->spType ); HELIUM_ASSERT( !pRequest->spTemplate ); HELIUM_ASSERT( !pRequest->spOwner ); SetInvalid( pRequest->templateLinkIndex ); SetInvalid( pRequest->ownerLinkIndex ); pRequest->flags = 0; // If a fully-loaded object already exists with the same name, do not attempt to re-load the object (just mark // the request as complete). pRequest->spObject = GameObject::FindObject( pEntry->path ); GameObject* pObject = pRequest->spObject; if( pObject && pObject->IsFullyLoaded() ) { HELIUM_TRACE( TraceLevels::Debug, ( TXT( "CachePackageLoader::BeginLoadObject(): \"%s\" is already fully loaded. Bypassing load " ) TXT( "process.\n" ) ), *path.ToString() ); pRequest->flags = LOAD_FLAG_PRELOADED; } else { HELIUM_ASSERT( !pObject || !pObject->GetAnyFlagSet( GameObject::FLAG_LOADED | GameObject::FLAG_LINKED ) ); HELIUM_TRACE( TraceLevels::Debug, TXT( "CachePackageLoader::BeginLoadObject(): Issuing async load of property data for \"%s\".\n" ), *path.ToString() ); size_t entrySize = pEntry->size; pRequest->pAsyncLoadBuffer = static_cast< uint8_t* >( DefaultAllocator().Allocate( entrySize ) ); HELIUM_ASSERT( pRequest->pAsyncLoadBuffer ); AsyncLoader& rLoader = AsyncLoader::GetStaticInstance(); pRequest->asyncLoadId = rLoader.QueueRequest( pRequest->pAsyncLoadBuffer, m_pCache->GetCacheFileName(), pEntry->offset, entrySize ); HELIUM_ASSERT( IsValid( pRequest->asyncLoadId ) ); } size_t requestId = m_loadRequests.Add( pRequest ); HELIUM_TRACE( TraceLevels::Debug, ( TXT( "CachePackageLoader::BeginLoadObject(): Load request for \"%s\" added (ID: %" ) TPRIuSZ TXT( ").\n" ) ), *path.ToString(), requestId ); return requestId; }