Esempio n. 1
0
/// 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;
}
Esempio n. 2
0
/// @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;
}