/// Update during the package preload process. void LoosePackageLoader::TickPreload() { HELIUM_ASSERT( m_startPreloadCounter != 0 ); HELIUM_ASSERT( m_preloadedCounter == 0 ); AsyncLoader& rAsyncLoader = AsyncLoader::GetStaticInstance(); bool bAllFileRequestsDone = true; // Walk through every load request for (size_t i = 0; i < m_fileReadRequests.GetSize();) { FileReadRequest &rRequest = m_fileReadRequests[i]; HELIUM_ASSERT(rRequest.asyncLoadId); HELIUM_ASSERT(rRequest.pLoadBuffer); size_t bytes_read = 0; if (!rAsyncLoader.TrySyncRequest(rRequest.asyncLoadId, bytes_read)) { // Havn't finished reading yet, move on to next entry bAllFileRequestsDone = false; ++i; continue; } HELIUM_ASSERT(bytes_read == rRequest.expectedSize); if( IsInvalid( bytes_read ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader: Failed to read the contents of async load request \"%d\".\n" ), rRequest.asyncLoadId ); } else if( bytes_read != rRequest.expectedSize) { HELIUM_TRACE( TraceLevels::Warning, ( TXT( "LoosePackageLoader: Attempted to read %" ) PRIuSZ TXT( " bytes from package file \"%s\", " ) TXT( "but only %" ) PRIuSZ TXT( " bytes were read.\n" ) ), rRequest.expectedSize, bytes_read ); } else { HELIUM_ASSERT( rRequest.expectedSize < ~static_cast<size_t>( 0 ) ); // the name is deduced from the file name (bad idea to store it in the file) Name name ( m_fileReadRequests[i].filePath.Basename().c_str() ); // read some preliminary data from the json struct PreliminaryObjectHandler : rapidjson::BaseReaderHandler<> { Helium::Name typeName; Helium::String templatePath; bool templateIsNext; PreliminaryObjectHandler() : typeName( ENullName () ) , templatePath( "" ) { templateIsNext = false; } void String(const Ch* chars, rapidjson::SizeType length, bool copy) { if ( typeName.IsEmpty() ) { typeName.Set( Helium::String ( chars, length ) ); return; } if ( templatePath.IsEmpty() ) { Helium::String str ( chars, length ); if ( templateIsNext ) { templatePath = str; templateIsNext = false; return; } else { if ( str == "m_spTemplate" ) { templateIsNext = true; return; } } } } void StartObject() { Default(); } void EndObject( rapidjson::SizeType ) { Default(); } } handler; // non destructive in-place stream helper rapidjson::StringStream stream ( static_cast< char* >( rRequest.pLoadBuffer ) ); // the main reader object rapidjson::Reader reader; if ( reader.Parse< rapidjson::kParseDefaultFlags >( stream, handler ) ) { SerializedObjectData* pObjectData = m_objects.New(); HELIUM_ASSERT( pObjectData ); HELIUM_VERIFY( pObjectData->objectPath.Set( name, false, m_packagePath ) ); pObjectData->templatePath.Set( handler.templatePath ); pObjectData->typeName = handler.typeName; pObjectData->filePath = rRequest.filePath; pObjectData->fileTimeStamp = rRequest.fileTimestamp; pObjectData->bMetadataGood = true; HELIUM_TRACE( TraceLevels::Debug, TXT( "LoosePackageLoader: Success reading preliminary data for object '%s' from file '%s'.\n" ), *name, rRequest.filePath.c_str() ); } else { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader: Failure reading preliminary data for object '%s' from file '%s': %s\n" ), *name, rRequest.filePath.c_str(), reader.GetParseError() ); } } // We're finished with this load, so deallocate memory and get rid of the request DefaultAllocator().Free( rRequest.pLoadBuffer ); rRequest.pLoadBuffer = NULL; SetInvalid(rRequest.asyncLoadId); m_fileReadRequests.RemoveSwap(i); } // Wait for the parent package to finish loading. AssetPtr spParentPackage; if( IsValid( m_parentPackageLoadId ) ) { AssetLoader* pAssetLoader = AssetLoader::GetStaticInstance(); HELIUM_ASSERT( pAssetLoader ); if( !pAssetLoader->TryFinishLoad( m_parentPackageLoadId, spParentPackage ) ) { return; } SetInvalid( m_parentPackageLoadId ); // Package loading should not fail. If it does, this is a sign of a potentially serious issue. HELIUM_ASSERT( spParentPackage ); } // Everything beyond this point "finalizes" the package preload, so stop here if we aren't ready to go if (!bAllFileRequestsDone) { return; } // Create the package object if it does not yet exist. Package* pPackage = m_spPackage; if( !pPackage ) { HELIUM_ASSERT( spParentPackage ? !m_packagePath.GetParent().IsEmpty() : m_packagePath.GetParent().IsEmpty() ); HELIUM_VERIFY( Asset::Create< Package >( m_spPackage, m_packagePath.GetName(), spParentPackage ) ); pPackage = m_spPackage; HELIUM_ASSERT( pPackage ); pPackage->SetLoader( this ); } HELIUM_ASSERT( pPackage->GetLoader() == this ); FilePath packageDirectoryPath; if ( !FileLocations::GetDataDirectory( packageDirectoryPath ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader::TickPreload(): Could not get data directory.\n" ) ); return; } packageDirectoryPath += m_packagePath.ToFilePathString().GetData(); packageDirectoryPath += TXT("/"); DirectoryIterator packageDirectory( packageDirectoryPath ); for( ; !packageDirectory.IsDone(); packageDirectory.Next() ) { const DirectoryIteratorItem& item = packageDirectory.GetItem(); if ( !item.m_Path.IsFile() ) { continue; } Name objectName( item.m_Path.Filename().c_str() ); String objectNameString( item.m_Path.Filename().c_str() ); size_t objectIndex = FindObjectByName( objectName ); if( objectIndex != Invalid< size_t >() ) { m_objects[ objectIndex ].fileTimeStamp = Helium::Max( m_objects[ objectIndex ].fileTimeStamp, static_cast< int64_t >( packageDirectory.GetItem().m_ModTime ) ); continue; } // Check the extension to see if the file is supported by one of the resource handlers. ResourceHandler* pBestHandler = ResourceHandler::GetBestResourceHandlerForFile( objectNameString ); if( pBestHandler ) { // File extension matches a supported source asset type, so add it to the object list. const AssetType* pResourceType = pBestHandler->GetResourceType(); HELIUM_ASSERT( pResourceType ); HELIUM_TRACE( TraceLevels::Debug, ( TXT( "LoosePackageLoader: Registered source asset file \"%s\" as as instance of resource " ) TXT( "type \"%s\" in package \"%s\".\n" ) ), *objectNameString, *pResourceType->GetName(), *m_packagePath.ToString() ); SerializedObjectData* pObjectData = m_objects.New(); HELIUM_ASSERT( pObjectData ); HELIUM_VERIFY( pObjectData->objectPath.Set( objectName, false, m_packagePath ) ); pObjectData->typeName = pResourceType->GetName(); pObjectData->templatePath.Clear(); pObjectData->filePath.Clear(); pObjectData->fileTimeStamp = packageDirectory.GetItem().m_ModTime; pObjectData->bMetadataGood = true; } else { HELIUM_TRACE( TraceLevels::Debug, ( TXT( "LoosePackageLoader: Did not recognize \"%s\" as as instance of resource " ) TXT( "in package \"%s\".\n" ) ), *objectNameString, *m_packagePath.ToString() ); for ( AssetType::ConstIterator iter = AssetType::GetTypeBegin(); iter != AssetType::GetTypeEnd(); ++iter) { HELIUM_TRACE( TraceLevels::Info, TXT( " - %s\n" ), *iter->GetName() ); } } } // Package preloading is now complete. pPackage->SetFlags( Asset::FLAG_PRELOADED | Asset::FLAG_LINKED ); pPackage->ConditionalFinalizeLoad(); AtomicExchangeRelease( m_preloadedCounter, 1 ); LooseAssetLoader::OnPackagePreloaded( this ); }
/// Update processing of object property preloading for a given load request. /// /// @param[in] pRequest Load request to process. /// /// @return True if object property preloading for the given load request has completed, false if not. bool LoosePackageLoader::TickDeserialize( LoadRequest* pRequest ) { HELIUM_ASSERT( pRequest ); HELIUM_ASSERT( !( pRequest->flags & LOAD_FLAG_PROPERTY_PRELOADED ) ); Asset* pObject = pRequest->spObject; HELIUM_ASSERT( pRequest->index < m_objects.GetSize() ); SerializedObjectData& rObjectData = m_objects[ pRequest->index ]; // Wait for the template and owner objects to load. AssetLoader* pAssetLoader = AssetLoader::GetStaticInstance(); HELIUM_ASSERT( pAssetLoader ); if( !rObjectData.templatePath.IsEmpty() ) { if( IsValid( pRequest->templateLoadId ) ) { if( !pAssetLoader->TryFinishLoad( pRequest->templateLoadId, pRequest->spTemplate ) ) { return false; } SetInvalid( pRequest->templateLoadId ); } if( !pRequest->spTemplate ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader: Failed to load template object for \"%s\".\n" ), *rObjectData.objectPath.ToString() ); if( pObject ) { pObject->SetFlags( Asset::FLAG_PRELOADED | Asset::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); } pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } HELIUM_ASSERT( IsInvalid( pRequest->templateLoadId ) ); Asset* pTemplate = pRequest->spTemplate; AssetPath ownerPath = rObjectData.objectPath.GetParent(); if( !ownerPath.IsEmpty() ) { if( IsValid( pRequest->ownerLoadId ) ) { if( !pAssetLoader->TryFinishLoad( pRequest->ownerLoadId, pRequest->spOwner ) ) { return false; } SetInvalid( pRequest->ownerLoadId ); } if( !pRequest->spOwner ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader: Failed to load owner object for \"%s\".\n" ), *rObjectData.objectPath.ToString() ); if( pObject ) { pObject->SetFlags( Asset::FLAG_PRELOADED | Asset::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); } pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } HELIUM_ASSERT( IsInvalid( pRequest->ownerLoadId ) ); Asset* pOwner = pRequest->spOwner; AssetType* pType = pRequest->spType; HELIUM_ASSERT( pType ); HELIUM_ASSERT( !pOwner || pOwner->IsFullyLoaded() ); HELIUM_ASSERT( !pTemplate || pTemplate->IsFullyLoaded() ); AsyncLoader& rAsyncLoader = AsyncLoader::GetStaticInstance(); FilePath object_file_path = m_packageDirPath + *rObjectData.objectPath.GetName() + TXT( "." ) + Persist::ArchiveExtensions[ Persist::ArchiveTypes::Json ]; bool load_properties_from_file = true; size_t object_file_size = 0; if ( !IsValid( pRequest->asyncFileLoadId ) ) { if (!object_file_path.IsFile()) { if (pType->GetMetaClass()->IsType( Reflect::GetMetaClass< Resource >() )) { HELIUM_TRACE( TraceLevels::Info, TXT( "LoosePackageLoader::TickDeserialize(): No object file found for resource \"%s\". Expected file location: \"%s\". This is normal for newly added resources.\n" ), *rObjectData.objectPath.ToString(), *object_file_path); // We will allow continuing to load using all default properties. This behavior is to support dropping resources into the // data property and autogenerating objects from them. load_properties_from_file = false; } else { HELIUM_TRACE( TraceLevels::Warning, TXT( "LoosePackageLoader::TickDeserialize(): No object file found for object \"%s\". Expected file location: \"%s\"\n" ), *rObjectData.objectPath.ToString(), *object_file_path); } } else { Status status; status.Read( object_file_path.Get().c_str() ); int64_t i64_object_file_size = status.m_Size; if( i64_object_file_size == -1 ) { HELIUM_TRACE( TraceLevels::Warning, TXT( "LoosePackageLoader::TickDeserialize(): Could not get file size for object file of object \"%s\". Expected file location: \"%s\"\n" ), *rObjectData.objectPath.ToString(), *object_file_path ); } else if( i64_object_file_size == 0 ) { HELIUM_TRACE( TraceLevels::Warning, TXT( "LoosePackageLoader::TickDeserialize(): Object file \"%s\" for objct \"%s\" is empty.\n" ), *object_file_path, *rObjectData.objectPath.ToString() ); } else if( static_cast< uint64_t >( i64_object_file_size ) > static_cast< uint64_t >( ~static_cast< size_t >( 0 ) ) ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "LoosePackageLoader::TickDeserialize(): Object file \"%s\" exceeds the maximum size supported by " ) TXT( "the current platform (file size: %" ) PRIu64 TXT( " bytes; max supported: %" ) PRIuSZ TXT( " bytes).\n" ) ), object_file_path.c_str(), static_cast< uint64_t >( i64_object_file_size ), ~static_cast< size_t >( 0 ) ); } else { object_file_size = static_cast< size_t >(i64_object_file_size); } } if (!load_properties_from_file) { HELIUM_ASSERT(!object_file_size); } else if (!object_file_size) { pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } else { HELIUM_ASSERT( !pRequest->pAsyncFileLoadBuffer ); pRequest->pAsyncFileLoadBuffer = DefaultAllocator().Allocate( object_file_size ); HELIUM_ASSERT( pRequest->pAsyncFileLoadBuffer ); pRequest->asyncFileLoadBufferSize = object_file_size; pRequest->asyncFileLoadId = rAsyncLoader.QueueRequest( pRequest->pAsyncFileLoadBuffer, String(object_file_path.c_str()), 0, pRequest->asyncFileLoadBufferSize); } } size_t bytesRead = 0; if (load_properties_from_file) { HELIUM_ASSERT( IsValid( pRequest->asyncFileLoadId ) ); if ( !rAsyncLoader.TrySyncRequest( pRequest->asyncFileLoadId, bytesRead ) ) { return false; } } /////// POINT OF NO RETURN: We *will* return true after this point, and the object *will* be finished preloading, /////// for good or for bad. SetInvalid(pRequest->asyncFileLoadId); bool object_creation_failure = false; // If we already had an existing object, make sure the type and template match. if( pObject ) { const AssetType* pExistingType = pObject->GetAssetType(); HELIUM_ASSERT( pExistingType ); if( pExistingType != pType ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "LoosePackageLoader: Cannot load \"%s\" using the existing object as the types do not match " ) TXT( "(existing type: \"%s\"; serialized type: \"%s\".\n" ) ), *rObjectData.objectPath.ToString(), *pExistingType->GetName(), *pType->GetName() ); pObject->SetFlags( Asset::FLAG_PRELOADED | Asset::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); object_creation_failure = true; } } else { bool bCreateResult = false; if (pRequest->forceReload) { // Create the object. bCreateResult = Asset::CreateObject( pRequest->spObject, pType, Name( NULL_NAME ), NULL, pTemplate ); } else { // Create the object. bCreateResult = Asset::CreateObject( pRequest->spObject, pType, rObjectData.objectPath.GetName(), pOwner, pTemplate ); } if( !bCreateResult ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader: Failed to create \"%s\" during loading.\n" ), *rObjectData.objectPath.ToString() ); object_creation_failure = true; } pObject = pRequest->spObject; HELIUM_ASSERT( pObject ); } if (load_properties_from_file && !object_creation_failure) { // Sanity checks for file load, then success path HELIUM_ASSERT( bytesRead == pRequest->asyncFileLoadBufferSize ); if( IsInvalid( bytesRead ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader: Failed to read the contents of object file \"%s\" in async load request \"%d\".\n" ), object_file_path.c_str(), pRequest->asyncFileLoadId ); } else if( bytesRead != pRequest->asyncFileLoadBufferSize ) { HELIUM_TRACE( TraceLevels::Warning, ( TXT( "LoosePackageLoader: Attempted to read %" ) PRIuSZ TXT( " bytes from object file \"%s\", " ) TXT( "but only %" ) PRIuSZ TXT( " bytes were read.\n" ) ), pRequest->asyncFileLoadBufferSize, object_file_path.c_str(), bytesRead ); } else { StaticMemoryStream archiveStream ( pRequest->pAsyncFileLoadBuffer, pRequest->asyncFileLoadBufferSize ); HELIUM_TRACE( TraceLevels::Info, TXT( "LoosePackageLoader: Reading %s. pResolver = %x\n"), object_file_path.c_str(), pRequest->pResolver); DynamicArray< Reflect::ObjectPtr > objects; objects.Push( pRequest->spObject.Get() ); // use existing objects Persist::ArchiveReaderJson::ReadFromStream( archiveStream, objects, pRequest->pResolver ); HELIUM_ASSERT( objects[0].Get() == pRequest->spObject.Get() ); } } if (load_properties_from_file) { DefaultAllocator().Free(pRequest->pAsyncFileLoadBuffer); pRequest->pAsyncFileLoadBuffer = NULL; pRequest->asyncFileLoadBufferSize = 0; } pRequest->flags |= LOAD_FLAG_PROPERTY_PRELOADED; if( object_creation_failure ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader: Deserialization of object \"%s\" failed.\n" ), *rObjectData.objectPath.ToString() ); pObject->SetFlags( Asset::FLAG_PRELOADED | Asset::FLAG_LINKED ); pObject->ConditionalFinalizeLoad(); pRequest->flags |= LOAD_FLAG_ERROR; } else if( !pObject->IsDefaultTemplate() ) { // If the object is a resource (not including the default template object for resource types), attempt to begin // loading any existing persistent resource data stored in the object cache. Resource* pResource = Reflect::SafeCast< Resource >( pObject ); if( pResource ) { Name objectCacheName = Name( HELIUM_ASSET_CACHE_NAME ); CacheManager& rCacheManager = CacheManager::GetStaticInstance(); Cache* pCache = rCacheManager.GetCache( objectCacheName ); HELIUM_ASSERT( pCache ); pCache->EnforceTocLoad(); const Cache::Entry* pEntry = pCache->FindEntry( rObjectData.objectPath, 0 ); if( pEntry && pEntry->size != 0 ) { HELIUM_ASSERT( IsInvalid( pRequest->persistentResourceDataLoadId ) ); HELIUM_ASSERT( !pRequest->pCachedObjectDataBuffer ); pRequest->pCachedObjectDataBuffer = static_cast< uint8_t* >( DefaultAllocator().Allocate( pEntry->size ) ); HELIUM_ASSERT( pRequest->pCachedObjectDataBuffer ); pRequest->cachedObjectDataBufferSize = pEntry->size; AsyncLoader& rAsyncLoader = AsyncLoader::GetStaticInstance(); pRequest->persistentResourceDataLoadId = rAsyncLoader.QueueRequest( pRequest->pCachedObjectDataBuffer, pCache->GetCacheFileName(), pEntry->offset, pEntry->size ); HELIUM_ASSERT( IsValid( pRequest->persistentResourceDataLoadId ) ); } } } if( IsInvalid( pRequest->persistentResourceDataLoadId ) ) { // No persistent resource data needs to be loaded. pObject->SetFlags( Asset::FLAG_PRELOADED ); pRequest->flags |= LOAD_FLAG_PERSISTENT_RESOURCE_PRELOADED; } // Asset is now preloaded. 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 ) ); HELIUM_ASSERT( !pRequest->spObject ); const Cache::Entry* pCacheEntry = pRequest->pEntry; HELIUM_ASSERT( pCacheEntry ); // Wait for the template and owner objects to load. AssetLoader* pAssetLoader = AssetLoader::GetInstance(); HELIUM_ASSERT( pAssetLoader ); if( IsValid( pRequest->ownerLoadIndex ) ) { size_t ownerLoadId = pRequest->ownerLoadIndex; if( IsValid( ownerLoadId ) && !pAssetLoader->TryFinishLoad( ownerLoadId, pRequest->spOwner ) ) { return false; } SetInvalid( pRequest->ownerLoadIndex ); if( !pRequest->spOwner ) { HELIUM_TRACE( TraceLevels::Error, "CachePackageLoader: Failed to load owner object for \"%s\".\n", *pCacheEntry->path.ToString() ); DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR; return true; } } Asset* pOwner = pRequest->spOwner; HELIUM_ASSERT( !pOwner || pOwner->IsFullyLoaded() ); Reflect::ObjectPtr cached_object = Cache::ReadCacheObjectFromBuffer( pRequest->pPropertyDataBegin, 0, pRequest->pPropertyDataEnd - pRequest->pPropertyDataBegin, pRequest->pResolver); AssetPtr assetPtr = Reflect::AssertCast<Asset>(cached_object); Asset::RenameParameters params; params.instanceIndex = -1; params.name = pCacheEntry->path.GetName(); params.spOwner = pRequest->spOwner; assetPtr->Rename(params); pRequest->spObject = assetPtr; Asset *pObject = assetPtr; HELIUM_ASSERT( pObject ); if (!cached_object.ReferencesObject()) { HELIUM_TRACE( TraceLevels::Error, "CachePackageLoader: Failed to deserialize object \"%s\".\n", *pCacheEntry->path.ToString() ); pObject->SetFlags( Asset::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->pPersistentResourceDataBegin, 0, (pRequest->pPersistentResourceDataEnd - pRequest->pPersistentResourceDataBegin), pRequest->pResolver); if (!cached_prd.ReferencesObject()) { HELIUM_TRACE( TraceLevels::Error, "CachePackageLoader: Failed to deserialize persistent resource data for \"%s\".\n", *pCacheEntry->path.ToString() ); } else { pResource->LoadPersistentResourceObject(cached_prd); } } } } DefaultAllocator().Free( pRequest->pAsyncLoadBuffer ); pRequest->pAsyncLoadBuffer = NULL; pObject->SetFlags( Asset::FLAG_PRELOADED ); pRequest->flags |= LOAD_FLAG_PRELOADED; // Asset is now preloaded. return true; }
void ForciblyFullyLoadedPackageManager::Tick() { AssetLoader *pAssetLoader = AssetLoader::GetStaticInstance(); // For each editable package for ( DynamicArray< ForciblyFullyLoadedPackage >::Iterator packageIter = m_ForciblyFullyLoadedPackages.Begin(); packageIter != m_ForciblyFullyLoadedPackages.End(); ++packageIter) { ForciblyFullyLoadedPackage &package = *packageIter; // Load the package if we need to if ( Helium::IsValid< size_t >( package.m_PackageLoadId ) ) { HELIUM_ASSERT( package.m_Assets.IsEmpty() ); HELIUM_ASSERT( package.m_AssetLoadIds.IsEmpty() ); HELIUM_ASSERT( package.m_AssetPaths.IsEmpty() ); HELIUM_ASSERT( !package.m_Package ); AssetPtr packagePtr; if ( pAssetLoader->TryFinishLoad( package.m_PackageLoadId, packagePtr ) ) { // Load request is finished. package.m_PackageLoadId = Helium::Invalid< size_t >(); package.m_Package = Reflect::AssertCast<Package>(packagePtr); if ( package.m_Package ) { if ( !package.m_Package->GetAllFlagsSet( Asset::FLAG_EDITOR_FORCIBLY_LOADED ) ) { // Package loaded successfully, queue load requests for all children package.m_Package->SetFlags( Asset::FLAG_EDITOR_FORCIBLY_LOADED ); e_AssetForciblyLoadedEvent.Raise( AssetEventArgs( package.m_Package ) ); } PackageLoader *pLoader = package.m_Package->GetLoader(); pLoader->EnumerateChildren( package.m_AssetPaths ); package.m_Assets.Resize( package.m_AssetPaths.GetSize() ); package.m_AssetLoadIds.Resize( package.m_AssetPaths.GetSize() ); DynamicArray< AssetPath >::Iterator assetPathIter = package.m_AssetPaths.Begin(); DynamicArray< size_t >::Iterator assetLoadIdIter = package.m_AssetLoadIds.Begin(); int i = 0; for ( ; assetPathIter != package.m_AssetPaths.End(); ++assetPathIter, ++assetLoadIdIter ) { *assetLoadIdIter = pAssetLoader->BeginLoadObject( *assetPathIter ); HELIUM_ASSERT( !package.m_Assets[i++] ); } } else { HELIUM_TRACE( TraceLevels::Warning, "Failed to load package '%s' for editor.", *package.m_PackagePath.ToString()); } } } } // For each editable package for ( DynamicArray< ForciblyFullyLoadedPackage >::Iterator packageIter = m_ForciblyFullyLoadedPackages.Begin(); packageIter != m_ForciblyFullyLoadedPackages.End(); ++packageIter) { ForciblyFullyLoadedPackage &package = *packageIter; // If the package is loaded if ( package.m_Package ) { // Load the child assets if we need to for ( int i = 0; i < package.m_AssetPaths.GetSize(); ++i ) { if ( Helium::IsValid<size_t>( package.m_AssetLoadIds[i] ) ) { HELIUM_ASSERT( !package.m_Assets[i] ); if ( pAssetLoader->TryFinishLoad( package.m_AssetLoadIds[i], package.m_Assets[i] ) ) { package.m_AssetLoadIds[i] = Invalid< size_t >(); if ( package.m_Assets[i] ) { // Asset loaded successfully if ( !package.m_Assets[i]->IsPackage() && !package.m_Assets[i]->GetAllFlagsSet( Asset::FLAG_EDITOR_FORCIBLY_LOADED ) ) { package.m_Assets[i]->SetFlags( Asset::FLAG_EDITOR_FORCIBLY_LOADED ); e_AssetForciblyLoadedEvent.Raise( AssetEventArgs( package.m_Assets[i] ) ); } } else { HELIUM_TRACE( TraceLevels::Warning, "Failed to asset '%s' for editor.", *package.m_PackagePath.ToString()); } } else { HELIUM_ASSERT( !package.m_Assets[i] ); } if ( Helium::IsValid<size_t>( package.m_AssetLoadIds[i] ) ) { HELIUM_ASSERT( !package.m_Assets[i] ); } } } } } }
/// @copydoc PackageLoader::TryFinishLoadObject() bool CachePackageLoader::TryFinishLoadObject( size_t requestId, AssetPtr& rspObject ) { HELIUM_ASSERT( requestId < m_loadRequests.GetSize() ); HELIUM_ASSERT( m_loadRequests.IsElementValid( requestId ) ); LoadRequest* pRequest = m_loadRequests[ requestId ]; HELIUM_ASSERT( pRequest ); if( !( pRequest->flags & LOAD_FLAG_PRELOADED ) ) { return false; } // Sync on template and owner dependencies. AssetLoader* pAssetLoader = AssetLoader::GetInstance(); HELIUM_ASSERT( pAssetLoader ); if( IsValid( pRequest->ownerLoadIndex ) ) { size_t linkLoadId = pRequest->ownerLoadIndex; if( IsValid( linkLoadId ) && !pAssetLoader->TryFinishLoad( linkLoadId, pRequest->spOwner ) ) { return false; } SetInvalid( pRequest->ownerLoadIndex ); } rspObject = pRequest->spObject; Asset* pObject = rspObject; if( pObject && ( pRequest->flags & LOAD_FLAG_ERROR ) ) { pObject->SetFlags( Asset::FLAG_BROKEN ); } if ( pObject->IsPackage() ) { Package *pPackage = Reflect::AssertCast<Package>( pObject ); pPackage->SetLoader( this ); } pRequest->spObject.Release(); HELIUM_ASSERT( IsInvalid( pRequest->asyncLoadId ) ); HELIUM_ASSERT( !pRequest->pAsyncLoadBuffer ); //pRequest->spTemplate.Release(); pRequest->spOwner.Release(); HELIUM_ASSERT( IsInvalid( pRequest->ownerLoadIndex ) ); //HELIUM_ASSERT( IsInvalid( pRequest->templateLoadIndex ) ); HELIUM_ASSERT( pObject || pRequest->pEntry ); HELIUM_TRACE( TraceLevels::Debug, "CachePackageLoader::TryFinishLoadObject(): Load request for \"%s\" (ID: %" PRIuSZ ") synced.\n", *( pObject ? pObject->GetPath() : pRequest->pEntry->path ).ToString(), requestId ); m_loadRequests.Remove( requestId ); m_loadRequestPool.Release( pRequest ); return true; }