diff --git a/Generals/Code/GameEngine/Include/GameLogic/Object.h b/Generals/Code/GameEngine/Include/GameLogic/Object.h index 28a5e2bfc5..39f60e21c8 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Object.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Object.h @@ -166,6 +166,10 @@ class Object : public Thing, public Snapshot Object* getNextObject() { return m_next; } const Object* getNextObject() const { return m_next; } + Object* getPrevObject() { return m_prev; } + const Object* getPrevObject() const { return m_prev; } + void friend_setNextObject(Object* obj) { m_next = obj; } + void friend_setPrevObject(Object* obj) { m_prev = obj; } void updateObjValuesFromMapProperties(Dict* properties); ///< Brings in properties set in the editor. diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 855d094270..54620233cc 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -4241,13 +4241,14 @@ void GameLogic::prepareLogicForObjectLoad( void ) * this version breaks compatibility with previous versions. (CBD) * 5: Added xfering the BuildAssistant's sell list. * 9: Added m_rankPointsToAddAtGameStart, or else on a load game, your RestartGame button will forget your exp + * 10: TheSuperHackers @tweak Save objects in reverse order so they load in correct order. Reverse object list for old saves. */ // ------------------------------------------------------------------------------------------------ void GameLogic::xfer( Xfer *xfer ) { // version - const XferVersion currentVersion = 9; + const XferVersion currentVersion = 10; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -4281,7 +4282,13 @@ void GameLogic::xfer( Xfer *xfer ) if( xfer->getXferMode() == XFER_SAVE ) { + // TheSuperHackers @fix bobtista 27/01/2026 Save objects in reverse order (newest first) + // so they load in the correct order (oldest objects at head of list). + Object *lastObj = nullptr; for( obj = getFirstObject(); obj; obj = obj->getNextObject() ) + lastObj = obj; + + for( obj = lastObj; obj; obj = obj->getPrevObject() ) { // get the object TOC entry for this template @@ -4364,6 +4371,25 @@ void GameLogic::xfer( Xfer *xfer ) } + // TheSuperHackers @fix bobtista 27/01/2026 Reverse object list for old saves. + // Old saves stored objects oldest-first, which results in reversed order when loaded + // since objects are prepended during creation. Version 10+ saves in reverse order. + if ( version <= 9 ) + { + Object *prev = nullptr; + Object *current = m_objList; + Object *next = nullptr; + while ( current != nullptr ) + { + next = current->getNextObject(); + current->friend_setNextObject( prev ); + current->friend_setPrevObject( next ); + prev = current; + current = next; + } + m_objList = prev; + } + } // campaign info diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h index 5c2851ef7b..78451396fc 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Object.h @@ -172,6 +172,10 @@ class Object : public Thing, public Snapshot Object* getNextObject() { return m_next; } const Object* getNextObject() const { return m_next; } + Object* getPrevObject() { return m_prev; } + const Object* getPrevObject() const { return m_prev; } + void friend_setNextObject(Object* obj) { m_next = obj; } + void friend_setPrevObject(Object* obj) { m_prev = obj; } void updateObjValuesFromMapProperties(Dict* properties); ///< Brings in properties set in the editor. diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 569b01943c..a4a8b1c583 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -4801,13 +4801,14 @@ void GameLogic::prepareLogicForObjectLoad( void ) * 5: Added xfering the BuildAssistant's sell list. * 9: Added m_rankPointsToAddAtGameStart, or else on a load game, your RestartGame button will forget your exp * 10: xfer m_superweaponRestriction + * 11: TheSuperHackers @tweak Save objects in reverse order so they load in correct order */ // ------------------------------------------------------------------------------------------------ void GameLogic::xfer( Xfer *xfer ) { // version - const XferVersion currentVersion = 10; + const XferVersion currentVersion = 11; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); @@ -4840,8 +4841,13 @@ void GameLogic::xfer( Xfer *xfer ) ObjectTOCEntry *tocEntry; if( xfer->getXferMode() == XFER_SAVE ) { - + // TheSuperHackers @fix bobtista 27/01/2026 Save objects in reverse order (newest first) + // so they load in the correct order (oldest objects at head of list). + Object *lastObj = nullptr; for( obj = getFirstObject(); obj; obj = obj->getNextObject() ) + lastObj = obj; + + for( obj = lastObj; obj; obj = obj->getPrevObject() ) { // get the object TOC entry for this template @@ -4924,6 +4930,25 @@ void GameLogic::xfer( Xfer *xfer ) } + // TheSuperHackers @fix bobtista 27/01/2026 Reverse object list for old saves. + // Old saves stored objects oldest-first, which results in reversed order when loaded + // since objects are prepended during creation. Version 11+ saves in reverse order. + if ( version <= 10 ) + { + Object *prev = nullptr; + Object *current = m_objList; + Object *next = nullptr; + while ( current != nullptr ) + { + next = current->getNextObject(); + current->friend_setNextObject( prev ); + current->friend_setPrevObject( next ); + prev = current; + current = next; + } + m_objList = prev; + } + } // campaign info