const FilePath *Helium::Asset::GetAssetFileSystemPath() { HELIUM_ASSERT( !m_path.IsEmpty() ); FilePath filePath; Asset *pSourceAsset = GetSourceAsset(); if (pSourceAsset) { Package *pPackage = Reflect::SafeCast<Package>( pSourceAsset->GetOwner() ); if ( pPackage ) { PackageLoader *pLoader = pPackage->GetLoader(); HELIUM_ASSERT( pLoader->HasAssetFileState() ); if ( pLoader ) { return &pLoader->GetAssetFileSystemPath( pSourceAsset->GetPath() ); } } } return NULL; }
int64_t AssetLoader::GetAssetFileTimestamp( const AssetPath &path ) { Package *pPackage = Asset::Find<Package>( path.GetParent() ); HELIUM_ASSERT( pPackage ); PackageLoader *pLoader = pPackage->GetLoader(); HELIUM_ASSERT( pLoader ); return pLoader->GetAssetFileSystemTimestamp( path ); }
bool Helium::Asset::SaveAsset() { Package *pPackage = GetOwningPackage(); if ( pPackage ) { PackageLoader *pLoader = pPackage->GetLoader(); if ( pLoader ) { pLoader->SaveAsset( this ); return true; } } return false; }
void ProjectPanel::OnSave( wxCommandEvent& event ) { wxDataViewItemArray selection; int numSelected = m_DataViewCtrl->GetSelections( selection ); for (int i = 0; i < numSelected; ++i) { Asset *pAsset = static_cast<Asset *>( selection[i].GetID() ); Package *pPackage = pAsset->GetOwningPackage(); HELIUM_ASSERT( pPackage ); PackageLoader *pPackageLoader = pPackage->GetLoader(); HELIUM_ASSERT( pPackageLoader ); pPackageLoader->SaveAsset( pAsset ); } }
uint64_t Helium::Asset::GetAssetFileTimeStamp() { HELIUM_ASSERT( !m_path.IsEmpty() ); uint64_t timestamp = 0; Asset *pSourceAsset = GetSourceAsset(); if (pSourceAsset) { Package *pPackage = Reflect::SafeCast<Package>( pSourceAsset->GetOwner() ); if ( pPackage ) { PackageLoader *pLoader = pPackage->GetLoader(); HELIUM_ASSERT( pLoader->HasAssetFileState() ); if ( pLoader ) { pLoader->GetAssetFileSystemTimestamp( pSourceAsset->GetPath() ); } } } return timestamp; }
/// 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 ); }
/// Initialize this package loader. /// /// @param[in] packagePath Asset path of the package to load. /// /// @return True if this loader was initialized successfully, false if not. /// /// @see Shutdown() bool LoosePackageLoader::Initialize( AssetPath packagePath ) { Shutdown(); // Make sure the path represents a package. if( packagePath.IsEmpty() ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader::Initialize(): Empty package path specified.\n" ) ); return false; } HELIUM_TRACE( TraceLevels::Debug, TXT( "LoosePackageLoader::Initialize(): Initializing loader for package \"%s\".\n" ), *packagePath.ToString() ); if( !packagePath.IsPackage() ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader::Initialize(): \"%s\" does not represent a package path.\n" ), *packagePath.ToString() ); return false; } // Store the package path. m_packagePath = packagePath; // Attempt to locate the specified package if it already happens to exist. m_spPackage = Asset::Find< Package >( packagePath ); Package* pPackage = m_spPackage; if( pPackage ) { if( pPackage->GetLoader() ) { HELIUM_TRACE( TraceLevels::Error, TXT( "LoosePackageLoader::Initialize(): Package \"%s\" already has a loader.\n" ), *packagePath.ToString() ); m_spPackage.Release(); return false; } pPackage->SetLoader( this ); } else { // Make sure we don't have a name clash with a non-package object. AssetPtr spObject( Asset::FindObject( packagePath ) ); if( spObject ) { HELIUM_ASSERT( !spObject->IsPackage() ); HELIUM_TRACE( TraceLevels::Error, ( TXT( "PackageLoader::Initialize(): Package loader cannot be initialized for \"%s\", as an " ) TXT( "object with the same name exists that is not a package.\n" ) ), *packagePath.ToString() ); return false; } } // Build the package file path. If the package is a user configuration package, use the user data directory, // otherwise use the global data directory. Config& rConfig = Config::GetStaticInstance(); FilePath dataDirectory; if ( !FileLocations::GetDataDirectory( dataDirectory ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "PackageLoader::Initialize(): Could not obtain user data directory." ) ); return false; } // Set up to read the TOC (which may not exist) //SetInvalid( m_packageTocFileSize ); // First do this check without a trailing "/" so that FilePath has to actually look at the file system FilePath package_dir = dataDirectory + packagePath.ToFilePathString().GetData(); if (!package_dir.Exists()) { // Some packages like types or uninitialized user config packages may not exist on file system m_packageDirPath = package_dir + TXT("/"); return true; } if (!package_dir.IsDirectory()) { // Packages should not be files return false; } // But internally we will store this m_packageDirPath = package_dir + TXT("/"); return true; }