/// Find an object based on its path name. /// /// @param[in] path FilePath of the object to locate. /// /// @return Pointer to the object if found, null pointer if not found. GameObject* GameObject::FindObject( GameObjectPath path ) { // Make sure the path isn't empty. if( path.IsEmpty() ) { return NULL; } // Assemble a list of object names and instance indices, from the top level on down. size_t pathDepth = 0; size_t packageDepth = 0; for( GameObjectPath testPath = path; !testPath.IsEmpty(); testPath = testPath.GetParent() ) { ++pathDepth; if( testPath.IsPackage() ) { ++packageDepth; } } StackMemoryHeap<>& rStackHeap = ThreadLocalStackAllocator::GetMemoryHeap(); StackMemoryHeap<>::Marker stackMarker( rStackHeap ); Name* pPathNames = static_cast< Name* >( rStackHeap.Allocate( sizeof( Name ) * pathDepth ) ); HELIUM_ASSERT( pPathNames ); uint32_t* pInstanceIndices = static_cast< uint32_t* >( rStackHeap.Allocate( sizeof( uint32_t ) * pathDepth ) ); HELIUM_ASSERT( pInstanceIndices ); size_t pathIndex = pathDepth; for( GameObjectPath testPath = path; !testPath.IsEmpty(); testPath = testPath.GetParent() ) { HELIUM_ASSERT( pathIndex != 0 ); --pathIndex; pPathNames[ pathIndex ] = testPath.GetName(); pInstanceIndices[ pathIndex ] = testPath.GetInstanceIndex(); } HELIUM_ASSERT( pathIndex == 0 ); // Search from the root. return FindChildOf( NULL, pPathNames, pInstanceIndices, pathDepth, packageDepth ); }
/// @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; }
/// @copydoc GameObjectLoader::CacheObject() bool EditorObjectLoader::CacheObject( GameObject* pObject, bool bEvictPlatformPreprocessedResourceData ) { HELIUM_ASSERT( pObject ); // Don't cache broken objects or packages. if( pObject->GetAnyFlagSet( GameObject::FLAG_BROKEN ) || pObject->IsPackage() ) { return false; } // Make sure we have an object preprocessor instance with which to cache the object. ObjectPreprocessor* pObjectPreprocessor = ObjectPreprocessor::GetStaticInstance(); if( !pObjectPreprocessor ) { HELIUM_TRACE( TRACE_WARNING, TXT( "EditorObjectLoader::CacheObject(): Missing ObjectPreprocessor to use for caching.\n" ) ); return false; } // Configuration objects should not be cached. GameObjectPath objectPath = pObject->GetPath(); Config& rConfig = Config::GetStaticInstance(); GameObjectPath configPackagePath = rConfig.GetConfigContainerPackagePath(); HELIUM_ASSERT( !configPackagePath.IsEmpty() ); for( GameObjectPath testPath = objectPath; !testPath.IsEmpty(); testPath = testPath.GetParent() ) { if( testPath == configPackagePath ) { return false; } } // Get the timestamp for the object based on the timestamp of its source package file and, if it's a resource, // the timestamp of the source resource file. GameObject* pPackageObject; for( pPackageObject = pObject; pPackageObject && !pPackageObject->IsPackage(); pPackageObject = pPackageObject->GetOwner() ) { } HELIUM_ASSERT( pPackageObject ); PackageLoader* pPackageLoader = Reflect::AssertCast< Package >( pPackageObject )->GetLoader(); HELIUM_ASSERT( pPackageLoader ); HELIUM_ASSERT( pPackageLoader->IsSourcePackageFile() ); int64_t objectTimestamp = pPackageLoader->GetFileTimestamp(); if( !pObject->IsDefaultTemplate() ) { Resource* pResource = Reflect::SafeCast< Resource >( pObject ); if( pResource ) { GameObjectPath baseResourcePath = pResource->GetPath(); HELIUM_ASSERT( !baseResourcePath.IsPackage() ); for( ; ; ) { GameObjectPath parentPath = baseResourcePath.GetParent(); if( parentPath.IsEmpty() || parentPath.IsPackage() ) { break; } baseResourcePath = parentPath; } Path sourceFilePath; if ( !File::GetDataDirectory( sourceFilePath ) ) { HELIUM_TRACE( TRACE_WARNING, TXT( "EditorObjectLoader::CacheObject(): Could not obtain data directory.\n" ) ); return false; } sourceFilePath += baseResourcePath.ToFilePathString().GetData(); int64_t sourceFileTimestamp = sourceFilePath.ModifiedTime(); if( sourceFileTimestamp > objectTimestamp ) { objectTimestamp = sourceFileTimestamp; } } } // Cache the object. bool bSuccess = pObjectPreprocessor->CacheObject( pObject, objectTimestamp, bEvictPlatformPreprocessedResourceData ); if( !bSuccess ) { HELIUM_TRACE( TRACE_ERROR, TXT( "EditorObjectLoader: Failed to cache object \"%s\".\n" ), *objectPath.ToString() ); } return bSuccess; }