From 33142610bbd579f84cc58393d2d46b6eae799be6 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Mon, 30 Jun 2025 22:12:17 +0200 Subject: [PATCH 1/3] [ZH] Generate git version information and print it in the Game Window title, Main Menu and Options Menu --- Core/CMakeLists.txt | 1 + .../Code/GameEngine/Include/Common/version.h | 46 ++- .../Code/GameEngine/Source/Common/version.cpp | 161 +++++--- .../GUI/GUICallbacks/Menus/MainMenu.cpp | 50 ++- .../GUI/GUICallbacks/Menus/OptionsMenu.cpp | 53 +-- .../GameEngine/Source/GameClient/GameText.cpp | 12 + GeneralsMD/Code/Main/CMakeLists.txt | 2 +- resources/CMakeLists.txt | 20 +- resources/gitinfo/git_watcher.cmake | 345 ++++++++++++++++++ resources/gitinfo/gitinfo.cpp.in | 28 ++ resources/gitinfo/gitinfo.h | 40 ++ 11 files changed, 661 insertions(+), 97 deletions(-) create mode 100644 resources/gitinfo/git_watcher.cmake create mode 100644 resources/gitinfo/gitinfo.cpp.in create mode 100644 resources/gitinfo/gitinfo.h diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index d98066d1bf..6e02803f99 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -12,6 +12,7 @@ target_include_directories(corei_libraries_source_wwvegas_wwlib INTERFACE "Libra target_link_libraries(corei_always INTERFACE core_utility corei_libraries_include + resources ) # Set where the build results will end up diff --git a/GeneralsMD/Code/GameEngine/Include/Common/version.h b/GeneralsMD/Code/GameEngine/Include/Common/version.h index 044df908db..fb0430adc0 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/version.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/version.h @@ -31,6 +31,8 @@ #ifndef __VERSION_H__ #define __VERSION_H__ +#include + /** * The Version class formats the version number into integer and string * values for different parts of the game. @@ -40,16 +42,26 @@ class Version { public: Version(); - UnsignedInt getVersionNumber( void ); ///< Return a 4-byte integer suitable for WOLAPI - AsciiString getAsciiVersion( void ); ///< Return a human-readable version number - UnicodeString getUnicodeVersion( void ); ///< Return a human-readable version number - UnicodeString getFullUnicodeVersion( void ); ///< Return a human-readable version number - AsciiString getAsciiBuildTime( void ); ///< Return a formated date/time string for build time - UnicodeString getUnicodeBuildTime( void ); ///< Return a formated date/time string for build time - AsciiString getAsciiBuildLocation( void ); ///< Return a string with the build location - UnicodeString getUnicodeBuildLocation( void ); ///< Return a string with the build location - AsciiString getAsciiBuildUser( void ); ///< Return a string with the build user - UnicodeString getUnicodeBuildUser( void ); ///< Return a string with the build user + + UnsignedInt getVersionNumber( void ) const; ///< Return a 4-byte integer suitable for WOLAPI + AsciiString getAsciiVersion( void ) const; ///< Return a human-readable version number + UnicodeString getUnicodeVersion( void ) const; ///< Return a human-readable version number + AsciiString getAsciiBuildTime( void ) const; ///< Return a formated date/time string for build time + UnicodeString getUnicodeBuildTime( void ) const; ///< Return a formated date/time string for build time + AsciiString getAsciiBuildLocation( void ) const; ///< Return a string with the build location + UnicodeString getUnicodeBuildLocation( void ) const; ///< Return a string with the build location + AsciiString getAsciiBuildUser( void ) const; ///< Return a string with the build user + UnicodeString getUnicodeBuildUser( void ) const; ///< Return a string with the build user + + static Int getGitRevision(); + static time_t getGitCommitTime(); + AsciiString getAsciiGitRevision( void ) const { return m_asciiGitRevision; } + AsciiString getAsciiGitVersion( void ) const { return m_asciiGitVersion; } + AsciiString getAsciiGitCommitTime( void ) const { return m_asciiGitCommitTime; } + UnicodeString getUnicodeGitRevision( void ) const { return m_unicodeGitRevision; } + UnicodeString getUnicodeGitVersion( void ) const { return m_unicodeGitVersion; } + UnicodeString getUnicodeGitCommitTime( void ) const { return m_unicodeGitCommitTime; } + UnicodeString getUnicodeGameAndGitVersion( void ) const; Bool showFullVersion( void ) { return m_showFullVersion; } void setShowFullVersion( Bool val ) { m_showFullVersion = val; } @@ -58,6 +70,14 @@ class Version Int localBuildNum, AsciiString user, AsciiString location, AsciiString buildTime, AsciiString buildDate); ///< Set version info +private: + static AsciiString buildAsciiGitRevision(); + static AsciiString buildAsciiGitVersion(); + static AsciiString buildAsciiGitCommitTime(); + static UnicodeString buildUnicodeGitRevision(); + static UnicodeString buildUnicodeGitVersion(); + static UnicodeString buildUnicodeGitCommitTime(); + private: Int m_major; Int m_minor; @@ -67,6 +87,12 @@ class Version AsciiString m_buildUser; AsciiString m_buildTime; AsciiString m_buildDate; + AsciiString m_asciiGitRevision; + AsciiString m_asciiGitVersion; + AsciiString m_asciiGitCommitTime; + UnicodeString m_unicodeGitRevision; + UnicodeString m_unicodeGitVersion; + UnicodeString m_unicodeGitCommitTime; Bool m_showFullVersion; }; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/version.cpp b/GeneralsMD/Code/GameEngine/Source/Common/version.cpp index 923b7a204c..53e9ec1273 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/version.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/version.cpp @@ -31,6 +31,8 @@ #include "GameClient/GameText.h" #include "Common/version.h" +#include "gitinfo.h" + Version *TheVersion = NULL; ///< The Version singleton Version::Version() @@ -39,8 +41,14 @@ Version::Version() m_minor = 0; m_buildNum = 0; m_localBuildNum = 0; - m_buildUser = AsciiString("somebody"); - m_buildLocation = AsciiString("somewhere"); + m_buildUser = "somebody"; + m_buildLocation = "somewhere"; + m_asciiGitRevision = buildAsciiGitRevision(); + m_asciiGitVersion = buildAsciiGitVersion(); + m_asciiGitCommitTime = buildAsciiGitCommitTime(); + m_unicodeGitRevision = buildUnicodeGitRevision(); + m_unicodeGitVersion = buildUnicodeGitVersion(); + m_unicodeGitCommitTime = buildUnicodeGitCommitTime(); #if defined RTS_DEBUG || defined RTS_INTERNAL m_showFullVersion = TRUE; #else @@ -62,12 +70,12 @@ void Version::setVersion(Int major, Int minor, Int buildNum, m_buildDate = buildDate; } -UnsignedInt Version::getVersionNumber( void ) +UnsignedInt Version::getVersionNumber( void ) const { return m_major << 16 | m_minor; } -AsciiString Version::getAsciiVersion( void ) +AsciiString Version::getAsciiVersion( void ) const { AsciiString version; #if defined RTS_DEBUG || defined RTS_INTERNAL @@ -83,19 +91,22 @@ AsciiString Version::getAsciiVersion( void ) return version; } -UnicodeString Version::getUnicodeVersion( void ) +UnicodeString Version::getUnicodeVersion( void ) const { UnicodeString version; -#if defined RTS_DEBUG || defined RTS_INTERNAL - if (!m_localBuildNum) - version.format(TheGameText->fetch("Version:Format3").str(), m_major, m_minor, m_buildNum); + if (m_showFullVersion) + { + if (!m_localBuildNum) + version.format(TheGameText->fetch("Version:Format3").str(), m_major, m_minor, m_buildNum); + else + version.format(TheGameText->fetch("Version:Format4").str(), m_major, m_minor, m_buildNum, m_localBuildNum, + m_buildUser.getCharAt(0), m_buildUser.getCharAt(1)); + } else - version.format(TheGameText->fetch("Version:Format4").str(), m_major, m_minor, m_buildNum, m_localBuildNum, - m_buildUser.getCharAt(0), m_buildUser.getCharAt(1)); -#else // defined RTS_DEBUG || defined RTS_INTERNAL - version.format(TheGameText->fetch("Version:Format2").str(), m_major, m_minor); -#endif // defined RTS_DEBUG || defined RTS_INTERNAL + { + version.format(TheGameText->fetch("Version:Format2").str(), m_major, m_minor); + } #ifdef RTS_DEBUG version.concat(UnicodeString(L" Debug")); @@ -108,28 +119,7 @@ UnicodeString Version::getUnicodeVersion( void ) return version; } -UnicodeString Version::getFullUnicodeVersion( void ) -{ - UnicodeString version; - - if (!m_localBuildNum) - version.format(TheGameText->fetch("Version:Format3").str(), m_major, m_minor, m_buildNum); - else - version.format(TheGameText->fetch("Version:Format4").str(), m_major, m_minor, m_buildNum, m_localBuildNum, - m_buildUser.getCharAt(0), m_buildUser.getCharAt(1)); - -#ifdef RTS_DEBUG - version.concat(UnicodeString(L" Debug")); -#endif - -#ifdef RTS_INTERNAL - version.concat(UnicodeString(L" Internal")); -#endif - - return version; -} - -AsciiString Version::getAsciiBuildTime( void ) +AsciiString Version::getAsciiBuildTime( void ) const { AsciiString timeStr; timeStr.format("%s %s", m_buildDate.str(), m_buildTime.str()); @@ -137,7 +127,7 @@ AsciiString Version::getAsciiBuildTime( void ) return timeStr; } -UnicodeString Version::getUnicodeBuildTime( void ) +UnicodeString Version::getUnicodeBuildTime( void ) const { UnicodeString build; UnicodeString dateStr; @@ -150,34 +140,117 @@ UnicodeString Version::getUnicodeBuildTime( void ) return build; } -AsciiString Version::getAsciiBuildLocation( void ) +AsciiString Version::getAsciiBuildLocation( void ) const { - return AsciiString(m_buildLocation); + return m_buildLocation; } -UnicodeString Version::getUnicodeBuildLocation( void ) +UnicodeString Version::getUnicodeBuildLocation( void ) const { UnicodeString build; UnicodeString machine; - machine.translate(AsciiString(m_buildLocation)); + machine.translate(m_buildLocation); build.format(TheGameText->fetch("Version:BuildMachine").str(), machine.str()); return build; } -AsciiString Version::getAsciiBuildUser( void ) +AsciiString Version::getAsciiBuildUser( void ) const { - return AsciiString(m_buildUser); + return m_buildUser; } -UnicodeString Version::getUnicodeBuildUser( void ) +UnicodeString Version::getUnicodeBuildUser( void ) const { UnicodeString build; UnicodeString user; - user.translate(AsciiString(m_buildUser)); + user.translate(m_buildUser); build.format(TheGameText->fetch("Version:BuildUser").str(), user.str()); return build; } + +Int Version::getGitRevision() +{ + return GitRevision; +} + +time_t Version::getGitCommitTime() +{ + return GitCommitTimeStamp; +} + +UnicodeString Version::getUnicodeGameAndGitVersion( void ) const +{ + UnicodeString str; + if (m_showFullVersion) + { + str.format(L"%s %s %s", + getUnicodeVersion().str(), + getUnicodeGitRevision().str(), + getUnicodeGitVersion().str()); + } + else + { + str.format(L"%s %s", + getUnicodeVersion().str(), + getUnicodeGitRevision().str()); + } + return str; +} + +AsciiString Version::buildAsciiGitRevision() +{ + AsciiString str; + str.format("R %s%d", + GitUncommittedChanges ? "~" : "", + GitRevision); + return str; +} + +AsciiString Version::buildAsciiGitVersion() +{ + AsciiString str; + str.format("%s%s", + GitUncommittedChanges ? "~" : "", + GitTag[0] ? GitTag : GitShortSHA1); + return str; +} + +AsciiString Version::buildAsciiGitCommitTime() +{ + const Int len = 19; + AsciiString str; + Char* buf = str.getBufferForRead(len); + tm* time = gmtime(&GitCommitTimeStamp); + strftime(buf, len+1, "%Y-%m-%d %H:%M:%S", time); + return str; +} + +UnicodeString Version::buildUnicodeGitRevision() +{ + UnicodeString str; + str.format(L"R %s%d", + GitUncommittedChanges ? L"~" : L"", + GitRevision); + return str; +} + +UnicodeString Version::buildUnicodeGitVersion() +{ + UnicodeString str; + str.translate(buildAsciiGitVersion()); + return str; +} + +UnicodeString Version::buildUnicodeGitCommitTime() +{ + const Int len = 19; + UnicodeString str; + WideChar* buf = str.getBufferForRead(len); + tm* time = gmtime(&GitCommitTimeStamp); + wcsftime(buf, len+1, L"%Y-%m-%d %H:%M:%S", time); + return str; +} diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp index f507410f4d..02384cef4d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp @@ -447,6 +447,36 @@ GameWindow *win = NULL; win->winHide(TRUE); } + +// TheSuperHackers @tweak Now prints version information in an optional version label. +// Originally this label does not exist in the Main Menu. It can be copied from the Options Menu. +static void initLabelVersion() +{ + NameKeyType versionID = TheNameKeyGenerator->nameToKey( AsciiString("MainMenu.wnd:LabelVersion") ); + GameWindow *labelVersion = TheWindowManager->winGetWindowFromId( NULL, versionID ); + + if (labelVersion) + { + if (TheVersion && TheGlobalData) + { + UnicodeString version; + version.format( + L"%s %s exe:%08X ini:%08X %s", + TheVersion->getUnicodeGameAndGitVersion().str(), + TheVersion->getUnicodeGitCommitTime().str(), + TheGlobalData->m_exeCRC, + TheGlobalData->m_iniCRC, + TheVersion->getUnicodeBuildUser().str() + ); + GadgetStaticTextSetText( labelVersion, version ); + } + else + { + labelVersion->winHide( TRUE ); + } + } +} + //------------------------------------------------------------------------------------------------- /** Initialize the main menu */ //------------------------------------------------------------------------------------------------- @@ -476,7 +506,6 @@ void MainMenuInit( WindowLayout *layout, void *userData ) exitID = TheNameKeyGenerator->nameToKey( AsciiString("MainMenu.wnd:ButtonExit") ); motdID = TheNameKeyGenerator->nameToKey( AsciiString("MainMenu.wnd:ButtonMOTD") ); worldBuilderID = TheNameKeyGenerator->nameToKey( AsciiString("MainMenu.wnd:ButtonWorldBuilder") ); -// NameKeyType versionID = TheNameKeyGenerator->nameToKey( AsciiString("MainMenu.wnd:LabelVersion") ); getUpdateID = TheNameKeyGenerator->nameToKey( AsciiString("MainMenu.wnd:ButtonGetUpdate") ); // buttonTRAININGID = TheNameKeyGenerator->nameToKey( AsciiString("MainMenu.wnd:ButtonTRAINING") ); buttonChallengeID = TheNameKeyGenerator->nameToKey( AsciiString("MainMenu.wnd:ButtonChallenge") ); @@ -526,9 +555,6 @@ void MainMenuInit( WindowLayout *layout, void *userData ) buttonHard = TheWindowManager->winGetWindowFromId( parentMainMenu, buttonHardID ); buttonDiffBack = TheWindowManager->winGetWindowFromId( parentMainMenu, buttonDiffBackID ); - -// GameWindow *labelVersion = TheWindowManager->winGetWindowFromId( parentMainMenu, versionID ); - getUpdate = TheWindowManager->winGetWindowFromId( parentMainMenu, getUpdateID ); // buttonTRAINING = TheWindowManager->winGetWindowFromId( parentMainMenu, buttonTRAININGID ); buttonChallenge = TheWindowManager->winGetWindowFromId( parentMainMenu, buttonChallengeID ); @@ -578,22 +604,10 @@ void MainMenuInit( WindowLayout *layout, void *userData ) 25, 54, 180, 26, &instData, NULL, TRUE ); - -// if (TheVersion) -// { -// UnicodeString version; -// version.format(L"%s\n%s", TheVersion->getUnicodeVersion().str(), TheVersion->getUnicodeBuildTime().str()); -// GadgetStaticTextSetText( labelVersion, version ); -// } -// else -// { -// labelVersion->winHide( TRUE ); -// } -//#else - -// GadgetStaticTextSetText( labelVersion, TheVersion->getUnicodeVersion() ); #endif + initLabelVersion(); + //TheShell->registerWithAnimateManager(buttonCampaign, WIN_ANIMATION_SLIDE_LEFT, TRUE, 800); //TheShell->registerWithAnimateManager(buttonSkirmish, WIN_ANIMATION_SLIDE_LEFT, TRUE, 600); // TheShell->registerWithAnimateManager(buttonSinglePlayer, WIN_ANIMATION_SLIDE_LEFT, TRUE, 400); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index b2c132d0c9..bb9dd6131b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -1361,6 +1361,35 @@ static void cancelAdvancedOptions() WinAdvancedDisplay->winHide(TRUE); } + +// TheSuperHackers @tweak Now prints additional version information in the version label. +static void initLabelVersion() +{ + NameKeyType versionID = TheNameKeyGenerator->nameToKey( AsciiString("OptionsMenu.wnd:LabelVersion") ); + GameWindow *labelVersion = TheWindowManager->winGetWindowFromId( NULL, versionID ); + + if (labelVersion) + { + if (TheVersion && TheGlobalData) + { + UnicodeString version; + version.format( + L"%s %s exe:%08X ini:%08X %s", + TheVersion->getUnicodeGameAndGitVersion().str(), + TheVersion->getUnicodeGitCommitTime().str(), + TheGlobalData->m_exeCRC, + TheGlobalData->m_iniCRC, + TheVersion->getUnicodeBuildUser().str() + ); + GadgetStaticTextSetText( labelVersion, version ); + } + else + { + labelVersion->winHide( TRUE ); + } + } +} + //------------------------------------------------------------------------------------------------- /** Initialize the options menu */ //------------------------------------------------------------------------------------------------- @@ -1492,29 +1521,7 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) NUM_ALIASING_MODES }; - NameKeyType versionID = TheNameKeyGenerator->nameToKey( AsciiString("OptionsMenu.wnd:LabelVersion") ); - GameWindow *labelVersion = TheWindowManager->winGetWindowFromId( NULL, versionID ); - UnicodeString versionString; - versionString.format(TheGameText->fetch("Version:Format2").str(), (GetRegistryVersion() >> 16), (GetRegistryVersion() & 0xffff)); - - if (TheVersion->showFullVersion()) - { - if (TheVersion) - { - UnicodeString version; - version.format(L"(%s) %s -- %s", versionString.str(), TheVersion->getFullUnicodeVersion().str(), TheVersion->getUnicodeBuildTime().str()); - GadgetStaticTextSetText( labelVersion, version ); - } - else - { - labelVersion->winHide( TRUE ); - } - } - else - { - GadgetStaticTextSetText( labelVersion, versionString ); - } - + initLabelVersion(); // Choose an IP address, then initialize the IP combo box UnsignedInt selectedIP = pref->getLANIPAddress(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameText.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameText.cpp index 163018fbd2..e7fafd3229 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameText.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameText.cpp @@ -56,6 +56,7 @@ #include "Common/GlobalData.h" #include "Common/file.h" #include "Common/FileSystem.h" +#include "Common/version.h" #ifdef RTS_INTERNAL @@ -381,6 +382,17 @@ void GameTextManager::init( void ) ourName = s; } + if (TheVersion != NULL) + { + // TheSuperHackers @tweak Now prints version information in the Window title. + UnicodeString version; + version.format(L" %s %s", + TheVersion->getUnicodeGameAndGitVersion().str(), + TheVersion->getUnicodeBuildUser().str() + ); + ourName.concat(version); + } + AsciiString ourNameA; ourNameA.translate(ourName); //get ASCII version for Win 9x diff --git a/GeneralsMD/Code/Main/CMakeLists.txt b/GeneralsMD/Code/Main/CMakeLists.txt index 2ef80b3e87..f14860c9b4 100644 --- a/GeneralsMD/Code/Main/CMakeLists.txt +++ b/GeneralsMD/Code/Main/CMakeLists.txt @@ -31,7 +31,7 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/GeneratedVersion.h "#pragma once #define VERSION_LOCALBUILDNUM 0 -#define VERSION_BUILDUSER \"Someone\" +#define VERSION_BUILDUSER \"The Super Hackers\" #define VERSION_BUILDLOC \"Someplace\" " ) diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index f94cc67511..d8d613ca9b 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -1,6 +1,24 @@ +# Create gitinfo.cpp +set(GIT_PRE_CONFIGURE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/gitinfo/gitinfo.cpp.in") +set(GIT_POST_CONFIGURE_FILE "${CMAKE_CURRENT_BINARY_DIR}/gitinfo.cpp") + +include(gitinfo/git_watcher.cmake) + +# Create resources library +add_library(resources STATIC) + +target_sources(resources PRIVATE + "${CMAKE_CURRENT_BINARY_DIR}/gitinfo.cpp" + gitinfo/gitinfo.h +) + +target_include_directories(resources PUBLIC + gitinfo +) + # Add resources (optional) if (MSVC_IDE) - add_library(resources INTERFACE + target_sources(resources PRIVATE visualstudio/asciistring.natvis visualstudio/stllist.natvis visualstudio/stlvector.natvis diff --git a/resources/gitinfo/git_watcher.cmake b/resources/gitinfo/git_watcher.cmake new file mode 100644 index 0000000000..0b4426cffa --- /dev/null +++ b/resources/gitinfo/git_watcher.cmake @@ -0,0 +1,345 @@ +# git_watcher.cmake +# https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git_watcher.cmake +# +# Released under the MIT License. +# https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE + + +# This file defines a target that monitors the state of a git repo. +# If the state changes (e.g. a commit is made), then a file gets reconfigured. +# Here are the primary variables that control script behavior: +# +# GIT_PRE_CONFIGURE_FILE (REQUIRED) +# -- The path to the file that'll be configured. +# +# GIT_POST_CONFIGURE_FILE (REQUIRED) +# -- The path to the configured GIT_PRE_CONFIGURE_FILE. +# +# GIT_STATE_FILE (OPTIONAL) +# -- The path to the file used to store the previous build's git state. +# Defaults to the current binary directory. +# +# GIT_WORKING_DIR (OPTIONAL) +# -- The directory from which git commands will be run. +# Defaults to the directory with the top level CMakeLists.txt. +# +# GIT_EXECUTABLE (OPTIONAL) +# -- The path to the git executable. It'll automatically be set if the +# user doesn't supply a path. +# +# DESIGN +# - This script was designed similar to a Python application +# with a Main() function. I wanted to keep it compact to +# simplify "copy + paste" usage. +# +# - This script is invoked under two CMake contexts: +# 1. Configure time (when build files are created). +# 2. Build time (called via CMake -P). +# The first invocation is what registers the script to +# be executed at build time. +# +# MODIFICATIONS +# You may wish to track other git properties like when the last +# commit was made. There are two sections you need to modify, +# and they're tagged with a ">>>" header. + +# Short hand for converting paths to absolute. +macro(PATH_TO_ABSOLUTE var_name) + get_filename_component(${var_name} "${${var_name}}" ABSOLUTE) +endmacro() + +# Check that a required variable is set. +macro(CHECK_REQUIRED_VARIABLE var_name) + if(NOT DEFINED ${var_name}) + message(FATAL_ERROR "The \"${var_name}\" variable must be defined.") + endif() + PATH_TO_ABSOLUTE(${var_name}) +endmacro() + +# Check that an optional variable is set, or, set it to a default value. +macro(CHECK_OPTIONAL_VARIABLE var_name default_value) + if(NOT DEFINED ${var_name}) + set(${var_name} ${default_value}) + endif() + PATH_TO_ABSOLUTE(${var_name}) +endmacro() + +CHECK_REQUIRED_VARIABLE(GIT_PRE_CONFIGURE_FILE) +CHECK_REQUIRED_VARIABLE(GIT_POST_CONFIGURE_FILE) +CHECK_OPTIONAL_VARIABLE(GIT_STATE_FILE "${CMAKE_BINARY_DIR}/git-state-hash") +CHECK_OPTIONAL_VARIABLE(GIT_WORKING_DIR "${CMAKE_SOURCE_DIR}") + +# Check the optional git variable. +# If it's not set, we'll try to find it using the CMake packaging system. +if(NOT DEFINED GIT_EXECUTABLE) + find_package(Git QUIET REQUIRED) +endif() +CHECK_REQUIRED_VARIABLE(GIT_EXECUTABLE) + + +set(_state_variable_names + GIT_RETRIEVED_STATE + GIT_HEAD_SHA1 + GIT_IS_DIRTY + GIT_AUTHOR_NAME + GIT_AUTHOR_EMAIL + GIT_COMMIT_DATE_ISO8601 + GIT_COMMIT_SUBJECT + GIT_COMMIT_BODY + GIT_COMMIT_TSTAMP + GIT_HEAD_SHORT_SHA1 + GIT_REV_LIST_COUNT + GIT_TAG + # >>> + # 1. Add the name of the additional git variable you're interested in monitoring + # to this list. +) + + + +# Macro: RunGitCommand +# Description: short-hand macro for calling a git function. Outputs are the +# "exit_code" and "output" variables. +macro(RunGitCommand) + execute_process(COMMAND + "${GIT_EXECUTABLE}" ${ARGV} + WORKING_DIRECTORY "${_working_dir}" + RESULT_VARIABLE exit_code + OUTPUT_VARIABLE output + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT exit_code EQUAL 0) + set(ENV{GIT_RETRIEVED_STATE} "false") + endif() +endmacro() + + + +# Function: GetGitState +# Description: gets the current state of the git repo. +# Args: +# _working_dir (in) string; the directory from which git commands will be executed. +function(GetGitState _working_dir) + + # This is an error code that'll be set to FALSE if the + # RunGitCommand ever returns a non-zero exit code. + set(ENV{GIT_RETRIEVED_STATE} "true") + + if(GIT_EXECUTABLE) + # Get whether or not the working tree is dirty. + RunGitCommand(status --porcelain) + if(NOT exit_code EQUAL 0) + set(ENV{GIT_IS_DIRTY} "false") + else() + if(NOT "${output}" STREQUAL "") + set(ENV{GIT_IS_DIRTY} "true") + else() + set(ENV{GIT_IS_DIRTY} "false") + endif() + endif() + + # There's a long list of attributes grabbed from git show. + set(object HEAD) + RunGitCommand(show -s "--format=%H" ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_HEAD_SHA1} ${output}) + endif() + + RunGitCommand(show -s "--format=%an" ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_AUTHOR_NAME} "${output}") + endif() + + RunGitCommand(show -s "--format=%ae" ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_AUTHOR_EMAIL} "${output}") + endif() + + RunGitCommand(show -s "--format=%ci" ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_COMMIT_DATE_ISO8601} "${output}") + endif() + + RunGitCommand(show -s "--format=%s" ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_COMMIT_SUBJECT} "${output}") + endif() + + RunGitCommand(show -s "--format=%b" ${object}) + if(exit_code EQUAL 0) + if(output) + # Escape line breaks in the commit message. + string(REPLACE "\r\n" "\\r\\n\\\r\n" safe ${output}) + if(safe STREQUAL output) + # Didn't have windows lines - try unix lines. + string(REPLACE "\n" "\\n\\\n" safe ${output}) + endif() + else() + # There was no commit body - set the safe string to empty. + set(safe "") + endif() + set(ENV{GIT_COMMIT_BODY} "\"${safe}\"") + else() + set(ENV{GIT_COMMIT_BODY} "\"\"") # empty string. + endif() + + RunGitCommand(show -s "--format=%ct" ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_COMMIT_TSTAMP} "${output}") + else() + set(ENV{GIT_COMMIT_TSTAMP} "0") + endif() + + RunGitCommand(show -s "--format=%h" ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_HEAD_SHORT_SHA1} ${output}) + endif() + + RunGitCommand(rev-list --count ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_REV_LIST_COUNT} ${output}) + else() + set(ENV{GIT_REV_LIST_COUNT} "0") + endif() + + RunGitCommand(describe --tags ${object}) + if(exit_code EQUAL 0) + set(ENV{GIT_TAG} ${output}) + else() + set(ENV{GIT_TAG} "") + endif() + + # >>> + # 2. Additional git properties can be added here via the + # "execute_process()" command. Be sure to set them in + # the environment using the same variable name you added + # to the "_state_variable_names" list. + else() + set(ENV{GIT_IS_DIRTY} "true") + set(ENV{GIT_HEAD_SHA1} "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF") + set(ENV{GIT_AUTHOR_NAME} "Someone") + set(ENV{GIT_AUTHOR_EMAIL} "someone@someplace.org") + set(ENV{GIT_COMMIT_DATE_ISO8601} "1955-11-12 22:04:00 +0000") + set(ENV{GIT_COMMIT_SUBJECT} "Git Not Found") + set(ENV{GIT_COMMIT_BODY} "\"\"") # empty string. + set(ENV{GIT_COMMIT_TSTAMP} "0") + set(ENV{GIT_HEAD_SHORT_SHA1} "DEADBEEF") + set(ENV{GIT_REV_LIST_COUNT} "0") + set(ENV{GIT_TAG} "") + endif() + +endfunction() + + + +# Function: GitStateChangedAction +# Description: this function is executed when the state of the git +# repository changes (e.g. a commit is made). +function(GitStateChangedAction) + foreach(var_name ${_state_variable_names}) + set(${var_name} $ENV{${var_name}}) + endforeach() + configure_file("${GIT_PRE_CONFIGURE_FILE}" "${GIT_POST_CONFIGURE_FILE}" @ONLY) +endfunction() + + + +# Function: HashGitState +# Description: loop through the git state variables and compute a unique hash. +# Args: +# _state (out) string; a hash computed from the current git state. +function(HashGitState _state) + set(ans "") + foreach(var_name ${_state_variable_names}) + string(SHA256 ans "${ans}$ENV{${var_name}}") + endforeach() + set(${_state} ${ans} PARENT_SCOPE) +endfunction() + + + +# Function: CheckGit +# Description: check if the git repo has changed. If so, update the state file. +# Args: +# _working_dir (in) string; the directory from which git commands will be ran. +# _state_changed (out) bool; whether or no the state of the repo has changed. +function(CheckGit _working_dir _state_changed) + + # Get the current state of the repo. + GetGitState("${_working_dir}") + + # Convert that state into a hash that we can compare against + # the hash stored on-disk. + HashGitState(state) + + # Issue 14: post-configure file isn't being regenerated. + # + # Update the state to include the SHA256 for the pre-configure file. + # This forces the post-configure file to be regenerated if the + # pre-configure file has changed. + file(SHA256 ${GIT_PRE_CONFIGURE_FILE} preconfig_hash) + string(SHA256 state "${preconfig_hash}${state}") + + # Check if the state has changed compared to the backup on disk. + if(EXISTS "${GIT_STATE_FILE}") + file(READ "${GIT_STATE_FILE}" OLD_HEAD_CONTENTS) + if(OLD_HEAD_CONTENTS STREQUAL "${state}") + # State didn't change. + set(${_state_changed} "false" PARENT_SCOPE) + return() + endif() + endif() + + # The state has changed. + # We need to update the state file on disk. + # Future builds will compare their state to this file. + file(WRITE "${GIT_STATE_FILE}" "${state}") + set(${_state_changed} "true" PARENT_SCOPE) +endfunction() + + + +# Function: SetupGitMonitoring +# Description: this function sets up custom commands that make the build system +# check the state of git before every build. If the state has +# changed, then a file is configured. +function(SetupGitMonitoring) + add_custom_target(check_git + ALL + DEPENDS ${GIT_PRE_CONFIGURE_FILE} + BYPRODUCTS + ${GIT_POST_CONFIGURE_FILE} + ${GIT_STATE_FILE} + COMMENT "Checking the git repository for changes..." + COMMAND + ${CMAKE_COMMAND} + -D_BUILD_TIME_CHECK_GIT=TRUE + -DGIT_WORKING_DIR=${GIT_WORKING_DIR} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + -DGIT_STATE_FILE=${GIT_STATE_FILE} + -DGIT_PRE_CONFIGURE_FILE=${GIT_PRE_CONFIGURE_FILE} + -DGIT_POST_CONFIGURE_FILE=${GIT_POST_CONFIGURE_FILE} + -P "${CMAKE_CURRENT_LIST_FILE}") +endfunction() + + + +# Function: Main +# Description: primary entry-point to the script. Functions are selected based +# on whether it's configure or build time. +function(Main) + if(_BUILD_TIME_CHECK_GIT) + # Check if the repo has changed. + # If so, run the change action. + CheckGit("${GIT_WORKING_DIR}" changed) + if(changed OR NOT EXISTS "${GIT_POST_CONFIGURE_FILE}") + GitStateChangedAction() + endif() + else() + # >> Executes at configure time. + SetupGitMonitoring() + endif() +endfunction() + +# And off we go... +Main() diff --git a/resources/gitinfo/gitinfo.cpp.in b/resources/gitinfo/gitinfo.cpp.in new file mode 100644 index 0000000000..6ab0802d01 --- /dev/null +++ b/resources/gitinfo/gitinfo.cpp.in @@ -0,0 +1,28 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ +#include "gitinfo.h" + +const char GitSHA1[] = "@GIT_HEAD_SHA1@"; +const char GitShortSHA1[] = "@GIT_HEAD_SHORT_SHA1@"; +const char GitCommitDate[] = "@GIT_COMMIT_DATE_ISO8601@"; +const char GitCommitAuthorName[] = "@GIT_AUTHOR_NAME@"; +const char GitTag[] = "@GIT_TAG@"; +time_t GitCommitTimeStamp = @GIT_COMMIT_TSTAMP@; +bool GitUncommittedChanges = @GIT_IS_DIRTY@; +bool GitHaveInfo = @GIT_RETRIEVED_STATE@; +int GitRevision = @GIT_REV_LIST_COUNT@; diff --git a/resources/gitinfo/gitinfo.h b/resources/gitinfo/gitinfo.h new file mode 100644 index 0000000000..6fbd55fffe --- /dev/null +++ b/resources/gitinfo/gitinfo.h @@ -0,0 +1,40 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#else +#include +#endif + +extern const char GitSHA1[]; +extern const char GitShortSHA1[]; +extern const char GitCommitDate[]; +extern const char GitCommitAuthorName[]; +extern const char GitTag[]; +extern time_t GitCommitTimeStamp; +extern bool GitUncommittedChanges; +extern bool GitHaveInfo; +extern int GitRevision; + +#ifdef __cplusplus +} // extern "C" +#endif From 87ea8e864626d70ae0abc2b1b15ca17954a69d2d Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 2 Jul 2025 20:01:50 +0200 Subject: [PATCH 2/3] Now use git commit author if no build user is specified, log out git info, fix getAsciiVersion to be consistent with getUnicodeVersion, add comment, remove ( void ), fix Version function ordering --- .../Code/GameEngine/Include/Common/version.h | 67 ++++-- .../GameEngine/Source/Common/GameEngine.cpp | 15 +- .../Code/GameEngine/Source/Common/version.cpp | 213 ++++++++++++++---- .../GUI/GUICallbacks/Menus/MainMenu.cpp | 2 +- .../GUI/GUICallbacks/Menus/OptionsMenu.cpp | 2 +- .../GameEngine/Source/GameClient/GameText.cpp | 2 +- GeneralsMD/Code/Main/CMakeLists.txt | 4 +- 7 files changed, 218 insertions(+), 87 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/version.h b/GeneralsMD/Code/GameEngine/Include/Common/version.h index fb0430adc0..32b41cb788 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/version.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/version.h @@ -38,44 +38,61 @@ * values for different parts of the game. * @todo: increment build number on compile, and stamp exe with username */ +// TheSuperHackers @tweak The Version class now also provides Git information +// alongside the original Version information. class Version { public: Version(); - UnsignedInt getVersionNumber( void ) const; ///< Return a 4-byte integer suitable for WOLAPI - AsciiString getAsciiVersion( void ) const; ///< Return a human-readable version number - UnicodeString getUnicodeVersion( void ) const; ///< Return a human-readable version number - AsciiString getAsciiBuildTime( void ) const; ///< Return a formated date/time string for build time - UnicodeString getUnicodeBuildTime( void ) const; ///< Return a formated date/time string for build time - AsciiString getAsciiBuildLocation( void ) const; ///< Return a string with the build location - UnicodeString getUnicodeBuildLocation( void ) const; ///< Return a string with the build location - AsciiString getAsciiBuildUser( void ) const; ///< Return a string with the build user - UnicodeString getUnicodeBuildUser( void ) const; ///< Return a string with the build user - - static Int getGitRevision(); - static time_t getGitCommitTime(); - AsciiString getAsciiGitRevision( void ) const { return m_asciiGitRevision; } - AsciiString getAsciiGitVersion( void ) const { return m_asciiGitVersion; } - AsciiString getAsciiGitCommitTime( void ) const { return m_asciiGitCommitTime; } - UnicodeString getUnicodeGitRevision( void ) const { return m_unicodeGitRevision; } - UnicodeString getUnicodeGitVersion( void ) const { return m_unicodeGitVersion; } - UnicodeString getUnicodeGitCommitTime( void ) const { return m_unicodeGitCommitTime; } - UnicodeString getUnicodeGameAndGitVersion( void ) const; - - Bool showFullVersion( void ) { return m_showFullVersion; } + UnsignedInt getVersionNumber() const; ///< Return a 4-byte integer suitable for WOLAPI + + AsciiString getAsciiVersion() const; ///< Return a human-readable version number + UnicodeString getUnicodeVersion() const; ///< Return a human-readable version number. Is decorated with localized string + + AsciiString getAsciiBuildTime() const; ///< Return a formated date/time string for build time + UnicodeString getUnicodeBuildTime() const; ///< Return a formated date/time string for build time. Is decorated with localized string + + AsciiString getAsciiBuildLocation() const; ///< Return a string with the build location + UnicodeString getUnicodeBuildLocation() const; ///< Return a string with the build location. Is decorated with localized string + + AsciiString getAsciiBuildUser() const; ///< Return a string with the build user + UnicodeString getUnicodeBuildUser() const; ///< Return a string with the build user. Is decorated with localized string + + static Int getGitRevision(); ///< Returns the total git commit count as a number + static time_t getGitCommitTime(); ///< Returns the last git commit time as a UTC timestamp + static const char* getGitCommitAuthorName(); ///< Returns the last git commit author name + + AsciiString getAsciiGitRevision() const; ///< Returns the total git commit count. Is prefixed with ~ if there were uncommitted changes. + UnicodeString getUnicodeGitRevision() const; ///< Returns the total git commit count. Is prefixed with ~ if there were uncommitted changes. + + AsciiString getAsciiGitVersion() const; ///< Returns the last git commit tag or hash. Is prefixed with ~ if there were uncommitted changes. + UnicodeString getUnicodeGitVersion() const; ///< Returns the last git commit tag or hash. Is prefixed with ~ if there were uncommitted changes. + + AsciiString getAsciiGitCommitTime() const; ///< Returns the last git commit time in YYYY-mm-dd HH:MM:SS format + UnicodeString getUnicodeGitCommitTime() const; ///< Returns the last git commit time in YYYY-mm-dd HH:MM:SS format + + AsciiString getAsciiGameAndGitVersion() const; ///< Returns the game and git version + UnicodeString getUnicodeGameAndGitVersion() const; ///< Returns the game and git version. Is decorated with localized string + + AsciiString getAsciiBuildUserOrGitCommitAuthorName() const; + UnicodeString getUnicodeBuildUserOrGitCommitAuthorName() const; ///< Is decorated with localized string + + Bool showFullVersion() const { return m_showFullVersion; } void setShowFullVersion( Bool val ) { m_showFullVersion = val; } void setVersion(Int major, Int minor, Int buildNum, Int localBuildNum, AsciiString user, AsciiString location, - AsciiString buildTime, AsciiString buildDate); ///< Set version info + AsciiString buildTime, AsciiString buildDate); private: static AsciiString buildAsciiGitRevision(); - static AsciiString buildAsciiGitVersion(); - static AsciiString buildAsciiGitCommitTime(); static UnicodeString buildUnicodeGitRevision(); + + static AsciiString buildAsciiGitVersion(); static UnicodeString buildUnicodeGitVersion(); + + static AsciiString buildAsciiGitCommitTime(); static UnicodeString buildUnicodeGitCommitTime(); private: @@ -96,6 +113,6 @@ class Version Bool m_showFullVersion; }; -extern Version *TheVersion; ///< The Version singleton +extern Version *TheVersion; #endif // __VERSION_H__ diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp index f95a046a49..c38a1f9156 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp @@ -261,17 +261,14 @@ void GameEngine::init() if (TheVersion) { DEBUG_LOG(("================================================================================\n")); - #if defined RTS_DEBUG - const char *buildType = "Debug"; - #elif defined RTS_INTERNAL - const char *buildType = "Internal"; - #else - const char *buildType = "Release"; - #endif - DEBUG_LOG(("Generals version %s (%s)\n", TheVersion->getAsciiVersion().str(), buildType)); + DEBUG_LOG(("Generals version %s\n", TheVersion->getAsciiVersion().str())); DEBUG_LOG(("Build date: %s\n", TheVersion->getAsciiBuildTime().str())); DEBUG_LOG(("Build location: %s\n", TheVersion->getAsciiBuildLocation().str())); - DEBUG_LOG(("Built by: %s\n", TheVersion->getAsciiBuildUser().str())); + DEBUG_LOG(("Build user: %s\n", TheVersion->getAsciiBuildUser().str())); + DEBUG_LOG(("Build git revision: %s\n", TheVersion->getAsciiGitRevision().str())); + DEBUG_LOG(("Build git version: %s\n", TheVersion->getAsciiGitVersion().str())); + DEBUG_LOG(("Build git commit time: %s\n", TheVersion->getAsciiGitCommitTime().str())); + DEBUG_LOG(("Build git commit author: %s\n", Version::getGitCommitAuthorName())); DEBUG_LOG(("================================================================================\n")); } #endif diff --git a/GeneralsMD/Code/GameEngine/Source/Common/version.cpp b/GeneralsMD/Code/GameEngine/Source/Common/version.cpp index 53e9ec1273..f60b5b2256 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/version.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/version.cpp @@ -41,8 +41,8 @@ Version::Version() m_minor = 0; m_buildNum = 0; m_localBuildNum = 0; - m_buildUser = "somebody"; - m_buildLocation = "somewhere"; + m_buildUser = AsciiString::TheEmptyString; + m_buildLocation = AsciiString::TheEmptyString; m_asciiGitRevision = buildAsciiGitRevision(); m_asciiGitVersion = buildAsciiGitVersion(); m_asciiGitCommitTime = buildAsciiGitCommitTime(); @@ -70,38 +70,68 @@ void Version::setVersion(Int major, Int minor, Int buildNum, m_buildDate = buildDate; } -UnsignedInt Version::getVersionNumber( void ) const +UnsignedInt Version::getVersionNumber() const { return m_major << 16 | m_minor; } -AsciiString Version::getAsciiVersion( void ) const +AsciiString Version::getAsciiVersion() const { AsciiString version; -#if defined RTS_DEBUG || defined RTS_INTERNAL - if (m_localBuildNum) - version.format("%d.%d.%d.%d%c%c", m_major, m_minor, m_buildNum, m_localBuildNum, - m_buildUser.getCharAt(0), m_buildUser.getCharAt(1)); + + if (m_showFullVersion) + { + if (!m_localBuildNum) + { + version.format("%d.%d.%d", m_major, m_minor, m_buildNum); + } + else + { + AsciiString user = getAsciiBuildUserOrGitCommitAuthorName(); + // User name requires at least 2 characters + if (user.getLength() < 2) + user.concat("xx"); + + version.format("%d.%d.%d.%d%c%c", m_major, m_minor, m_buildNum, m_localBuildNum, + user.getCharAt(0), user.getCharAt(1)); + } + } else - version.format("%d.%d.%d", m_major, m_minor, m_buildNum); -#else // defined RTS_DEBUG || defined RTS_INTERNAL - version.format("%d.%d", m_major, m_minor); -#endif // defined RTS_DEBUG || defined RTS_INTERNAL + { + version.format("%d.%d", m_major, m_minor); + } + +#ifdef RTS_DEBUG + version.concat(" Debug"); +#endif + +#ifdef RTS_INTERNAL + version.concat(" Internal"); +#endif return version; } -UnicodeString Version::getUnicodeVersion( void ) const +UnicodeString Version::getUnicodeVersion() const { UnicodeString version; if (m_showFullVersion) { if (!m_localBuildNum) + { version.format(TheGameText->fetch("Version:Format3").str(), m_major, m_minor, m_buildNum); + } else + { + UnicodeString user = getUnicodeBuildUserOrGitCommitAuthorName(); + // User name requires at least 2 characters + if (user.getLength() < 2) + user.concat(L"xx"); + version.format(TheGameText->fetch("Version:Format4").str(), m_major, m_minor, m_buildNum, m_localBuildNum, - m_buildUser.getCharAt(0), m_buildUser.getCharAt(1)); + user.getCharAt(0), user.getCharAt(1)); + } } else { @@ -109,17 +139,17 @@ UnicodeString Version::getUnicodeVersion( void ) const } #ifdef RTS_DEBUG - version.concat(UnicodeString(L" Debug")); + version.concat(L" Debug"); #endif #ifdef RTS_INTERNAL - version.concat(UnicodeString(L" Internal")); + version.concat(L" Internal"); #endif return version; } -AsciiString Version::getAsciiBuildTime( void ) const +AsciiString Version::getAsciiBuildTime() const { AsciiString timeStr; timeStr.format("%s %s", m_buildDate.str(), m_buildTime.str()); @@ -127,7 +157,7 @@ AsciiString Version::getAsciiBuildTime( void ) const return timeStr; } -UnicodeString Version::getUnicodeBuildTime( void ) const +UnicodeString Version::getUnicodeBuildTime() const { UnicodeString build; UnicodeString dateStr; @@ -140,34 +170,40 @@ UnicodeString Version::getUnicodeBuildTime( void ) const return build; } -AsciiString Version::getAsciiBuildLocation( void ) const +AsciiString Version::getAsciiBuildLocation() const { return m_buildLocation; } -UnicodeString Version::getUnicodeBuildLocation( void ) const +UnicodeString Version::getUnicodeBuildLocation() const { UnicodeString build; - UnicodeString machine; - machine.translate(m_buildLocation); - build.format(TheGameText->fetch("Version:BuildMachine").str(), machine.str()); + if (!m_buildLocation.isEmpty()) + { + UnicodeString machine; + machine.translate(m_buildLocation); + build.format(TheGameText->fetch("Version:BuildMachine").str(), machine.str()); + } return build; } -AsciiString Version::getAsciiBuildUser( void ) const +AsciiString Version::getAsciiBuildUser() const { return m_buildUser; } -UnicodeString Version::getUnicodeBuildUser( void ) const +UnicodeString Version::getUnicodeBuildUser() const { UnicodeString build; - UnicodeString user; - user.translate(m_buildUser); - build.format(TheGameText->fetch("Version:BuildUser").str(), user.str()); + if (!m_buildUser.isEmpty()) + { + UnicodeString user; + user.translate(m_buildUser); + build.format(TheGameText->fetch("Version:BuildUser").str(), user.str()); + } return build; } @@ -182,62 +218,133 @@ time_t Version::getGitCommitTime() return GitCommitTimeStamp; } -UnicodeString Version::getUnicodeGameAndGitVersion( void ) const +const char* Version::getGitCommitAuthorName() +{ + return GitCommitAuthorName; +} + +AsciiString Version::getAsciiGitRevision() const +{ + return m_asciiGitRevision; +} + +UnicodeString Version::getUnicodeGitRevision() const +{ + return m_unicodeGitRevision; +} + +AsciiString Version::getAsciiGitVersion() const +{ + return m_asciiGitVersion; +} + +UnicodeString Version::getUnicodeGitVersion() const +{ + return m_unicodeGitVersion; +} + +AsciiString Version::getAsciiGitCommitTime() const +{ + return m_asciiGitCommitTime; +} + +UnicodeString Version::getUnicodeGitCommitTime() const +{ + return m_unicodeGitCommitTime; +} + +AsciiString Version::getAsciiGameAndGitVersion() const +{ + AsciiString str; + if (m_showFullVersion) + { + str.format("%s R %s %s", + getAsciiVersion().str(), + getAsciiGitRevision().str(), + getAsciiGitVersion().str()); + } + else + { + str.format("%s R %s", + getAsciiVersion().str(), + getAsciiGitRevision().str()); + } + return str; +} + +UnicodeString Version::getUnicodeGameAndGitVersion() const { UnicodeString str; if (m_showFullVersion) { - str.format(L"%s %s %s", + str.format(L"%s R %s %s", getUnicodeVersion().str(), getUnicodeGitRevision().str(), getUnicodeGitVersion().str()); } else { - str.format(L"%s %s", + str.format(L"%s R %s", getUnicodeVersion().str(), getUnicodeGitRevision().str()); } return str; } -AsciiString Version::buildAsciiGitRevision() +AsciiString Version::getAsciiBuildUserOrGitCommitAuthorName() const { - AsciiString str; - str.format("R %s%d", - GitUncommittedChanges ? "~" : "", - GitRevision); - return str; + AsciiString asciiUser = getAsciiBuildUser(); + + if (asciiUser.isEmpty()) + { + asciiUser = getGitCommitAuthorName(); + } + + return asciiUser; } -AsciiString Version::buildAsciiGitVersion() +UnicodeString Version::getUnicodeBuildUserOrGitCommitAuthorName() const { - AsciiString str; - str.format("%s%s", - GitUncommittedChanges ? "~" : "", - GitTag[0] ? GitTag : GitShortSHA1); + UnicodeString str; + AsciiString asciiUser = getAsciiBuildUserOrGitCommitAuthorName(); + + if (!asciiUser.isEmpty()) + { + UnicodeString unicodeUser; + unicodeUser.translate(asciiUser); + str.format(TheGameText->fetch("Version:BuildUser").str(), unicodeUser.str()); + } + return str; } -AsciiString Version::buildAsciiGitCommitTime() +AsciiString Version::buildAsciiGitRevision() { - const Int len = 19; AsciiString str; - Char* buf = str.getBufferForRead(len); - tm* time = gmtime(&GitCommitTimeStamp); - strftime(buf, len+1, "%Y-%m-%d %H:%M:%S", time); + str.format("%s%d", + GitUncommittedChanges ? "~" : "", + GitRevision); return str; } UnicodeString Version::buildUnicodeGitRevision() { UnicodeString str; - str.format(L"R %s%d", + str.format(L"%s%d", GitUncommittedChanges ? L"~" : L"", GitRevision); return str; } +AsciiString Version::buildAsciiGitVersion() +{ + AsciiString str; + str.format("%s%s", + GitUncommittedChanges ? "~" : "", + GitTag[0] ? GitTag : GitShortSHA1); + return str; +} + UnicodeString Version::buildUnicodeGitVersion() { UnicodeString str; @@ -245,6 +352,16 @@ UnicodeString Version::buildUnicodeGitVersion() return str; } +AsciiString Version::buildAsciiGitCommitTime() +{ + const Int len = 19; + AsciiString str; + Char* buf = str.getBufferForRead(len); + tm* time = gmtime(&GitCommitTimeStamp); + strftime(buf, len+1, "%Y-%m-%d %H:%M:%S", time); + return str; +} + UnicodeString Version::buildUnicodeGitCommitTime() { const Int len = 19; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp index 02384cef4d..6de7db5d12 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/MainMenu.cpp @@ -466,7 +466,7 @@ static void initLabelVersion() TheVersion->getUnicodeGitCommitTime().str(), TheGlobalData->m_exeCRC, TheGlobalData->m_iniCRC, - TheVersion->getUnicodeBuildUser().str() + TheVersion->getUnicodeBuildUserOrGitCommitAuthorName().str() ); GadgetStaticTextSetText( labelVersion, version ); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index bb9dd6131b..d7ed1c0b6f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -1379,7 +1379,7 @@ static void initLabelVersion() TheVersion->getUnicodeGitCommitTime().str(), TheGlobalData->m_exeCRC, TheGlobalData->m_iniCRC, - TheVersion->getUnicodeBuildUser().str() + TheVersion->getUnicodeBuildUserOrGitCommitAuthorName().str() ); GadgetStaticTextSetText( labelVersion, version ); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameText.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameText.cpp index e7fafd3229..2ccce89eb9 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameText.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameText.cpp @@ -388,7 +388,7 @@ void GameTextManager::init( void ) UnicodeString version; version.format(L" %s %s", TheVersion->getUnicodeGameAndGitVersion().str(), - TheVersion->getUnicodeBuildUser().str() + TheVersion->getUnicodeBuildUserOrGitCommitAuthorName().str() ); ourName.concat(version); } diff --git a/GeneralsMD/Code/Main/CMakeLists.txt b/GeneralsMD/Code/Main/CMakeLists.txt index f14860c9b4..fa73f03c13 100644 --- a/GeneralsMD/Code/Main/CMakeLists.txt +++ b/GeneralsMD/Code/Main/CMakeLists.txt @@ -31,8 +31,8 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/GeneratedVersion.h "#pragma once #define VERSION_LOCALBUILDNUM 0 -#define VERSION_BUILDUSER \"The Super Hackers\" -#define VERSION_BUILDLOC \"Someplace\" +#define VERSION_BUILDUSER \"\" +#define VERSION_BUILDLOC \"\" " ) From 0f0352ec5e48e9b1f5771518d1baf4e10eda5bc1 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 2 Jul 2025 22:15:10 +0200 Subject: [PATCH 3/3] Demystify code names --- .../Code/GameEngine/Include/Common/version.h | 34 ++++++------- .../GameEngine/Source/Common/GameEngine.cpp | 4 +- .../Code/GameEngine/Source/Common/version.cpp | 48 +++++++++---------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/version.h b/GeneralsMD/Code/GameEngine/Include/Common/version.h index 32b41cb788..35dce458bc 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/version.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/version.h @@ -59,18 +59,18 @@ class Version AsciiString getAsciiBuildUser() const; ///< Return a string with the build user UnicodeString getUnicodeBuildUser() const; ///< Return a string with the build user. Is decorated with localized string - static Int getGitRevision(); ///< Returns the total git commit count as a number - static time_t getGitCommitTime(); ///< Returns the last git commit time as a UTC timestamp - static const char* getGitCommitAuthorName(); ///< Returns the last git commit author name + static Int getGitCommitCount(); ///< Returns the git commit count as a number + static time_t getGitCommitTime(); ///< Returns the git head commit time as a UTC timestamp + static const char* getGitCommitAuthorName(); ///< Returns the git head commit author name - AsciiString getAsciiGitRevision() const; ///< Returns the total git commit count. Is prefixed with ~ if there were uncommitted changes. - UnicodeString getUnicodeGitRevision() const; ///< Returns the total git commit count. Is prefixed with ~ if there were uncommitted changes. + AsciiString getAsciiGitCommitCount() const; ///< Returns the git commit count. Is prefixed with ~ if there were uncommitted changes. + UnicodeString getUnicodeGitCommitCount() const; ///< Returns the git commit count. Is prefixed with ~ if there were uncommitted changes. - AsciiString getAsciiGitVersion() const; ///< Returns the last git commit tag or hash. Is prefixed with ~ if there were uncommitted changes. - UnicodeString getUnicodeGitVersion() const; ///< Returns the last git commit tag or hash. Is prefixed with ~ if there were uncommitted changes. + AsciiString getAsciiGitTagOrHash() const; ///< Returns the git head commit tag or hash. Is prefixed with ~ if there were uncommitted changes. + UnicodeString getUnicodeGitTagOrHash() const; ///< Returns the git head commit tag or hash. Is prefixed with ~ if there were uncommitted changes. - AsciiString getAsciiGitCommitTime() const; ///< Returns the last git commit time in YYYY-mm-dd HH:MM:SS format - UnicodeString getUnicodeGitCommitTime() const; ///< Returns the last git commit time in YYYY-mm-dd HH:MM:SS format + AsciiString getAsciiGitCommitTime() const; ///< Returns the git head commit time in YYYY-mm-dd HH:MM:SS format + UnicodeString getUnicodeGitCommitTime() const; ///< Returns the git head commit time in YYYY-mm-dd HH:MM:SS format AsciiString getAsciiGameAndGitVersion() const; ///< Returns the game and git version UnicodeString getUnicodeGameAndGitVersion() const; ///< Returns the game and git version. Is decorated with localized string @@ -86,11 +86,11 @@ class Version AsciiString buildTime, AsciiString buildDate); private: - static AsciiString buildAsciiGitRevision(); - static UnicodeString buildUnicodeGitRevision(); + static AsciiString buildAsciiGitCommitCount(); + static UnicodeString buildUnicodeGitCommitCount(); - static AsciiString buildAsciiGitVersion(); - static UnicodeString buildUnicodeGitVersion(); + static AsciiString buildAsciiGitTagOrHash(); + static UnicodeString buildUnicodeGitTagOrHash(); static AsciiString buildAsciiGitCommitTime(); static UnicodeString buildUnicodeGitCommitTime(); @@ -104,11 +104,11 @@ class Version AsciiString m_buildUser; AsciiString m_buildTime; AsciiString m_buildDate; - AsciiString m_asciiGitRevision; - AsciiString m_asciiGitVersion; + AsciiString m_asciiGitCommitCount; + AsciiString m_asciiGitTagOrHash; AsciiString m_asciiGitCommitTime; - UnicodeString m_unicodeGitRevision; - UnicodeString m_unicodeGitVersion; + UnicodeString m_unicodeGitCommitCount; + UnicodeString m_unicodeGitTagOrHash; UnicodeString m_unicodeGitCommitTime; Bool m_showFullVersion; }; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp index c38a1f9156..48a7513b54 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp @@ -265,8 +265,8 @@ void GameEngine::init() DEBUG_LOG(("Build date: %s\n", TheVersion->getAsciiBuildTime().str())); DEBUG_LOG(("Build location: %s\n", TheVersion->getAsciiBuildLocation().str())); DEBUG_LOG(("Build user: %s\n", TheVersion->getAsciiBuildUser().str())); - DEBUG_LOG(("Build git revision: %s\n", TheVersion->getAsciiGitRevision().str())); - DEBUG_LOG(("Build git version: %s\n", TheVersion->getAsciiGitVersion().str())); + DEBUG_LOG(("Build git revision: %s\n", TheVersion->getAsciiGitCommitCount().str())); + DEBUG_LOG(("Build git version: %s\n", TheVersion->getAsciiGitTagOrHash().str())); DEBUG_LOG(("Build git commit time: %s\n", TheVersion->getAsciiGitCommitTime().str())); DEBUG_LOG(("Build git commit author: %s\n", Version::getGitCommitAuthorName())); DEBUG_LOG(("================================================================================\n")); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/version.cpp b/GeneralsMD/Code/GameEngine/Source/Common/version.cpp index f60b5b2256..214f2c8e81 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/version.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/version.cpp @@ -43,11 +43,11 @@ Version::Version() m_localBuildNum = 0; m_buildUser = AsciiString::TheEmptyString; m_buildLocation = AsciiString::TheEmptyString; - m_asciiGitRevision = buildAsciiGitRevision(); - m_asciiGitVersion = buildAsciiGitVersion(); + m_asciiGitCommitCount = buildAsciiGitCommitCount(); + m_asciiGitTagOrHash = buildAsciiGitTagOrHash(); m_asciiGitCommitTime = buildAsciiGitCommitTime(); - m_unicodeGitRevision = buildUnicodeGitRevision(); - m_unicodeGitVersion = buildUnicodeGitVersion(); + m_unicodeGitCommitCount = buildUnicodeGitCommitCount(); + m_unicodeGitTagOrHash = buildUnicodeGitTagOrHash(); m_unicodeGitCommitTime = buildUnicodeGitCommitTime(); #if defined RTS_DEBUG || defined RTS_INTERNAL m_showFullVersion = TRUE; @@ -208,7 +208,7 @@ UnicodeString Version::getUnicodeBuildUser() const return build; } -Int Version::getGitRevision() +Int Version::getGitCommitCount() { return GitRevision; } @@ -223,24 +223,24 @@ const char* Version::getGitCommitAuthorName() return GitCommitAuthorName; } -AsciiString Version::getAsciiGitRevision() const +AsciiString Version::getAsciiGitCommitCount() const { - return m_asciiGitRevision; + return m_asciiGitCommitCount; } -UnicodeString Version::getUnicodeGitRevision() const +UnicodeString Version::getUnicodeGitCommitCount() const { - return m_unicodeGitRevision; + return m_unicodeGitCommitCount; } -AsciiString Version::getAsciiGitVersion() const +AsciiString Version::getAsciiGitTagOrHash() const { - return m_asciiGitVersion; + return m_asciiGitTagOrHash; } -UnicodeString Version::getUnicodeGitVersion() const +UnicodeString Version::getUnicodeGitTagOrHash() const { - return m_unicodeGitVersion; + return m_unicodeGitTagOrHash; } AsciiString Version::getAsciiGitCommitTime() const @@ -260,14 +260,14 @@ AsciiString Version::getAsciiGameAndGitVersion() const { str.format("%s R %s %s", getAsciiVersion().str(), - getAsciiGitRevision().str(), - getAsciiGitVersion().str()); + getAsciiGitCommitCount().str(), + getAsciiGitTagOrHash().str()); } else { str.format("%s R %s", getAsciiVersion().str(), - getAsciiGitRevision().str()); + getAsciiGitCommitCount().str()); } return str; } @@ -279,14 +279,14 @@ UnicodeString Version::getUnicodeGameAndGitVersion() const { str.format(L"%s R %s %s", getUnicodeVersion().str(), - getUnicodeGitRevision().str(), - getUnicodeGitVersion().str()); + getUnicodeGitCommitCount().str(), + getUnicodeGitTagOrHash().str()); } else { str.format(L"%s R %s", getUnicodeVersion().str(), - getUnicodeGitRevision().str()); + getUnicodeGitCommitCount().str()); } return str; } @@ -318,7 +318,7 @@ UnicodeString Version::getUnicodeBuildUserOrGitCommitAuthorName() const return str; } -AsciiString Version::buildAsciiGitRevision() +AsciiString Version::buildAsciiGitCommitCount() { AsciiString str; str.format("%s%d", @@ -327,7 +327,7 @@ AsciiString Version::buildAsciiGitRevision() return str; } -UnicodeString Version::buildUnicodeGitRevision() +UnicodeString Version::buildUnicodeGitCommitCount() { UnicodeString str; str.format(L"%s%d", @@ -336,7 +336,7 @@ UnicodeString Version::buildUnicodeGitRevision() return str; } -AsciiString Version::buildAsciiGitVersion() +AsciiString Version::buildAsciiGitTagOrHash() { AsciiString str; str.format("%s%s", @@ -345,10 +345,10 @@ AsciiString Version::buildAsciiGitVersion() return str; } -UnicodeString Version::buildUnicodeGitVersion() +UnicodeString Version::buildUnicodeGitTagOrHash() { UnicodeString str; - str.translate(buildAsciiGitVersion()); + str.translate(buildAsciiGitTagOrHash()); return str; }