/// 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;
}
Beispiel #2
0
/// Update processing of persistent resource data loading for a given load request.
///
/// @param[in] pRequest  Load request to process.
///
/// @return  True if persistent resource data loading for the given load request has completed, false if not.
bool LoosePackageLoader::TickPersistentResourcePreload( LoadRequest* pRequest )
{
	HELIUM_ASSERT( pRequest );
	HELIUM_ASSERT( !( pRequest->flags & LOAD_FLAG_PERSISTENT_RESOURCE_PRELOADED ) );

	Resource* pResource = Reflect::AssertCast< Resource >( pRequest->spObject.Get() );
	HELIUM_ASSERT( pResource );

	// Wait for the cached data load to complete.
	AsyncLoader& rAsyncLoader = AsyncLoader::GetStaticInstance();

	size_t bytesRead = 0;
	HELIUM_ASSERT( IsValid( pRequest->persistentResourceDataLoadId ) );
	if( !rAsyncLoader.TrySyncRequest( pRequest->persistentResourceDataLoadId, bytesRead ) )
	{
		return false;
	}

	SetInvalid( pRequest->persistentResourceDataLoadId );

	if( bytesRead != pRequest->cachedObjectDataBufferSize )
	{
		HELIUM_TRACE(
			TraceLevels::Warning,
			( TXT( "LoosePackageLoader: Requested load of %" ) PRIu32 TXT( " bytes from cached object data for " )
			TXT( "\"%s\", but only %" ) PRIuSZ TXT( " bytes were read.\n" ) ),
			pRequest->cachedObjectDataBufferSize,
			*pResource->GetPath().ToString(),
			bytesRead );
	}

	// Make sure we read enough bytes to cover the object property data size.
	if( bytesRead < sizeof( uint32_t ) )
	{
		HELIUM_TRACE(
			TraceLevels::Error,
			( TXT( "LoosePackageLoader: Not enough bytes read of cached object data \"%s\" from which to parse the " )
			TXT( "property stream size.\n" ) ),
			*pResource->GetPath().ToString() );

		pRequest->flags |= LOAD_FLAG_ERROR;
	}
	else
	{
		// Skip over the object property data.
		uint8_t* pCachedObjectData = pRequest->pCachedObjectDataBuffer;
		HELIUM_ASSERT( pCachedObjectData );

		uint32_t propertyDataSize = *reinterpret_cast< uint32_t* >( pCachedObjectData );

		size_t byteSkipCount = sizeof( propertyDataSize ) + propertyDataSize;
		if( byteSkipCount > bytesRead )
		{
			HELIUM_TRACE(
				TraceLevels::Error,
				( TXT( "LoosePackageLoader: Cached persistent resource data for \"%s\" extends past the end of the " )
				TXT( "cached data stream.\n" ) ),
				*pResource->GetPath().ToString() );

			pRequest->flags |= LOAD_FLAG_ERROR;
		}
		else
		{
			pCachedObjectData += byteSkipCount;
			size_t bytesRemaining = bytesRead - byteSkipCount;

			// Make sure we have enough bytes at the end for the resource sub-data count.
			if( bytesRemaining < sizeof( uint32_t ) )
			{
				HELIUM_TRACE(
					TraceLevels::Error,
					( TXT( "LoosePackageLoader: Not enough space is reserved in the cached persistent resource " )
					TXT( "data stream for \"%s\" for the resource sub-data count.\n" ) ),
					*pResource->GetPath().ToString() );

				pRequest->flags |= LOAD_FLAG_ERROR;
			}
			else
			{
				bytesRemaining -= sizeof( uint32_t );

				//// Deserialize the persistent resource data.
				//// Having to do this copy is unfortunate.. maybe we can revisit this later
				//std::stringstream ss_in;
				//ss_in.write(reinterpret_cast<char *>(pCachedObjectData), bytesRemaining);

				//Reflect::ArchiveBinary archive(new Reflect::CharStream(&ss_in, false, Helium::ByteOrders::LittleEndian, Helium::Reflect::CharacterEncodings::UTF_16), false);
			   
				//Reflect::ObjectPtr persistent_data;
				//archive.ReadSingleObject(persistent_data);

				Reflect::ObjectPtr persistent_data;
				persistent_data = Cache::ReadCacheObjectFromBuffer(pCachedObjectData, /*sizeof( uint32_t )*/ 0, bytesRemaining, pRequest->pResolver);

				if (!pResource->LoadPersistentResourceObject(persistent_data))
				{
					HELIUM_TRACE(
						TraceLevels::Error,
						( TXT( "LoosePackageLoader: Failed to load persistent resource object for \"%s\".\n" ) ),
						*pResource->GetPath().ToString() );

					pRequest->flags |= LOAD_FLAG_ERROR;
				}
			}
		}
	}

	DefaultAllocator().Free( pRequest->pCachedObjectDataBuffer );
	pRequest->pCachedObjectDataBuffer = NULL;
	pRequest->cachedObjectDataBufferSize = 0;

	pResource->SetFlags( Asset::FLAG_PRELOADED );

	pRequest->flags |= LOAD_FLAG_PERSISTENT_RESOURCE_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 ) );

    GameObject* pObject = pRequest->spObject;

    const Cache::Entry* pCacheEntry = pRequest->pEntry;
    HELIUM_ASSERT( pCacheEntry );

    // Wait for the template and owner objects to load.
    GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
    HELIUM_ASSERT( pObjectLoader );

    if( IsValid( pRequest->templateLinkIndex ) )
    {
        HELIUM_ASSERT( pRequest->templateLinkIndex < pRequest->objectLinkTable.GetSize() );
        size_t templateLoadId = pRequest->objectLinkTable[ pRequest->templateLinkIndex ];
        if( IsValid( templateLoadId ) && !pObjectLoader->TryFinishLoad( templateLoadId, pRequest->spTemplate ) )
        {
            return false;
        }

        SetInvalid( pRequest->templateLinkIndex );

        if( !pRequest->spTemplate )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Failed to load template object for \"%s\".\n" ),
                *pCacheEntry->path.ToString() );

            if( pObject )
            {
                pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED );
                pObject->ConditionalFinalizeLoad();
            }

            DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
            pRequest->pAsyncLoadBuffer = NULL;

            pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR;

            return true;
        }
    }

    GameObject* pTemplate = pRequest->spTemplate;

    if( IsValid( pRequest->ownerLinkIndex ) )
    {
        HELIUM_ASSERT( pRequest->ownerLinkIndex < pRequest->objectLinkTable.GetSize() );
        size_t ownerLoadId = pRequest->objectLinkTable[ pRequest->ownerLinkIndex ];
        if( IsValid( ownerLoadId ) && !pObjectLoader->TryFinishLoad( ownerLoadId, pRequest->spOwner ) )
        {
            return false;
        }

        SetInvalid( pRequest->ownerLinkIndex );

        if( !pRequest->spOwner )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Failed to load owner object for \"%s\".\n" ),
                *pCacheEntry->path.ToString() );

            if( pObject )
            {
                pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED );
                pObject->ConditionalFinalizeLoad();
            }

            DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
            pRequest->pAsyncLoadBuffer = NULL;

            pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR;

            return true;
        }
    }

    GameObject* pOwner = pRequest->spOwner;

    HELIUM_ASSERT( !pOwner || pOwner->IsFullyLoaded() );
    HELIUM_ASSERT( !pTemplate || pTemplate->IsFullyLoaded() );

    GameObjectType* pType = pRequest->spType;
    HELIUM_ASSERT( pType );

    // If we already had an existing object, make sure the type and template match.
    if( pObject )
    {
        const GameObjectType* pExistingType = pObject->GetGameObjectType();
        HELIUM_ASSERT( pExistingType );
        if( pExistingType != pType )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                ( TXT( "CachePackageLoader: Cannot load \"%s\" using the existing object as the types do not " )
                TXT( "match (existing type: \"%s\"; serialized type: \"%s\".\n" ) ),
                *pCacheEntry->path.ToString(),
                *pExistingType->GetName(),
                *pType->GetName() );

            pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED );
            pObject->ConditionalFinalizeLoad();

            DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
            pRequest->pAsyncLoadBuffer = NULL;

            pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR;

            return true;
        }
    }
    else
    {
        // Create the object.
        if( !GameObject::CreateObject( pRequest->spObject, pType, pCacheEntry->path.GetName(), pOwner, pTemplate ) )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Failed to create \"%s\" during loading.\n" ),
                *pCacheEntry->path.ToString() );

            DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
            pRequest->pAsyncLoadBuffer = NULL;

            pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR;

            return true;
        }

        pObject = pRequest->spObject;
        HELIUM_ASSERT( pObject );
    }
        
    Reflect::ObjectPtr cached_object = Cache::ReadCacheObjectFromBuffer(pRequest->pSerializedData, 0, pRequest->pPropertyStreamEnd - pRequest->pSerializedData);

    if (!cached_object.ReferencesObject())
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: Failed to deserialize object \"%s\".\n" ),
            *pCacheEntry->path.ToString() );

        // Clear out object references (object can now be considered fully loaded as well).
        // pmd - Not sure that we need to do this.. but if we do, just use this visitor
        //ClearLinkIndicesFromObject clifo_visitor;
        //pObject->Accept(clifo_visitor);
        pObject->SetFlags( GameObject::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->pPropertyStreamEnd, 
                    0, 
                    (pRequest->pPersistentResourceStreamEnd - pRequest->pPropertyStreamEnd));

                if (!cached_prd.ReferencesObject())
                {
                    HELIUM_TRACE(
                        TraceLevels::Error,
                        ( TXT( "CachePackageLoader: Failed to deserialize persistent resource " )
                        TXT( "data for \"%s\".\n" ) ),
                        *pCacheEntry->path.ToString() );
                }
                else
                {
                    pResource->LoadPersistentResourceObject(cached_prd);
                }
            }
        }
    }

    DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
    pRequest->pAsyncLoadBuffer = NULL;

    pObject->SetFlags( GameObject::FLAG_PRELOADED );

    pRequest->flags |= LOAD_FLAG_PRELOADED;

    // GameObject is now preloaded.
    return true;
}