From 7fc3fb4c15e2dc2e7a296c70f5ff9f8b384a6d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Thu, 19 Oct 2023 10:48:10 +0200 Subject: [PATCH] Sort out version info The idea is to have the following version information included: - 1-component save version - 2-component under the hood but the minor component shouldn't ever change again - see currentVersionMajor in GameSave.cpp - 1-component website API version - again, currently 2-component because that's what the website code expects - see apiVersion in requestmanager/Common.cpp - 2-component display version, entirely cosmetic - exposed as meson options display_version_major and display_version_minor - see APP_VERSION in Config.template.h - 1-component business logic version aka build number - exposed as meson option build_num - see APP_VERSION in Config.template.h - variant id aka mod id, tightly coupled with the build number - exposed as meson option mod_id - see MOD_ID in Config.template.h - display and business logic versions repeated for the upstream - exposed as meson options upstream_version_major, upstream_version_minor, and upstream_build_num - we'll have to update these alongside display_version_major, display_version_minor, and build_num, but mod owners can just merge our changes - see UPSTREAM_VERSION in Config.template.h - update channel, makes sense in the context of the variant (and yes, this would later enable mod snapshots) - currently not exposed as a meson option but derived from meson options snapshot and mod_id - see IDENT_RELTYPE in Config.template.h - vcs tag aka git commit hash - set by build.sh in ghactions workflows - see VCS_TAG in VcsTag.tempalte.h Rather importantly, the save and website API versions are now allowed to change independently of the display version. These changes also allowed me to remove the ugly sed hacks in build.sh used to provision some manifest files; they are now provisioned by meson. Also add version info for windows and android. --- .github/build.sh | 36 +++------- android/AndroidManifest.template.xml | 4 +- meson_options.txt | 60 ++++++++++++++++ resources/Info.template.plist | 8 +-- resources/appdata.template.xml | 2 +- resources/meson.build | 12 +++- resources/powder-res.rc | 6 -- resources/powder-res.template.rc | 32 +++++++++ src/Config.template.h | 16 +++-- src/client/Client.cpp | 4 +- src/client/GameSave.cpp | 88 ++++++++++++----------- src/client/GameSave.h | 4 +- src/client/http/StartupRequest.cpp | 4 +- src/client/http/requestmanager/Common.cpp | 5 +- src/common/Version.h | 10 +++ src/gui/game/GameController.cpp | 8 +-- src/gui/game/IntroText.h | 4 +- src/gui/save/LocalSaveActivity.cpp | 4 +- src/lua/LuaScriptInterface.cpp | 12 +++- src/meson.build | 9 +++ src/simulation/Simulation.cpp | 12 ++-- 21 files changed, 229 insertions(+), 111 deletions(-) delete mode 100644 resources/powder-res.rc create mode 100644 resources/powder-res.template.rc diff --git a/.github/build.sh b/.github/build.sh index 452034477..405e2577e 100755 --- a/.github/build.sh +++ b/.github/build.sh @@ -87,18 +87,6 @@ function inplace_sed() { fi } -function subst_version() { - local path=$1 - if [[ $BSH_HOST_PLATFORM == darwin ]]; then - inplace_sed "s|SUBST_MACOS_MIN_VER|$macos_min_ver|g" $path - else - inplace_sed "s|SUBST_DATE|$(date --iso-8601)|g" $path - fi - inplace_sed "s|SUBST_SAVE_VERSION|$save_version|g" $path - inplace_sed "s|SUBST_MINOR_VERSION|$minor_version|g" $path - inplace_sed "s|SUBST_BUILD_NUM|$build_num|g" $path -} - if [[ $BSH_HOST_PLATFORM == android ]]; then android_platform=android-30 if [[ -z "${JAVA_HOME_8_X64-}" ]]; then @@ -189,6 +177,11 @@ meson_configure=meson$'\t'setup if [[ $BSH_DEBUG_RELEASE == release ]]; then meson_configure+=$'\t'-Dbuildtype=debugoptimized fi +if [[ $BSH_HOST_PLATFORM == darwin ]]; then + meson_configure+=$'\t'-Dmanifest_macos_min_ver=$macos_min_ver +else + meson_configure+=$'\t'-Dmanifest_date=$(date --iso-8601) +fi meson_configure+=$'\t'-Dapp_name=$APP_NAME meson_configure+=$'\t'-Dapp_comment=$APP_COMMENT meson_configure+=$'\t'-Dapp_exe=$APP_EXE @@ -251,19 +244,10 @@ fi if [[ $RELEASE_TYPE == stable ]]; then stable_or_beta=yes fi -set +e -save_version=$(cat src/Config.template.h | sed -n 's/constexpr int SAVE_VERSION * = \([^;]*\);/\1/p') -minor_version=$(cat src/Config.template.h | sed -n 's/constexpr int MINOR_VERSION * = \([^;]*\);/\1/p') -build_num=$(cat src/Config.template.h | sed -n 's/constexpr int BUILD_NUM * = \([^;]*\);/\1/p') -if [[ -z ${save_version-} ]] || [[ -z ${minor_version-} ]] || [[ -z ${build_num-} ]]; then - >&2 echo "failed to extract version from Config.template.h" - exit 1 -fi -set -e -if [[ $stable_or_beta == yes ]] && [[ $MOD_ID != 0 ]]; then - save_version=$(echo $RELEASE_NAME | cut -d '.' -f 1) - minor_version=$(echo $RELEASE_NAME | cut -d '.' -f 2) - build_num=$(echo $RELEASE_NAME | cut -d '.' -f 3) +if [[ $stable_or_beta == yes ]]; then + meson_configure+=$'\t'-Ddisplay_version_major=$(echo $RELEASE_NAME | cut -d '.' -f 1) + meson_configure+=$'\t'-Ddisplay_version_minor=$(echo $RELEASE_NAME | cut -d '.' -f 2) + meson_configure+=$'\t'-Dbuild_num=$(echo $RELEASE_NAME | cut -d '.' -f 3) fi if [[ $RELEASE_TYPE == snapshot ]]; then meson_configure+=$'\t'-Dsnapshot=true @@ -426,7 +410,6 @@ if [[ $PACKAGE_MODE == dmg ]]; then mkdir $appdir mkdir $appdir/Contents cp resources/Info.plist $appdir/Contents/Info.plist - subst_version $appdir/Contents/Info.plist mkdir $appdir/Contents/MacOS cp $APP_EXE $appdir/Contents/MacOS/$APP_EXE mkdir $appdir/Contents/Resources @@ -471,7 +454,6 @@ elif [[ $PACKAGE_MODE == appimage ]]; then cp ../resources/icon_exe.svg $appdir/$APP_VENDOR-$APP_EXE.svg cp resources/powder.desktop $appdir/$APP_ID.desktop cp resources/appdata.xml $appdir/usr/share/metainfo/$APP_ID.appdata.xml - subst_version $appdir/usr/share/metainfo/$APP_ID.appdata.xml cp $appdir/$APP_VENDOR-$APP_EXE.svg $appdir/usr/share/icons/$APP_VENDOR-$APP_EXE.svg cp $appdir/$APP_ID.desktop $appdir/usr/share/applications/$APP_ID.desktop ./appimagetool $appdir $ASSET_PATH diff --git a/android/AndroidManifest.template.xml b/android/AndroidManifest.template.xml index c84b868c1..af9ace73d 100644 --- a/android/AndroidManifest.template.xml +++ b/android/AndroidManifest.template.xml @@ -2,8 +2,8 @@ CFBundleIconFile icon_exe.icns NSHumanReadableCopyright - Copyright © 2008-2011 Stanislaw K Skowrenek, Copyright © 2011-2023 Simon Robertshaw, Copyright © 2016-2023 jacob1 + @MANIFEST_COPYRIGHT@ CFBundleDevelopmentRegion English CFBundleDocumentTypes @@ -57,13 +57,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - SUBST_SAVE_VERSION.SUBST_MINOR_VERSION + @DISPLAY_VERSION_MAJOR@.@DISPLAY_VERSION_MINOR@ CFBundleSignature ???? CFBundleVersion - SUBST_SAVE_VERSION.SUBST_MINOR_VERSION (build SUBST_BUILD_NUM) + @DISPLAY_VERSION_MAJOR@.@DISPLAY_VERSION_MINOR@ (build @BUILD_NUM@) LSMinimumSystemVersion - SUBST_MACOS_MIN_VER + @MANIFEST_MACOS_MIN_VER@ NSPrincipalClass NSApplication diff --git a/resources/appdata.template.xml b/resources/appdata.template.xml index 9d67bf029..824921133 100644 --- a/resources/appdata.template.xml +++ b/resources/appdata.template.xml @@ -29,6 +29,6 @@ https://github.com/The-Powder-Toy/The-Powder-Toy/issues https://powdertoy.co.uk/Wiki/W/Main_Page.html - + diff --git a/resources/meson.build b/resources/meson.build index bf8b39532..44a470ce2 100644 --- a/resources/meson.build +++ b/resources/meson.build @@ -52,8 +52,18 @@ if host_platform == 'windows' command: command, ) } endforeach + rc_conf_data = configuration_data() + rc_conf_data.merge_from(conf_data) + rc_conf_data.set('RESOUCE_H', join_paths(meson.current_source_dir(), 'resource.h')) + rc_conf_data.set('WINUTF8_XML', join_paths(meson.current_source_dir(), 'winutf8.xml')) + rc_conf_data.set('ICON_EXE_ICO', join_paths(meson.current_build_dir(), 'icon_exe.ico')) + rc_conf_data.set('ICON_CPS_ICO', join_paths(meson.current_build_dir(), 'icon_cps.ico')) powder_files += windows_mod.compile_resources( - 'powder-res.rc', + configure_file( + input: 'powder-res.template.rc', + output: 'powder-res.rc', + configuration: rc_conf_data, + ), depends: [ generated_win_icos['icon_exe'], generated_win_icos['icon_cps'], diff --git a/resources/powder-res.rc b/resources/powder-res.rc deleted file mode 100644 index 7bb0c594e..000000000 --- a/resources/powder-res.rc +++ /dev/null @@ -1,6 +0,0 @@ -#include "resource.h" -#include - -IDI_ICON ICON DISCARDABLE "icon_exe.ico" -IDI_DOC_ICON ICON DISCARDABLE "icon_cps.ico" -CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "winutf8.xml" diff --git a/resources/powder-res.template.rc b/resources/powder-res.template.rc new file mode 100644 index 000000000..71d47a6a2 --- /dev/null +++ b/resources/powder-res.template.rc @@ -0,0 +1,32 @@ +#include "@RESOUCE_H@" +#include +#include +#include + +IDI_ICON ICON DISCARDABLE "@ICON_EXE_ICO@" +IDI_DOC_ICON ICON DISCARDABLE "@ICON_CPS_ICO@" +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "@WINUTF8_XML@" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION @DISPLAY_VERSION_MAJOR@,@DISPLAY_VERSION_MINOR@,0,@BUILD_NUM@ +PRODUCTVERSION @DISPLAY_VERSION_MAJOR@,@DISPLAY_VERSION_MINOR@,0,@BUILD_NUM@ +{ + BLOCK "StringFileInfo" + { + BLOCK "040904b0" + { + VALUE "CompanyName", "https://powdertoy.co.uk/\0" + VALUE "FileDescription", "@APPCOMMENT@\0" + VALUE "FileVersion", "@DISPLAY_VERSION_MAJOR@.@DISPLAY_VERSION_MINOR@.0.@BUILD_NUM@\0" + VALUE "OriginalFilename", "@APPEXE@.exe\0" + VALUE "LegalCopyright", "@MANIFEST_COPYRIGHT@\0" + VALUE "ProductName", "@APPNAME@\0" + VALUE "ProductVersion", "@DISPLAY_VERSION_MAJOR@.@DISPLAY_VERSION_MINOR@.0.@BUILD_NUM@\0" + VALUE "InternalName", "@APPID@\0" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x409, 65001 + } +} diff --git a/src/Config.template.h b/src/Config.template.h index 41292c497..e9fce5618 100644 --- a/src/Config.template.h +++ b/src/Config.template.h @@ -1,5 +1,6 @@ #pragma once #include "VcsTag.h" +#include "common/Version.h" constexpr bool SET_WINDOW_ICON = @SET_WINDOW_ICON@; constexpr bool DEBUG = @DEBUG@; @@ -44,13 +45,18 @@ constexpr char APPID[] = "@APPID@"; constexpr char APPDATA[] = "@APPDATA@"; constexpr char APPVENDOR[] = "@APPVENDOR@"; -constexpr int SAVE_VERSION = 97; -constexpr int MINOR_VERSION = 0; -constexpr int BUILD_NUM = 352; constexpr int SNAPSHOT_ID = @SNAPSHOT_ID@; constexpr int MOD_ID = @MOD_ID@; -constexpr int FUTURE_SAVE_VERSION = 98; -constexpr int FUTURE_MINOR_VERSION = 0; + +struct DisplayVersionWithBuild +{ + Version<2> displayVersion; + size_t build; +}; +constexpr DisplayVersionWithBuild APP_VERSION = { { @DISPLAY_VERSION_MAJOR@, @DISPLAY_VERSION_MINOR@ }, @BUILD_NUM@ }; +constexpr DisplayVersionWithBuild UPSTREAM_VERSION = { { @UPSTREAM_VERSION_MAJOR@, @UPSTREAM_VERSION_MINOR@ }, @UPSTREAM_BUILD_NUM@ }; + +constexpr auto DISPLAY_VERSION = APP_VERSION.displayVersion; constexpr char IDENT_RELTYPE = SNAPSHOT ? 'S' : (BETA ? 'B' : 'R'); diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 8e2b1e54c..419c87e0a 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -325,8 +325,8 @@ ByteString Client::AddStamp(std::unique_ptr saveData) } saveData->authors = stampInfo; - auto [ fromNewerVersion, gameData ] = saveData->Serialise(); - (void)fromNewerVersion; + std::vector gameData; + std::tie(std::ignore, gameData) = saveData->Serialise(); if (!gameData.size()) return ""; diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 27196e45a..adbe30dd4 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -4,7 +4,6 @@ #include "simulation/Simulation.h" #include "simulation/ElementClasses.h" #include "common/tpt-compat.h" -#include "common/Version.h" #include "bson/BSON.h" #include "graphics/Renderer.h" #include "Config.h" @@ -16,6 +15,9 @@ #include #include +constexpr auto currentVersionMajor = 97; +constexpr auto nextVersionMajor = currentVersionMajor + 1; + static void ConvertJsonToBson(bson *b, Json::Value j, int depth = 0); static void ConvertBsonToJson(bson_iterator *b, Json::Value *j, int depth = 0); static void CheckBsonFieldUser(bson_iterator iter, const char *field, unsigned char **data, unsigned int *fieldLen); @@ -326,6 +328,9 @@ static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *se void GameSave::readOPS(const std::vector &data) { + constexpr auto currentVersion = Version(currentVersionMajor, 0); + constexpr auto nextVersion = Version(nextVersionMajor, 0); + Renderer::PopulateTables(); unsigned char *inputData = (unsigned char*)&data[0], *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL, *soapLinkData = NULL; @@ -333,9 +338,8 @@ void GameSave::readOPS(const std::vector &data) unsigned int inputDataLen = data.size(), bsonDataLen = 0, partsDataLen, partsPosDataLen, fanDataLen, wallDataLen, soapLinkDataLen; unsigned int pressDataLen, vxDataLen, vyDataLen, ambientDataLen, blockAirDataLen; unsigned partsCount = 0; - int savedVersion = inputData[4]; - majorVersion = savedVersion; - minorVersion = 0; + unsigned int savedVersion = inputData[4]; + version = { savedVersion, 0 }; bool fakeNewerVersion = false; // used for development builds only bson b; @@ -354,7 +358,7 @@ void GameSave::readOPS(const std::vector &data) auto partS = blockS * CELL; //From newer version - if (savedVersion > SAVE_VERSION) + if (savedVersion > currentVersion[0]) { fromNewerVersion = true; //throw ParseException(ParseException::WrongVersion, "Save from newer version"); @@ -470,7 +474,7 @@ void GameSave::readOPS(const std::vector &data) if (!strcmp(bson_iterator_key(&signiter), "text") && bson_iterator_type(&signiter) == BSON_STRING) { tempSign.text = format::CleanString(ByteString(bson_iterator_string(&signiter)).FromUtf8(), true, true, true).Substr(0, 45); - if (majorVersion < 94 || (majorVersion == 94 && minorVersion < 2)) + if (version < Version(94, 2)) { if (tempSign.text == "{t}") { @@ -582,7 +586,7 @@ void GameSave::readOPS(const std::vector &data) { if (!strcmp(bson_iterator_key(&subiter), "minorVersion")) { - minorVersion = bson_iterator_int(&subiter); + version[1] = bson_iterator_int(&subiter); } } } @@ -596,27 +600,30 @@ void GameSave::readOPS(const std::vector &data) { if (bson_iterator_type(&iter) == BSON_OBJECT) { - int major = INT_MAX, minor = INT_MAX; - bson_iterator subiter; - bson_iterator_subiterator(&iter, &subiter); - while (bson_iterator_next(&subiter)) + Version<2> version; { - if (bson_iterator_type(&subiter) == BSON_INT) + int major = INT_MAX, minor = INT_MAX; + bson_iterator subiter; + bson_iterator_subiterator(&iter, &subiter); + while (bson_iterator_next(&subiter)) { - if (!strcmp(bson_iterator_key(&subiter), "major")) - major = bson_iterator_int(&subiter); - else if (!strcmp(bson_iterator_key(&subiter), "minor")) - minor = bson_iterator_int(&subiter); + if (bson_iterator_type(&subiter) == BSON_INT) + { + if (!strcmp(bson_iterator_key(&subiter), "major")) + major = bson_iterator_int(&subiter); + else if (!strcmp(bson_iterator_key(&subiter), "minor")) + minor = bson_iterator_int(&subiter); + } } + version = Version(major, minor); } - auto majorToCheck = ALLOW_FAKE_NEWER_VERSION ? FUTURE_SAVE_VERSION : SAVE_VERSION; - auto minorToCheck = ALLOW_FAKE_NEWER_VERSION ? FUTURE_MINOR_VERSION : MINOR_VERSION; - if (major > majorToCheck || (major == majorToCheck && minor > minorToCheck)) + auto versionToCheck = ALLOW_FAKE_NEWER_VERSION ? nextVersion : currentVersion; + if (versionToCheck < version) { - String errorMessage = String::Build("Save from a newer version: Requires version ", major, ".", minor); + String errorMessage = String::Build("Save from a newer version: Requires version ", version[0], ".", version[1]); throw ParseException(ParseException::WrongVersion, errorMessage); } - else if (ALLOW_FAKE_NEWER_VERSION && (major > SAVE_VERSION || (major == SAVE_VERSION && minor > MINOR_VERSION))) + else if (ALLOW_FAKE_NEWER_VERSION && currentVersion < version) { fakeNewerVersion = true; } @@ -642,8 +649,8 @@ void GameSave::readOPS(const std::vector &data) } } - auto paletteRemap = [this, saveVersion = Version(majorVersion, minorVersion)](auto maxVersion, ByteString from, ByteString to) { - if (saveVersion <= maxVersion) + auto paletteRemap = [this](auto maxVersion, ByteString from, ByteString to) { + if (version <= maxVersion) { auto it = std::find_if(palette.begin(), palette.end(), [&from](auto &item) { return item.first == from; @@ -1182,7 +1189,7 @@ void GameSave::readPSv(const std::vector &dataVec) unsigned char * saveData = (unsigned char *)&dataVec[0]; auto dataLength = int(dataVec.size()); - int q,p=0, ver, pty, ty, legacy_beta=0; + int q,p=0, pty, ty, legacy_beta=0; Vec2 blockP = { 0, 0 }; int new_format = 0, ttv = 0; @@ -1202,11 +1209,10 @@ void GameSave::readPSv(const std::vector &dataVec) if (saveData[2]==0x76 && saveData[1]==0x53 && saveData[0]==0x50) { new_format = 1; } - if (saveData[4]>SAVE_VERSION) + if (saveData[4]>97) // this used to respect currentVersion but no valid PSv will ever have a version > 97 so it's ok to hardcode throw ParseException(ParseException::WrongVersion, "Save from newer version"); - ver = saveData[4]; - majorVersion = saveData[4]; - minorVersion = 0; + version = { saveData[4], 0 }; + auto ver = version[0]; if (ver<34) { @@ -1818,16 +1824,18 @@ void GameSave::readPSv(const std::vector &dataVec) std::pair> GameSave::serialiseOPS() const { + constexpr auto currentVersion = Version(currentVersionMajor, 0); + // minimum version this save is compatible with // when building, this number may be increased depending on what elements are used // or what properties are detected - int minimumMajorVersion = 90, minimumMinorVersion = 2; - auto RESTRICTVERSION = [&minimumMajorVersion, &minimumMinorVersion](int major, int minor) { + auto minimumVersion = Version(90, 2); + auto RESTRICTVERSION = [&minimumVersion](auto major, auto minor = 0) { // restrict the minimum version this save can be opened with - if (major > minimumMajorVersion || ((major == minimumMajorVersion && minor > minimumMinorVersion))) + auto version = Version(major, minor); + if (minimumVersion < version) { - minimumMajorVersion = major; - minimumMinorVersion = minor; + minimumVersion = version; } }; @@ -2295,7 +2303,7 @@ std::pair> GameSave::serialiseOPS() const } // Mark save as incompatible with latest release - bool fakeFromNewerVersion = ALLOW_FAKE_NEWER_VERSION && (minimumMajorVersion > SAVE_VERSION || (minimumMajorVersion == SAVE_VERSION && minimumMinorVersion > MINOR_VERSION)); + bool fakeFromNewerVersion = ALLOW_FAKE_NEWER_VERSION && currentVersion < minimumVersion; bson b; b.data = NULL; @@ -2306,9 +2314,9 @@ std::pair> GameSave::serialiseOPS() const set_bson_err_handler([](const char* err) { throw BuildException("BSON error when parsing save: " + ByteString(err).FromUtf8()); }); bson_init(&b); bson_append_start_object(&b, "origin"); - bson_append_int(&b, "majorVersion", SAVE_VERSION); - bson_append_int(&b, "minorVersion", MINOR_VERSION); - bson_append_int(&b, "buildNum", BUILD_NUM); + bson_append_int(&b, "majorVersion", int(currentVersion[0])); + bson_append_int(&b, "minorVersion", int(currentVersion[1])); + bson_append_int(&b, "buildNum", APP_VERSION.build); bson_append_int(&b, "snapshotId", SNAPSHOT_ID); bson_append_int(&b, "modId", MOD_ID); bson_append_string(&b, "releaseType", ByteString(1, IDENT_RELTYPE).c_str()); @@ -2322,8 +2330,8 @@ std::pair> GameSave::serialiseOPS() const RESTRICTVERSION(97, 0); } bson_append_start_object(&b, "minimumVersion"); - bson_append_int(&b, "major", minimumMajorVersion); - bson_append_int(&b, "minor", minimumMinorVersion); + bson_append_int(&b, "major", int(minimumVersion[0])); + bson_append_int(&b, "minor", int(minimumVersion[1])); bson_append_finish_object(&b); @@ -2467,7 +2475,7 @@ std::pair> GameSave::serialiseOPS() const header[1] = 'P'; header[2] = 'S'; header[3] = '1'; - header[4] = SAVE_VERSION; + header[4] = currentVersion[0]; header[5] = CELL; header[6] = blockS.X; header[7] = blockS.Y; diff --git a/src/client/GameSave.h b/src/client/GameSave.h index 2490372f0..a22d359a3 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -2,6 +2,7 @@ #include "common/Plane.h" #include "common/String.h" #include "common/tpt-rand.h" +#include "common/Version.h" #include "simulation/Sign.h" #include "simulation/Particle.h" #include "Misc.h" @@ -64,8 +65,7 @@ class GameSave public: Vec2 blockSize = { 0, 0 }; bool fromNewerVersion = false; - int majorVersion = 0; - int minorVersion = 0; + Version<2> version{}; bool hasPressure = false; bool hasAmbientHeat = false; bool hasBlockAirMaps = false; // only written by readOPS, never read diff --git a/src/client/http/StartupRequest.cpp b/src/client/http/StartupRequest.cpp index c3c036b88..34fda09aa 100644 --- a/src/client/http/StartupRequest.cpp +++ b/src/client/http/StartupRequest.cpp @@ -82,12 +82,12 @@ namespace http else { parseUpdate("Stable", UpdateInfo::channelStable, [](int build) -> bool { - return build > BUILD_NUM; + return size_t(build) > APP_VERSION.build; }); if (!startupInfo.updateInfo.has_value()) { parseUpdate("Beta", UpdateInfo::channelBeta, [](int build) -> bool { - return build > BUILD_NUM; + return size_t(build) > APP_VERSION.build; }); } } diff --git a/src/client/http/requestmanager/Common.cpp b/src/client/http/requestmanager/Common.cpp index a8d18c5c9..e2cde7223 100644 --- a/src/client/http/requestmanager/Common.cpp +++ b/src/client/http/requestmanager/Common.cpp @@ -10,13 +10,14 @@ namespace http capath(newCapath), disableNetwork(newDisableNetwork) { + auto apiVersion = Version(97, 0); userAgent = ByteString::Build( - "PowderToy/", SAVE_VERSION, ".", MINOR_VERSION, + "PowderToy/", DISPLAY_VERSION[0], ".", DISPLAY_VERSION[1], " (", IDENT_PLATFORM, "; NO", // Unused, used to be SSE level. "; M", MOD_ID, "; ", IDENT, - ") TPTPP/", SAVE_VERSION, ".", MINOR_VERSION, ".", BUILD_NUM, IDENT_RELTYPE, ".", SNAPSHOT_ID + ") TPTPP/", apiVersion[0], ".", apiVersion[1], ".", APP_VERSION.build, IDENT_RELTYPE, ".", SNAPSHOT_ID ); } diff --git a/src/common/Version.h b/src/common/Version.h index 11c1e2846..ae215e3f0 100644 --- a/src/common/Version.h +++ b/src/common/Version.h @@ -26,6 +26,16 @@ struct Version { return *this < other || *this == other; } + + constexpr size_t operator [](size_t index) const + { + return components[index]; + } + + size_t &operator [](size_t index) + { + return components[index]; + } }; template diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index a04b3c844..05e23a359 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -1204,10 +1204,10 @@ void GameController::OpenLocalSaveWindow(bool asCurrent) gameSave->authors = localSaveInfo; Platform::MakeDirectory(LOCAL_SAVE_DIR); - auto [ fromNewerVersion, saveData ] = gameSave->Serialise(); + std::vector saveData; + std::tie(std::ignore, saveData) = gameSave->Serialise(); tempSave->SetGameSave(std::move(gameSave)); gameModel->SetSaveFile(std::move(tempSave), gameView->ShiftBehaviour()); - (void)fromNewerVersion; if (saveData.size() == 0) new ErrorMessage("Error", "Unable to serialize game data."); else if (!Platform::WriteFile(saveData, gameModel->GetSaveFile()->GetName())) @@ -1611,11 +1611,11 @@ void GameController::NotifyUpdateAvailable(Client * sender) } else if constexpr (BETA) { - updateMessage << SAVE_VERSION << "." << MINOR_VERSION << " Beta, Build " << BUILD_NUM; + updateMessage << DISPLAY_VERSION[0] << "." << DISPLAY_VERSION[1] << " Beta, Build " << APP_VERSION.build; } else { - updateMessage << SAVE_VERSION << "." << MINOR_VERSION << " Stable, Build " << BUILD_NUM; + updateMessage << DISPLAY_VERSION[0] << "." << DISPLAY_VERSION[1] << " Stable, Build " << APP_VERSION.build; } updateMessage << "\nNew version:\n "; diff --git a/src/gui/game/IntroText.h b/src/gui/game/IntroText.h index 9ab482324..741849ec7 100644 --- a/src/gui/game/IntroText.h +++ b/src/gui/game/IntroText.h @@ -5,7 +5,7 @@ inline ByteString VersionInfo() { ByteStringBuilder sb; - sb << SAVE_VERSION << "." << MINOR_VERSION << "." << BUILD_NUM << " " << IDENT; + sb << DISPLAY_VERSION[0] << "." << DISPLAY_VERSION[1] << "." << APP_VERSION.build << " " << IDENT; if constexpr (SNAPSHOT) { sb << " SNAPSHOT " << SNAPSHOT_ID; @@ -39,7 +39,7 @@ inline ByteString VersionInfo() inline ByteString IntroText() { ByteStringBuilder sb; - sb << "\bl\bU" << APPNAME << "\bU - Version " << SAVE_VERSION << "." << MINOR_VERSION << " - https://powdertoy.co.uk, irc.libera.chat #powder, https://tpt.io/discord\n" + sb << "\bl\bU" << APPNAME << "\bU - Version " << DISPLAY_VERSION[0] << "." << DISPLAY_VERSION[1] << " - https://powdertoy.co.uk, irc.libera.chat #powder, https://tpt.io/discord\n" "\n" "\n" "\bgControl+C/V/X are Copy, Paste and cut respectively.\n" diff --git a/src/gui/save/LocalSaveActivity.cpp b/src/gui/save/LocalSaveActivity.cpp index 46ece246e..cb5e80cd5 100644 --- a/src/gui/save/LocalSaveActivity.cpp +++ b/src/gui/save/LocalSaveActivity.cpp @@ -115,8 +115,8 @@ void LocalSaveActivity::saveWrite(ByteString finalFilename) gameSave->authors = localSaveInfo; save->SetGameSave(std::move(gameSave)); } - auto [ fromNewerVersion, saveData ] = save->GetGameSave()->Serialise(); - (void)fromNewerVersion; + std::vector saveData; + std::tie(std::ignore, saveData) = save->GetGameSave()->Serialise(); if (saveData.size() == 0) new ErrorMessage("Error", "Unable to serialize game data."); else if (!Platform::WriteFile(saveData, finalFilename)) diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index d43c3f594..a40f74a13 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -403,12 +403,18 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): lua_newtable(l); tptPropertiesVersion = lua_gettop(l); - lua_pushinteger(l, SAVE_VERSION); + lua_pushinteger(l, DISPLAY_VERSION[0]); lua_setfield(l, tptPropertiesVersion, "major"); - lua_pushinteger(l, MINOR_VERSION); + lua_pushinteger(l, DISPLAY_VERSION[1]); lua_setfield(l, tptPropertiesVersion, "minor"); - lua_pushinteger(l, BUILD_NUM); + lua_pushinteger(l, APP_VERSION.build); lua_setfield(l, tptPropertiesVersion, "build"); + lua_pushinteger(l, UPSTREAM_VERSION.displayVersion[0]); + lua_setfield(l, tptPropertiesVersion, "upstream_major"); + lua_pushinteger(l, UPSTREAM_VERSION.displayVersion[1]); + lua_setfield(l, tptPropertiesVersion, "upstream_minor"); + lua_pushinteger(l, UPSTREAM_VERSION.build); + lua_setfield(l, tptPropertiesVersion, "upstream_build"); if constexpr (SNAPSHOT || MOD) { lua_pushinteger(l, SNAPSHOT_ID); diff --git a/src/meson.build b/src/meson.build index 96595a170..cb53f8a15 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,6 +12,15 @@ conf_data.set('DEBUG', is_debug.to_string()) conf_data.set('MOD', is_mod.to_string()) conf_data.set('SNAPSHOT', is_snapshot.to_string()) conf_data.set('SNAPSHOT_ID', get_option('snapshot_id')) +conf_data.set('DISPLAY_VERSION_MAJOR', get_option('display_version_major')) +conf_data.set('DISPLAY_VERSION_MINOR', get_option('display_version_minor')) +conf_data.set('BUILD_NUM', get_option('build_num')) +conf_data.set('UPSTREAM_VERSION_MAJOR', get_option('upstream_version_major')) +conf_data.set('UPSTREAM_VERSION_MINOR', get_option('upstream_version_minor')) +conf_data.set('UPSTREAM_BUILD_NUM', get_option('upstream_build_num')) +conf_data.set('MANIFEST_COPYRIGHT', get_option('manifest_copyright')) +conf_data.set('MANIFEST_MACOS_MIN_VER', get_option('manifest_macos_min_ver')) +conf_data.set('MANIFEST_DATE', get_option('manifest_date')) conf_data.set('ALLOW_FAKE_NEWER_VERSION', (is_snapshot or is_beta or is_debug or is_mod).to_string()) conf_data.set('IDENT_PLATFORM', ident_platform) conf_data.set('IDENT', '@0@-@1@-@2@'.format(host_arch, host_platform, host_libc).to_upper()) diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index fcb8e2e9e..7b76e8fbe 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -151,8 +151,8 @@ std::vector Simulation::Load(const GameSave *save, bool includePress player.spwn = 1; player.elem = PT_DUST; - if ((save->majorVersion < 93 && parts[i].ctype == SPC_AIR) || - (save->majorVersion < 88 && parts[i].ctype == OLD_SPC_AIR)) + if ((save->version < Version(93, 0) && parts[i].ctype == SPC_AIR) || + (save->version < Version(88, 0) && parts[i].ctype == OLD_SPC_AIR)) { player.fan = true; } @@ -165,8 +165,8 @@ std::vector Simulation::Load(const GameSave *save, bool includePress Element_STKM_init_legs(this, &player2, i); player2.spwn = 1; player2.elem = PT_DUST; - if ((save->majorVersion < 93 && parts[i].ctype == SPC_AIR) || - (save->majorVersion < 88 && parts[i].ctype == OLD_SPC_AIR)) + if ((save->version < Version(93, 0) && parts[i].ctype == SPC_AIR) || + (save->version < Version(88, 0) && parts[i].ctype == OLD_SPC_AIR)) { player2.fan = true; } @@ -189,8 +189,8 @@ std::vector Simulation::Load(const GameSave *save, bool includePress if (parts[i].tmp >= 0) { bool fan = false; - if ((save->majorVersion < 93 && parts[i].ctype == SPC_AIR) - || (save->majorVersion < 88 && parts[i].ctype == OLD_SPC_AIR)) + if ((save->version < Version(93, 0) && parts[i].ctype == SPC_AIR) + || (save->version < Version(88, 0) && parts[i].ctype == OLD_SPC_AIR)) { fan = true; parts[i].ctype = 0;