diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp index f46cb876301..9e8cc41dbac 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp @@ -34,6 +34,7 @@ #include "Common/GameEngine.h" #include "Common/GameState.h" #include "Common/GameStateMap.h" +#include "Common/GlobalData.h" #include "Common/LatchRestore.h" #include "Common/MapObject.h" #include "Common/PlayerList.h" @@ -563,7 +564,8 @@ SaveCode GameState::saveGame( AsciiString filename, UnicodeString desc, xferSave.open( filepath ); } catch(...) { // print error message to the user - TheInGameUI->message( "GUI:Error" ); + if (TheGlobalData && !TheGlobalData->m_headless) + TheInGameUI->message( "GUI:Error" ); DEBUG_LOG(( "Error opening file '%s'", filepath.str() )); return SC_ERROR; } @@ -593,13 +595,16 @@ SaveCode GameState::saveGame( AsciiString filename, UnicodeString desc, catch( ... ) { - UnicodeString ufilepath; - ufilepath.translate(filepath); + if (TheGlobalData && !TheGlobalData->m_headless) + { + UnicodeString ufilepath; + ufilepath.translate(filepath); - UnicodeString msg; - msg.format( TheGameText->fetch("GUI:ErrorSavingGame"), ufilepath.str() ); + UnicodeString msg; + msg.format( TheGameText->fetch("GUI:ErrorSavingGame"), ufilepath.str() ); - MessageBoxOk(TheGameText->fetch("GUI:Error"), msg, nullptr); + MessageBoxOk(TheGameText->fetch("GUI:Error"), msg, nullptr); + } // close the file and get out of here xferSave.close(); @@ -611,8 +616,11 @@ SaveCode GameState::saveGame( AsciiString filename, UnicodeString desc, xferSave.close(); // print message to the user for game successfully saved - UnicodeString msg = TheGameText->fetch( "GUI:GameSaveComplete" ); - TheInGameUI->message( msg ); + if (TheGlobalData && !TheGlobalData->m_headless) + { + UnicodeString msg = TheGameText->fetch( "GUI:GameSaveComplete" ); + TheInGameUI->message( msg ); + } return SC_OK; @@ -719,13 +727,16 @@ SaveCode GameState::loadGame( AvailableGameInfo gameInfo ) TheGameEngine->reset(); // print error message to the user - UnicodeString ufilepath; - ufilepath.translate(filepath); + if (TheGlobalData && !TheGlobalData->m_headless) + { + UnicodeString ufilepath; + ufilepath.translate(filepath); - UnicodeString msg; - msg.format( TheGameText->fetch("GUI:ErrorLoadingGame"), ufilepath.str() ); + UnicodeString msg; + msg.format( TheGameText->fetch("GUI:ErrorLoadingGame"), ufilepath.str() ); - MessageBoxOk(TheGameText->fetch("GUI:Error"), msg, nullptr); + MessageBoxOk(TheGameText->fetch("GUI:Error"), msg, nullptr); + } return SC_INVALID_DATA; // you can't use a naked "throw" outside of a catch statement! @@ -1365,6 +1376,24 @@ void GameState::xferSaveData( Xfer *xfer, SnapshotType which ) DEBUG_LOG(("Looking at block '%s'", blockName.str())); + // Skip blocks with nullptr snapshot (can happen in headless mode) + if( blockInfo->snapshot == nullptr ) + { + DEBUG_LOG(("Skipping block '%s' because snapshot is nullptr", blockName.str())); + continue; + } + + // Skip visual-only blocks when saving in headless mode + if( TheGlobalData && TheGlobalData->m_headless && + (blockName.compareNoCase( "CHUNK_TerrainVisual" ) == 0 || + blockName.compareNoCase( "CHUNK_TacticalView" ) == 0 || + blockName.compareNoCase( "CHUNK_ParticleSystem" ) == 0 || + blockName.compareNoCase( "CHUNK_GhostObject" ) == 0) ) + { + DEBUG_LOG(("Skipping block '%s' in headless mode", blockName.str())); + continue; + } + // // for mission save files, we only save the game state block and campaign manager // because anything else is not needed. @@ -1455,6 +1484,15 @@ void GameState::xferSaveData( Xfer *xfer, SnapshotType which ) } + // Skip blocks with nullptr snapshot (can happen in headless mode) + if( blockInfo->snapshot == nullptr ) + { + DEBUG_LOG(("Skipping block '%s' because snapshot is nullptr", blockInfo->blockName.str())); + Int dataSize = xfer->beginBlock(); + xfer->skip( dataSize ); + continue; + } + try {