From 1b2baf43ad898feba2eae89e9d50478176fff7db Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 7 Feb 2021 06:10:19 +0100 Subject: [PATCH] Add information about dhewm3 build to savegames like the dhewm3 version and the OS and architecture of the dhewm3 version that created the savegame. Also added an internalSavegameVersion so be independent of BUILD_NUMBER fixes #344 --- neo/CMakeLists.txt | 14 ++++++++++-- neo/d3xp/Game_local.cpp | 41 +++++++++++++++++++++++++++++++++ neo/d3xp/Game_local.h | 1 + neo/d3xp/gamesys/SaveGame.cpp | 1 + neo/d3xp/gamesys/SaveGame.h | 15 ++++++++++++ neo/framework/Common.cpp | 24 +++++++++++++++++++ neo/framework/Licensee.h | 4 ++-- neo/game/Game_local.cpp | 43 ++++++++++++++++++++++++++++++----- neo/game/Game_local.h | 1 + neo/game/gamesys/SaveGame.cpp | 1 + neo/game/gamesys/SaveGame.h | 15 ++++++++++++ 11 files changed, 150 insertions(+), 10 deletions(-) diff --git a/neo/CMakeLists.txt b/neo/CMakeLists.txt index b95fc3cb..c8eba3da 100644 --- a/neo/CMakeLists.txt +++ b/neo/CMakeLists.txt @@ -74,7 +74,15 @@ elseif(cpu MATCHES "i.86") endif() if(MSVC AND CMAKE_CL_64) - set(cpu "amd64") + set(cpu "x86_64") +endif() + +add_definitions(-DD3_ARCH="${cpu}" -DD3_SIZEOFPTR=${CMAKE_SIZEOF_VOID_P}) + +if(cpu STREQUAL "x86_64" AND NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + # TODO: same for arm64? PPC64? + message(SEND_ERROR "CMake thinks sizeof(void*) == 4, but that the target CPU is x86_64!") + message(FATAL_ERROR "If you're building in a 32bit chroot on a 64bit host, switch to it with 'linux32 chroot' or at least call cmake with linux32 (or your OSs equivalent)!") endif() # target os @@ -84,6 +92,8 @@ else() string(TOLOWER "${CMAKE_SYSTEM_NAME}" os) endif() +add_definitions(-DD3_OSTYPE="${os}") + # build type if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "RelWithDebInfo") @@ -230,7 +240,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang") if(cpu STREQUAL "x86_64") add_compile_options(-arch x86_64 -mmacosx-version-min=10.9) set(ldflags "${ldflags} -arch x86_64 -mmacosx-version-min=10.9") - elseif(cpu STREQUAL "arm64") + elseif(cpu STREQUAL "arm64") add_compile_options(-arch arm64 -mmacosx-version-min=11.0) set(ldflags "${ldflags} -arch arm64 -mmacosx-version-min=11.0") elseif(cpu STREQUAL "x86") diff --git a/neo/d3xp/Game_local.cpp b/neo/d3xp/Game_local.cpp index 6ffb61b1..08aaf9bf 100644 --- a/neo/d3xp/Game_local.cpp +++ b/neo/d3xp/Game_local.cpp @@ -26,6 +26,8 @@ If you have questions concerning this license or the applicable additional terms =========================================================================== */ +#include + #include "sys/platform.h" #include "idlib/LangDict.h" #include "idlib/Timer.h" @@ -505,6 +507,15 @@ void idGameLocal::SaveGame( idFile *f ) { savegame.WriteBuildNumber( BUILD_NUMBER ); + // DG: add some more information to savegame to make future quirks easier + savegame.WriteInt( INTERNAL_SAVEGAME_VERSION ); // to be independent of BUILD_NUMBER + savegame.WriteString( D3_OSTYPE ); // operating system - from CMake + savegame.WriteString( D3_ARCH ); // CPU architecture (e.g. "x86" or "x86_64") - from CMake + savegame.WriteString( ENGINE_VERSION ); + savegame.WriteShort( (short)sizeof(void*) ); // tells us if it's from a 32bit (4) or 64bit system (8) + savegame.WriteShort( SDL_BYTEORDER ) ; // SDL_LIL_ENDIAN or SDL_BIG_ENDIAN + // DG end + // go through all entities and threads and add them to the object list for( i = 0; i < MAX_GENTITIES; i++ ) { ent = entities[i]; @@ -1360,6 +1371,36 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo savegame.ReadBuildNumber(); + // DG: I enhanced the information in savegames a bit for dhewm3 1.5.1 + // for which I bumped th BUILD_NUMBER to 1305 + if( savegame.GetBuildNumber() >= 1305 ) + { + savegame.ReadInternalSavegameVersion(); + if( savegame.GetInternalSavegameVersion() > INTERNAL_SAVEGAME_VERSION ) { + Warning( "Savegame from newer dhewm3 version, don't know how to load! (its version is %d, only up to %d supported)", + savegame.GetInternalSavegameVersion(), INTERNAL_SAVEGAME_VERSION ); + return false; + } + idStr osType; + idStr cpuArch; + idStr engineVersion; + short ptrSize = 0; + short byteorder = 0; + savegame.ReadString( osType ); // operating system the savegame was crated on (written from D3_OSTYPE) + savegame.ReadString( cpuArch ); // written from D3_ARCH (which is set in CMake), like "x86" or "x86_64" + savegame.ReadString( engineVersion ); // written from ENGINE_VERSION + savegame.ReadShort( ptrSize ); // sizeof(void*) of system that created the savegame, 4 on 32bit systems, 8 on 64bit systems + savegame.ReadShort( byteorder ); // SDL_LIL_ENDIAN or SDL_BIG_ENDIAN + + Printf( "Savegame was created by %s on %s %s. BuildNumber was %d, savegameversion %d\n", + engineVersion.c_str(), osType.c_str(), cpuArch.c_str(), savegame.GetBuildNumber(), + savegame.GetInternalSavegameVersion() ); + + // right now I have no further use for this information, but in the future + // it can be used for quirks for (then-) old savegames + } + // DG end + // Create the list of all objects in the game savegame.CreateObjects(); diff --git a/neo/d3xp/Game_local.h b/neo/d3xp/Game_local.h index cb229cd9..acd4fff0 100644 --- a/neo/d3xp/Game_local.h +++ b/neo/d3xp/Game_local.h @@ -512,6 +512,7 @@ public: private: const static int INITIAL_SPAWN_COUNT = 1; + const static int INTERNAL_SAVEGAME_VERSION = 1; // DG: added this for >= 1305 savegames idStr mapFileName; // name of the map, empty string if no map loaded idMapFile * mapFile; // will be NULL during the game unless in-game editing is used diff --git a/neo/d3xp/gamesys/SaveGame.cpp b/neo/d3xp/gamesys/SaveGame.cpp index 2dd04a66..83414a91 100644 --- a/neo/d3xp/gamesys/SaveGame.cpp +++ b/neo/d3xp/gamesys/SaveGame.cpp @@ -785,6 +785,7 @@ idRestoreGame::RestoreGame */ idRestoreGame::idRestoreGame( idFile *savefile ) { file = savefile; + internalSavegameVersion = 0; } /* diff --git a/neo/d3xp/gamesys/SaveGame.h b/neo/d3xp/gamesys/SaveGame.h index 4b0927f4..b7816597 100644 --- a/neo/d3xp/gamesys/SaveGame.h +++ b/neo/d3xp/gamesys/SaveGame.h @@ -158,8 +158,23 @@ public: // Used to retrieve the saved game buildNumber from within class Restore methods int GetBuildNumber( void ); + // DG: added these methods, internalSavegameVersion makes us independent of the global BUILD_NUMBER + void ReadInternalSavegameVersion( void ) + { + ReadInt( internalSavegameVersion ); + } + + // if it's 0, this is from a GetBuildNumber() < 1305 savegame + // otherwise, compare it to idGameLocal::INTERNAL_SAVEGAME_VERSION + int GetInternalSavegameVersion( void ) const + { + return internalSavegameVersion; + } + // DG end + private: int buildNumber; + int internalSavegameVersion; // DG added this idFile * file; diff --git a/neo/framework/Common.cpp b/neo/framework/Common.cpp index 87d9df69..d0bda134 100644 --- a/neo/framework/Common.cpp +++ b/neo/framework/Common.cpp @@ -2837,6 +2837,24 @@ static bool checkForHelp(int argc, char **argv) return false; } +#ifdef UINTPTR_MAX // DG: make sure D3_SIZEOFPTR is consistent with reality + +#if D3_SIZEOFPTR == 4 + #if UINTPTR_MAX != 0xFFFFFFFFUL + #error "CMake assumes that we're building for a 32bit architecture, but UINTPTR_MAX doesn't match!" + #endif +#elif D3_SIZEOFPTR == 8 + #if UINTPTR_MAX != 18446744073709551615ULL + #error "CMake assumes that we're building for a 64bit architecture, but UINTPTR_MAX doesn't match!" + #endif +#else + // Hello future person with a 128bit(?) CPU, I hope the future doesn't suck too much and that you don't still use CMake. + // Also, please adapt this check and send a pull request (or whatever way we have to send patches in the future) + #error "D3_SIZEOFPTR should really be 4 (for 32bit targets) or 8 (for 64bit targets), what kind of machine is this?!" +#endif + +#endif // UINTPTR_MAX defined + /* ================= idCommonLocal::Init @@ -2844,6 +2862,12 @@ idCommonLocal::Init */ void idCommonLocal::Init( int argc, char **argv ) { + // in case UINTPTR_MAX isn't defined (or wrong), do a runtime check at startup + if ( D3_SIZEOFPTR != sizeof(void*) ) { + Sys_Error( "Something went wrong in your build: CMake assumed that sizeof(void*) == %d but in reality it's %d!\n", + (int)D3_SIZEOFPTR, (int)sizeof(void*) ); + } + if(checkForHelp(argc, argv)) { // game has been started with --help (or similar), usage message has been shown => quit diff --git a/neo/framework/Licensee.h b/neo/framework/Licensee.h index dcf75071..f9b4c8c1 100644 --- a/neo/framework/Licensee.h +++ b/neo/framework/Licensee.h @@ -41,12 +41,12 @@ If you have questions concerning this license or the applicable additional terms #define GAME_NAME "dhewm 3" // appears on window titles and errors #endif -#define ENGINE_VERSION "dhewm3 1.5.1rc2" // printed in console +#define ENGINE_VERSION "dhewm3 1.5.1rc3" // printed in console #ifdef ID_REPRODUCIBLE_BUILD // for reproducible builds we hardcode values that would otherwise come from __DATE__ and __TIME__ // NOTE: remember to update esp. the date for (pre-) releases and RCs and the like - #define ID__DATE__ "Jul 21 2020" + #define ID__DATE__ "Feb 06 2021" #define ID__TIME__ "13:37:42" #else // not reproducible build, use __DATE__ and __TIME__ macros diff --git a/neo/game/Game_local.cpp b/neo/game/Game_local.cpp index d99901cb..ef820d66 100644 --- a/neo/game/Game_local.cpp +++ b/neo/game/Game_local.cpp @@ -26,6 +26,8 @@ If you have questions concerning this license or the applicable additional terms =========================================================================== */ +#include + #include "sys/platform.h" #include "idlib/LangDict.h" #include "idlib/Timer.h" @@ -447,9 +449,14 @@ void idGameLocal::SaveGame( idFile *f ) { savegame.WriteBuildNumber( BUILD_NUMBER ); - // DG: TODO: write other things (maybe internal savegame version so I don't have to bump BUILD_NUMBER AGAIN) - // and OS, architecture etc, see #344 - // TODO: adjust InitFromSavegame() accordingly! + // DG: add some more information to savegame to make future quirks easier + savegame.WriteInt( INTERNAL_SAVEGAME_VERSION ); // to be independent of BUILD_NUMBER + savegame.WriteString( D3_OSTYPE ); // operating system - from CMake + savegame.WriteString( D3_ARCH ); // CPU architecture (e.g. "x86" or "x86_64") - from CMake + savegame.WriteString( ENGINE_VERSION ); + savegame.WriteShort( (short)sizeof(void*) ); // tells us if it's from a 32bit (4) or 64bit system (8) + savegame.WriteShort( SDL_BYTEORDER ) ; // SDL_LIL_ENDIAN or SDL_BIG_ENDIAN + // DG end // go through all entities and threads and add them to the object list for( i = 0; i < MAX_GENTITIES; i++ ) { @@ -1244,11 +1251,35 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo savegame.ReadBuildNumber(); - - if(savegame.GetBuildNumber() >= 1305) + // DG: I enhanced the information in savegames a bit for dhewm3 1.5.1 + // for which I bumped th BUILD_NUMBER to 1305 + if( savegame.GetBuildNumber() >= 1305 ) { - // TODO: read stuff additionally written in SaveGame() + savegame.ReadInternalSavegameVersion(); + if( savegame.GetInternalSavegameVersion() > INTERNAL_SAVEGAME_VERSION ) { + Warning( "Savegame from newer dhewm3 version, don't know how to load! (its version is %d, only up to %d supported)", + savegame.GetInternalSavegameVersion(), INTERNAL_SAVEGAME_VERSION ); + return false; + } + idStr osType; + idStr cpuArch; + idStr engineVersion; + short ptrSize = 0; + short byteorder = 0; + savegame.ReadString( osType ); // operating system the savegame was crated on (written from D3_OSTYPE) + savegame.ReadString( cpuArch ); // written from D3_ARCH (which is set in CMake), like "x86" or "x86_64" + savegame.ReadString( engineVersion ); // written from ENGINE_VERSION + savegame.ReadShort( ptrSize ); // sizeof(void*) of system that created the savegame, 4 on 32bit systems, 8 on 64bit systems + savegame.ReadShort( byteorder ); // SDL_LIL_ENDIAN or SDL_BIG_ENDIAN + + Printf( "Savegame was created by %s on %s %s. BuildNumber was %d, savegameversion %d\n", + engineVersion.c_str(), osType.c_str(), cpuArch.c_str(), savegame.GetBuildNumber(), + savegame.GetInternalSavegameVersion() ); + + // right now I have no further use for this information, but in the future + // it can be used for quirks for (then-) old savegames } + // DG end // Create the list of all objects in the game savegame.CreateObjects(); diff --git a/neo/game/Game_local.h b/neo/game/Game_local.h index 1f724434..df7456d1 100644 --- a/neo/game/Game_local.h +++ b/neo/game/Game_local.h @@ -450,6 +450,7 @@ public: private: const static int INITIAL_SPAWN_COUNT = 1; + const static int INTERNAL_SAVEGAME_VERSION = 1; // DG: added this for >= 1305 savegames idStr mapFileName; // name of the map, empty string if no map loaded idMapFile * mapFile; // will be NULL during the game unless in-game editing is used diff --git a/neo/game/gamesys/SaveGame.cpp b/neo/game/gamesys/SaveGame.cpp index e0b70c9d..7dceafeb 100644 --- a/neo/game/gamesys/SaveGame.cpp +++ b/neo/game/gamesys/SaveGame.cpp @@ -780,6 +780,7 @@ idRestoreGame::RestoreGame */ idRestoreGame::idRestoreGame( idFile *savefile ) { file = savefile; + internalSavegameVersion = 0; } /* diff --git a/neo/game/gamesys/SaveGame.h b/neo/game/gamesys/SaveGame.h index 4b0927f4..b7816597 100644 --- a/neo/game/gamesys/SaveGame.h +++ b/neo/game/gamesys/SaveGame.h @@ -158,8 +158,23 @@ public: // Used to retrieve the saved game buildNumber from within class Restore methods int GetBuildNumber( void ); + // DG: added these methods, internalSavegameVersion makes us independent of the global BUILD_NUMBER + void ReadInternalSavegameVersion( void ) + { + ReadInt( internalSavegameVersion ); + } + + // if it's 0, this is from a GetBuildNumber() < 1305 savegame + // otherwise, compare it to idGameLocal::INTERNAL_SAVEGAME_VERSION + int GetInternalSavegameVersion( void ) const + { + return internalSavegameVersion; + } + // DG end + private: int buildNumber; + int internalSavegameVersion; // DG added this idFile * file;