예제 #1
0
/// Create a type object.
///
/// @param[in] name          Type name.
/// @param[in] pTypePackage  Package in which the template object should be stored.
/// @param[in] pParent       Parent type.
/// @param[in] pTemplate     Template object.
/// @param[in] flags         Type flags.
///
/// @return  Pointer to the type object if created successfully, null if not.
///
/// @see Unregister()
const GameObjectType* GameObjectType::Create(
    Name name,
    Package* pTypePackage,
    const GameObjectType* pParent,
    GameObject* pTemplate,
    RELEASE_STATIC_TYPE_CALLBACK* pReleaseStaticTypeCallback,
    uint32_t flags )
{
    HELIUM_ASSERT( !name.IsEmpty() );
    HELIUM_ASSERT( pTypePackage );
    HELIUM_ASSERT( pTemplate );
    HELIUM_ASSERT( pReleaseStaticTypeCallback );

    // Register the template object with the object system.
    if( !GameObject::RegisterObject( pTemplate ) )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            TXT( "GameObjectType::Initialize(): Failed to register type \"%s\" template object.\n" ),
            *name );

        return false;
    }

    // Set up the template object name, and set this object as its parent.
    GameObject::RenameParameters nameParameters;
    nameParameters.name = name;
    nameParameters.spOwner = pTypePackage;
    if( !pTemplate->Rename( nameParameters ) )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            TXT( "GameObjectType::Initialize(): Failed to set type \"%s\" template object name and owner.\n" ),
            *name );

        GameObject::UnregisterObject( pTemplate );

        return false;
    }

    // Flag the object as the default template object for the type being created.
    pTemplate->SetFlags( GameObject::FLAG_DEFAULT_TEMPLATE );

    // If the parent type is null, default to Reflect::Object, as the type should be deriving from it directly.
    const Reflect::Class* pBaseClass = pParent;
    if( !pBaseClass )
    {
        pBaseClass = Reflect::Object::s_Class;
        HELIUM_ASSERT( pBaseClass );
    }

    // Create the type object and store its parameters.
    GameObjectType* pType = new GameObjectType;
    HELIUM_ASSERT( pType );
    pType->m_Name = *name;
    pType->m_Size = static_cast< uint32_t >( pTemplate->GetInstanceSize() );
    pType->m_Base = pBaseClass;
    pType->Composite::m_Default = pType->m_Default = pTemplate;
    pType->m_cachedName = name;
    pType->m_pReleaseStaticTypeCallback = pReleaseStaticTypeCallback;
    pType->m_flags = flags;

    if( pParent )
    {
        pParent->AddDerived( pType );
    }

    // Lazily initialize the lookup map.  Note that this is not inherently thread-safe, but there should always be
    // at least one type registered before any sub-threads are spawned.
    if( !sm_pLookupMap )
    {
        sm_pLookupMap = new LookupMap;
        HELIUM_ASSERT( sm_pLookupMap );
    }

    // Register the type (note that a type with the same name should not already exist in the lookup map).
    LookupMap::Iterator typeIterator;
    HELIUM_VERIFY( sm_pLookupMap->Insert(
        typeIterator,
        KeyValue< Name, GameObjectTypePtr >( pType->GetName(), pType ) ) );

    Reflect::Registry* pRegistry = Reflect::Registry::GetInstance();
    HELIUM_ASSERT( pRegistry );
    pRegistry->RegisterType( pType );

    return pType;
}
예제 #2
0
/// 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;
}