bool ConsoleGame::Init() { //Initialise the RuntimeObjectSystem m_pRuntimeObjectSystem = new RuntimeObjectSystem; m_pCompilerLogger = new StdioLogSystem(); if( !m_pRuntimeObjectSystem->Initialise(m_pCompilerLogger, 0) ) { m_pRuntimeObjectSystem = 0; return false; } m_pRuntimeObjectSystem->GetObjectFactorySystem()->AddListener(this); // construct first object IObjectConstructor* pCtor = m_pRuntimeObjectSystem->GetObjectFactorySystem()->GetConstructor( "RuntimeObject01" ); if( pCtor ) { IObject* pObj = pCtor->Construct(); pObj->GetInterface( &m_pUpdateable ); if( 0 == m_pUpdateable ) { delete pObj; m_pCompilerLogger->LogError("Error - no updateable interface found\n"); return false; } m_ObjectId = pObj->GetObjectId(); } return true; }
void Game::DeleteObjects() { m_pConsole->DestroyContext(); delete IObjectUtils::GetUniqueObject( "MainObject" ); #ifdef _DEBUG // Do a check to verify that all objects have been destroyed at this point int totalObjectCount = 0; AUDynArray<IObjectConstructor*> constructors; m_pEnv->sys->pObjectFactorySystem->GetAll(constructors); for (size_t i=0; i<constructors.Size(); ++i) { IObjectConstructor* pConstructor = constructors[i]; size_t count = pConstructor->GetNumberConstructedObjects(); // Need to iterate through all objects and check if they're valid // since GetNumConstructedObjects isn't accurate, can return some null pointers for (size_t j=0; j<count; ++j) { if (pConstructor->GetConstructedObject(j) != NULL) { totalObjectCount++; } } // Do an assert check here so it's easy to figure out which object type wasn't deleted AU_ASSERT( totalObjectCount == 0 ); } #endif }
IObject* ObjectFactorySystem::GetObject( ObjectId id ) const { IObjectConstructor* pConstructor = ObjectFactorySystem::GetConstructor( id.m_ConstructorId ); if( pConstructor ) { return pConstructor->GetConstructedObject( id.m_PerTypeId ); } return 0; }
void ObjectFactorySystem::ProtectedObjectSwapper::ProtectedFunc() { m_ProtectedPhase = PHASE_SERIALIZEOUT; // serialize all out if( m_pLogger ) m_pLogger->LogInfo( "Serializing out from %d old constructors...", (int)m_ConstructorsOld.size()); // use a temporary serializer in case there is an exception, so preserving any old state (if there is any) m_Serializer.SetIsLoading( false ); for( size_t i = 0; i < m_ConstructorsOld.size(); ++i ) { IObjectConstructor* pOldConstructor = m_ConstructorsOld[i]; size_t numObjects = pOldConstructor->GetNumberConstructedObjects(); for( size_t j = 0; j < numObjects; ++j ) { IObject* pOldObject = pOldConstructor->GetConstructedObject( j ); if (pOldObject) { m_Serializer.Serialize( pOldObject ); } } } // swap serializer if( m_pLogger ) m_pLogger->LogInfo( "Swapping in and creating objects for %d new constructors...", (int)m_ConstructorsToAdd.size()); m_ProtectedPhase = PHASE_CONSTRUCTNEW; TConstructors& constructorsNew = m_pObjectFactorySystem->m_Constructors; std::vector<IObject*> old_objects; //swap old constructors with new ones and create new objects for( size_t i = 0; i < m_ConstructorsToAdd.size(); ++i ) { IObjectConstructor* pConstructor = m_ConstructorsToAdd[i]; //replace constructor, but if one exists then replace objects IObjectConstructor* pOldConstructor = m_pObjectFactorySystem->GetConstructor( pConstructor->GetName() ); if( pOldConstructor == pConstructor ) { // don't add constructor if it's already in existance continue; } // Reconstruct objects, starting at end to reduce overhead in factory container if( pOldConstructor ) { // replace and construct pConstructor->SetConstructorId( pOldConstructor->GetConstructorId() ); constructorsNew[ pConstructor->GetConstructorId() ] = pConstructor; for( PerTypeObjectId objId = 0; objId < pOldConstructor->GetNumberConstructedObjects(); ++ objId ) { // create new object if(IObject* old_object = pOldConstructor->GetConstructedObject( objId ) ) { old_objects.push_back(old_object); auto state = pOldConstructor->GetState(objId); pConstructor->Construct(state); } else { pConstructor->ConstructNull(); } } m_ConstructorsReplaced.push_back( pOldConstructor ); } else { ConstructorId id = constructorsNew.size(); m_pObjectFactorySystem->m_ConstructorIds[ pConstructor->GetName() ] = id; constructorsNew.push_back( pConstructor ); pConstructor->SetConstructorId( id ); } } if( m_pLogger ) m_pLogger->LogInfo( "Serialising in..."); //serialize back m_ProtectedPhase = PHASE_SERIALIZEIN; m_Serializer.SetIsLoading( true ); for( size_t i = 0; i < constructorsNew.size(); ++i ) { IObjectConstructor* pConstructor = constructorsNew[i]; for( PerTypeObjectId objId = 0; objId < pConstructor->GetNumberConstructedObjects(); ++ objId ) { // Serialize new object IObject* pObject = pConstructor->GetConstructedObject( objId ); if (pObject) { m_Serializer.Serialize( pObject ); } } } // auto construct singletons // now in 2 phases - construct then init m_ProtectedPhase = PHASE_AUTOCONSTRUCTSINGLETONS; std::vector<bool> bSingletonConstructed( constructorsNew.size(), false ); if( m_pLogger ) m_pLogger->LogInfo( "Auto Constructing Singletons..."); for( size_t i = 0; i < constructorsNew.size(); ++i ) { IObjectConstructor* pConstructor = constructorsNew[i]; if( pConstructor->GetIsAutoConstructSingleton() ) { if( 0 == pConstructor->GetNumberConstructedObjects() ) { pConstructor->GetSingleton(); bSingletonConstructed[i] = true; } } } // Do a second pass, initializing objects now that they've all been serialized // and testing serialization if required m_ProtectedPhase = PHASE_INITANDSERIALIZEOUTTEST; if( m_bTestSerialization ) { if( m_pLogger ) m_pLogger->LogInfo( "Initialising and testing new serialisation..."); } else { if( m_pLogger ) m_pLogger->LogInfo( "Initialising..."); } for( size_t i = 0; i < constructorsNew.size(); ++i ) { IObjectConstructor* pConstructor = constructorsNew[i]; for( PerTypeObjectId objId = 0; objId < pConstructor->GetNumberConstructedObjects(); ++ objId ) { IObject* pObject = pConstructor->GetConstructedObject( objId ); if (pObject) { // if a singleton was newly constructed in earlier phase, pass true to init. pObject->Init( bSingletonConstructed[i] ); if( m_bTestSerialization && ( m_ConstructorsOld.size() <= i || m_ConstructorsOld[ i ] != constructorsNew[ i ] ) ) { //test serialize out for all new objects, we assume old objects are OK. SimpleSerializer tempSerializer; tempSerializer.SetIsLoading( false ); tempSerializer.Serialize( pObject ); } } } } m_ProtectedPhase = PHASE_DELETEOLD; //delete old objects which have been replaced for(auto pOldObject: old_objects) { pOldObject->_isRuntimeDelete = true; delete pOldObject; } }
void ObjectFactorySystem::CompleteConstructorSwap( ProtectedObjectSwapper& swapper ) { if( swapper.HasHadException() && PHASE_DELETEOLD != swapper.m_ProtectedPhase ) { if( m_pLogger ) { m_pLogger->LogError( "Exception during object swapping, switching back to previous objects." ); switch( swapper.m_ProtectedPhase ) { case PHASE_NONE: AU_ASSERT( false ); break; case PHASE_SERIALIZEOUT: m_pLogger->LogError( "\tError occured during serialize out old objects phase." ); break; case PHASE_CONSTRUCTNEW: m_pLogger->LogError( "\tError occured during constructing new objects phase." ); break; case PHASE_SERIALIZEIN: m_pLogger->LogError( "\tError occured during serialize into the new objects phase." ); break; case PHASE_AUTOCONSTRUCTSINGLETONS: m_pLogger->LogError( "\tError occured during auto construct singletons phase." ); break; case PHASE_INITANDSERIALIZEOUTTEST: if( m_bTestSerialization ) { m_pLogger->LogError( "\tError occured during Initialization and serialize test of new objects phase." ); } else { m_pLogger->LogError( "\tError occured during Initialization phase." ); } break; case PHASE_DELETEOLD: break; } } //swap back to new constructors before everything is serialized back in m_Constructors = swapper.m_ConstructorsOld; if( PHASE_SERIALIZEOUT != swapper.m_ProtectedPhase ) { //serialize back with old objects - could cause exception which isn't handled, but hopefully not. swapper.m_Serializer.SetIsLoading( true ); for( size_t i = 0; i < m_Constructors.size(); ++i ) { IObjectConstructor* pConstructor = m_Constructors[i]; for( PerTypeObjectId objId = 0; objId < pConstructor->GetNumberConstructedObjects(); ++ objId ) { // Iserialize new object IObject* pObject = pConstructor->GetConstructedObject( objId ); if (pObject) { swapper.m_Serializer.Serialize( pObject ); } } } // Do a second pass, initializing objects now that they've all been serialized for( size_t i = 0; i < m_Constructors.size(); ++i ) { IObjectConstructor* pConstructor = m_Constructors[i]; for( PerTypeObjectId objId = 0; objId < pConstructor->GetNumberConstructedObjects(); ++ objId ) { IObject* pObject = pConstructor->GetConstructedObject( objId ); if (pObject) { pObject->Init(false); } } } } } else { if( m_pLogger ) m_pLogger->LogInfo( "Object swap completed"); if( swapper.HasHadException() && PHASE_DELETEOLD == swapper.m_ProtectedPhase ) { if( m_pLogger ) m_pLogger->LogError( "Exception during object destruction of old objects, leaking." ); } } // Notify any listeners that constructors have changed TObjectFactoryListeners::iterator it = m_Listeners.begin(); TObjectFactoryListeners::iterator itEnd = m_Listeners.end(); while (it != itEnd) { (*it)->OnConstructorsAdded(); ++it; } }