Beispiel #1
0
/// 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;
}
Beispiel #3
0
/// @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;
}