diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 35241be11..087b49dcd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1104,6 +1104,7 @@ set (PCH_SOURCES common/filesystem/resourcefile.cpp common/engine/cycler.cpp common/engine/d_event.cpp + common/engine/date.cpp common/engine/stats.cpp common/engine/sc_man.cpp common/engine/palettecontainer.cpp diff --git a/src/common/engine/date.cpp b/src/common/engine/date.cpp new file mode 100644 index 000000000..c409416f8 --- /dev/null +++ b/src/common/engine/date.cpp @@ -0,0 +1,248 @@ +/* +** date.cpp +** +** VM exports for engine backend classes +** +**--------------------------------------------------------------------------- +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include "c_dispatch.h" +#include "vm.h" +#include "zstring.h" +#include "printf.h" + +time_t epochoffset = 0; // epoch start in seconds (0 = January 1st, 1970) + + +//========================================================================== +// +// CCMD setdate +// +// Set the time to a specific value +// +//========================================================================== + +UNSAFE_CCMD(setdate) +{ + if (argv.argc() != 3) + { + Printf("setdate HH:MM:SS DD-MM-YYYY: Set the current date\n"); + return; + } + + time_t today; + time(&today); + struct tm* timeinfo = localtime(&today); + if (timeinfo != nullptr) + { + auto clock = FString(argv[1]).Split(":"); + auto date = FString(argv[2]).Split("-"); + if(clock.Size() != 3 || date.Size() != 3) + { + Printf("setdate HH:MM:SS DD-MM-YYYY: Set the current date\n"); + return; + } + + if(!clock[0].IsInt()) + { + Printf("Invalid hour\n"); + return; + } + if (!clock[1].IsInt()) + { + Printf("Invalid minutes\n"); + return; + } + if (!clock[2].IsInt()) + { + Printf("Invalid seconds\n"); + return; + } + if (!date[0].IsInt()) + { + Printf("Invalid day\n"); + return; + } + if (!date[1].IsInt()) + { + Printf("Invalid month\n"); + return; + } + if (!date[2].IsInt()) + { + Printf("Invalid year\n"); + return; + } + + //Set Date + timeinfo->tm_hour = int( clock[0].ToLong() ); + timeinfo->tm_min = int( clock[1].ToLong() ); + timeinfo->tm_sec = int( clock[2].ToLong() ); + timeinfo->tm_mday = int( date[0].ToLong() ); + timeinfo->tm_mon = int( date[1].ToLong() - 1); // Month interally is 0 - 11 + timeinfo->tm_year = int( date[2].ToLong() - 1900 ); // Year interally is 00 - 138 + + time_t newTime = mktime(timeinfo); + tm* t_old = localtime(&today); + time_t oldTime = mktime(t_old); + + if (newTime == -1 || oldTime == -1) + { + Printf("Unable to set the date\n"); + return; + } + + epochoffset = newTime - oldTime; + + // This deals with some inconsistent display behaviour for DST + // In this case, we want to emulate GCC's behaviour + today += epochoffset; + struct tm* t_new = localtime(&today); + if (t_new != nullptr) + { + char timeString[1024]; + if (strftime(timeString, sizeof(timeString), "%H", t_new)) + { + auto hour = FString(timeString).ToLong(); + if (hour - clock[0].ToLong() == -1 || hour - clock[0].ToLong() == 23) + epochoffset += 3600; + else if (hour - clock[0].ToLong() == 1 || hour - clock[0].ToLong() == -23) + epochoffset -= 3600; + } + } + + return; + } + else + { + Printf("Unable to set the date\n"); + return; + } +} + +CCMD(getdate) +{ + time_t now; + time(&now); + now += epochoffset; + struct tm* timeinfo = localtime(&now); + if (timeinfo != nullptr) + { + char timeString[1024]; + if (strftime(timeString, sizeof(timeString), "%H:%M:%S %d-%m-%Y%n", timeinfo)) + Printf("%s\n", timeString); + else + Printf("Error Retrieving Current Date\n"); + } + else + { + Printf("Error Retrieving Current Date\n"); + } +} + +//===================================================================================== +// +// +// +//===================================================================================== + +extern time_t epochoffset; + +static int GetEpochTime() +{ + time_t now; + time(&now); + return now != (time_t)(-1) ? int(now + epochoffset) : -1; +} + +//Returns an empty string if the Strf tokens are valid, otherwise returns the problematic token +static FString CheckStrfString(FString timeForm) +{ + // Valid Characters after % + const char validSingles[] = { 'a','A','b','B','c','C','d','D','e','F','g','G','h','H','I','j','m','M','n','p','r','R','S','t','T','u','U','V','w','W','x','X','y','Y','z','Z' }; + + timeForm.Substitute("%%", "%a"); //Prevent %% from causing tokenizing problems + timeForm = "a" + timeForm; //Prevent %* at the beginning from causing a false error from tokenizing + + auto tokens = timeForm.Split("%"); + for (auto t : tokens) + { + bool found = false; + // % at end + if (t.Len() == 0) return FString("%"); + + // Single Character + for (size_t i = 0; i < sizeof(validSingles) / sizeof(validSingles[0]); i++) + { + if (t[0] == validSingles[i]) + { + found = true; + break; + } + } + if (found) continue; + return FString("%") + t[0]; + } + return ""; +} + +static void FormatTime(const FString& timeForm, int timeVal, FString* result) +{ + FString error = CheckStrfString(timeForm); + if (!error.IsEmpty()) + ThrowAbortException(X_FORMAT_ERROR, "'%s' is not a valid format specifier of SystemTime.Format()", error.GetChars()); + + time_t val = timeVal; + struct tm* timeinfo = localtime(&val); + if (timeinfo != nullptr) + { + char timeString[1024]; + if (strftime(timeString, sizeof(timeString), timeForm, timeinfo)) + *result = timeString; + } +} + +DEFINE_ACTION_FUNCTION_NATIVE(_SystemTime, Now, GetEpochTime) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(GetEpochTime()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_SystemTime, Format, FormatTime) +{ + PARAM_PROLOGUE; + PARAM_STRING(timeForm); + PARAM_INT(timeVal); + FString result; + FormatTime(timeForm, timeVal, &result); + ACTION_RETURN_STRING(result); +} + + diff --git a/src/console/c_cmds.cpp b/src/console/c_cmds.cpp index fb96b553a..dcec415b3 100644 --- a/src/console/c_cmds.cpp +++ b/src/console/c_cmds.cpp @@ -573,134 +573,6 @@ CCMD (special) } - -//========================================================================== -// -// CCMD setdate -// -// Set the time to a specific value -// -//========================================================================== - -extern time_t epochoffset; -CCMD(setdate) -{ - if (argv.argc() != 3) - { - Printf("setdate HH:MM:SS DD-MM-YYYY: Set the current date\n"); - return; - } - - time_t today; - time(&today); - struct tm* timeinfo = localtime(&today); - if (timeinfo != nullptr) - { - auto clock = FString(argv[1]).Split(":"); - auto date = FString(argv[2]).Split("-"); - if(clock.Size() != 3 || date.Size() != 3) - { - Printf("setdate HH:MM:SS DD-MM-YYYY: Set the current date\n"); - return; - } - - if(!clock[0].IsInt()) - { - Printf("Invalid hour\n"); - return; - } - if (!clock[1].IsInt()) - { - Printf("Invalid minutes\n"); - return; - } - if (!clock[2].IsInt()) - { - Printf("Invalid seconds\n"); - return; - } - if (!date[0].IsInt()) - { - Printf("Invalid day\n"); - return; - } - if (!date[1].IsInt()) - { - Printf("Invalid month\n"); - return; - } - if (!date[2].IsInt()) - { - Printf("Invalid year\n"); - return; - } - - //Set Date - timeinfo->tm_hour = int( clock[0].ToLong() ); - timeinfo->tm_min = int( clock[1].ToLong() ); - timeinfo->tm_sec = int( clock[2].ToLong() ); - timeinfo->tm_mday = int( date[0].ToLong() ); - timeinfo->tm_mon = int( date[1].ToLong() - 1); // Month interally is 0 - 11 - timeinfo->tm_year = int( date[2].ToLong() - 1900 ); // Year interally is 00 - 138 - - time_t newTime = mktime(timeinfo); - tm* t_old = localtime(&today); - time_t oldTime = mktime(t_old); - - if (newTime == -1 || oldTime == -1) - { - Printf("Unable to set the date\n"); - return; - } - - epochoffset = newTime - oldTime; - - // This deals with some inconsistent display behaviour for DST - // In this case, we want to emulate GCC's behaviour - today += epochoffset; - struct tm* t_new = localtime(&today); - if (t_new != nullptr) - { - char timeString[1024]; - if (strftime(timeString, sizeof(timeString), "%H", t_new)) - { - auto hour = FString(timeString).ToLong(); - if (hour - clock[0].ToLong() == -1 || hour - clock[0].ToLong() == 23) - epochoffset += 3600; - else if (hour - clock[0].ToLong() == 1 || hour - clock[0].ToLong() == -23) - epochoffset -= 3600; - } - } - - return; - } - else - { - Printf("Unable to set the date\n"); - return; - } -} - -CCMD(getdate) -{ - time_t now; - time(&now); - now += epochoffset; - struct tm* timeinfo = localtime(&now); - if (timeinfo != nullptr) - { - char timeString[1024]; - if (strftime(timeString, sizeof(timeString), "%H:%M:%S %d-%m-%Y%n", timeinfo)) - Printf("%s\n", timeString); - else - Printf("Error Retrieving Current Date\n"); - } - else - { - Printf("Error Retrieving Current Date\n"); - } -} - //========================================================================== // // CCMD warp diff --git a/src/g_game.cpp b/src/g_game.cpp index d14054c0f..c79ac5d77 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -161,8 +161,6 @@ bool playeringame[MAXPLAYERS]; int gametic; -time_t epochoffset = 0; // epoch start in seconds (0 = January 1st, 1970) - CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); FString newdemoname; FString newdemomap; diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index d9698d24a..3b796bf7b 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -2669,84 +2669,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, setFrozen, setFrozen) // //===================================================================================== -extern time_t epochoffset; - -static int GetEpochTime() -{ - time_t now; - time(&now); - return now != (time_t)(-1) ? int(now + epochoffset) : -1; -} - -//Returns an empty string if the Strf tokens are valid, otherwise returns the problematic token -static FString CheckStrfString(FString timeForm) -{ - // Valid Characters after % - const char validSingles[] = { 'a','A','b','B','c','C','d','D','e','F','g','G','h','H','I','j','m','M','n','p','r','R','S','t','T','u','U','V','w','W','x','X','y','Y','z','Z' }; - - timeForm.Substitute("%%", "%a"); //Prevent %% from causing tokenizing problems - timeForm = "a" + timeForm; //Prevent %* at the beginning from causing a false error from tokenizing - - auto tokens = timeForm.Split("%"); - for (auto t : tokens) - { - bool found = false; - // % at end - if (t.Len() == 0) return FString("%"); - - // Single Character - for (size_t i = 0; i < sizeof(validSingles)/sizeof(validSingles[0]); i++) - { - if (t[0] == validSingles[i]) - { - found = true; - break; - } - } - if (found) continue; - return FString("%") + t[0]; - } - return ""; -} - -static void FormatTime(const FString& timeForm, int timeVal, FString* result) -{ - FString error = CheckStrfString(timeForm); - if (!error.IsEmpty()) - ThrowAbortException(X_FORMAT_ERROR, "'%s' is not a valid format specifier of SystemTime.Format()", error.GetChars()); - - time_t val = timeVal; - struct tm* timeinfo = localtime(&val); - if (timeinfo != nullptr) - { - char timeString[1024]; - if (strftime(timeString, sizeof(timeString), timeForm, timeinfo)) - *result = timeString; - } -} - -DEFINE_ACTION_FUNCTION_NATIVE(_SystemTime, Now, GetEpochTime) -{ - PARAM_PROLOGUE; - ACTION_RETURN_INT(GetEpochTime()); -} - -DEFINE_ACTION_FUNCTION_NATIVE(_SystemTime, Format, FormatTime) -{ - PARAM_PROLOGUE; - PARAM_STRING(timeForm); - PARAM_INT(timeVal); - FString result; - FormatTime(timeForm, timeVal, &result); - ACTION_RETURN_STRING(result); -} - -//===================================================================================== -// -// -// -//===================================================================================== - DEFINE_ACTION_FUNCTION_NATIVE(_AltHUD, GetLatency, Net_GetLatency) { PARAM_PROLOGUE;