From 7c53788c9037dc5570a43e7d340fd379403da3c1 Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Sun, 31 Aug 2025 21:25:53 -0400 Subject: [PATCH 01/18] Write getTimerString Wrote a function that can break seconds into a formatted string of seconds, minutes, hours, and an overflow of days. This will convert timers into visible text. --- src/ClockUpdater.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index 03efc78..e5c79c2 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -53,6 +53,24 @@ namespace ClockMod { return time; } + // Turns an uncapped duration in seconds into a nicely formatted string + std::string getTimerString(double totalSeconds) { + int seconds = (int)totalSeconds % 60; + int minutes = (int)(totalSeconds / 60) % 60; + int hours = (int)(totalSeconds / 60 / 60) % 24; + int days = (int)(totalSeconds / 60 / 60 / 24); + + bool showSeconds = getModConfig().SecToggle.GetValue(); + + std::string timerStr; + if(days > 0) timerStr += fmt::format("{}:", days); + if(hours > 0 || !timerStr.empty() || !showSeconds) timerStr += fmt::format("{:02}:", hours); + timerStr += fmt::format("{:02}", minutes); + if(showSeconds) timerStr += fmt::format(":{:02}", seconds); + + return timerStr; + } + // New Battery Percentage Formatting std::string getBatteryString(float level, UnityEngine::BatteryStatus status, ClockMod::ClockUpdater* instance) { From 93fac2f0e16369903043b3c7979f31e485ec3068 Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Sun, 31 Aug 2025 21:59:04 -0400 Subject: [PATCH 02/18] Add sessionTime to ClockUpdater Added a member variable that will be updated with UnityEngine::Time::get_realtimeSinceStartup. Could just use the Unity function over and over again, but ClockUpdater seems like a hub for time information. --- shared/ClockUpdater.hpp | 2 ++ src/ClockUpdater.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/shared/ClockUpdater.hpp b/shared/ClockUpdater.hpp index cba811b..a0470a2 100644 --- a/shared/ClockUpdater.hpp +++ b/shared/ClockUpdater.hpp @@ -27,6 +27,8 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { time_t rawtime; struct tm* timeinfo; + double sessionTime = 0; + static ClockUpdater* instance; std::string _message; diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index e5c79c2..cdfa74d 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -10,6 +10,7 @@ #include "UnityEngine/BatteryStatus.hpp" #include "UnityEngine/GradientColorKey.hpp" #include "UnityEngine/SystemInfo.hpp" +#include "UnityEngine/Time.hpp" using namespace UnityEngine; using namespace TMPro; @@ -209,6 +210,8 @@ namespace ClockMod { last_time = this_time; + sessionTime = Time::get_realtimeSinceStartup(); + if (!(time_counter > (double)(NUM_SECONDS * CLOCKS_PER_SEC))) { return; From 75722ce5869c01f2c11f8bc01c24eb0d422bcb6e Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Sun, 31 Aug 2025 22:34:03 -0400 Subject: [PATCH 03/18] Add session time to ClockViewController Display the session time underneath the timezone and UTC time. Showing all time options on the info section of the settings menu should help convey what each of them are. --- shared/ClockUpdater.hpp | 2 ++ src/ClockUpdater.cpp | 6 +++++- src/ClockViewContoller.cpp | 8 ++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/shared/ClockUpdater.hpp b/shared/ClockUpdater.hpp index a0470a2..cdff6fa 100644 --- a/shared/ClockUpdater.hpp +++ b/shared/ClockUpdater.hpp @@ -38,10 +38,12 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { const time_t getRawTime() const; struct tm* getTimeInfo(); struct tm* getTimeInfoUTC(); + const double getSessionTime() const; TMPro::TextMeshProUGUI* getTextMesh(); void SetColor(UnityEngine::Color color); static ClockUpdater* getInstance(); static std::string getTimeFormat(); + static std::string getTimerString(const double totalSeconds); void ShowMessage(std::string message, int duration = 4); }; diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index cdfa74d..2dc82aa 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -55,7 +55,7 @@ namespace ClockMod { } // Turns an uncapped duration in seconds into a nicely formatted string - std::string getTimerString(double totalSeconds) { + std::string ClockUpdater::getTimerString(const double totalSeconds) { int seconds = (int)totalSeconds % 60; int minutes = (int)(totalSeconds / 60) % 60; int hours = (int)(totalSeconds / 60 / 60) % 24; @@ -286,6 +286,10 @@ namespace ClockMod { return gmtime(&time); } + const double ClockUpdater::getSessionTime() const { + return sessionTime; + } + TMPro::TextMeshProUGUI* ClockUpdater::getTextMesh() { return text; } diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp index 6a1f93b..c770147 100644 --- a/src/ClockViewContoller.cpp +++ b/src/ClockViewContoller.cpp @@ -42,11 +42,15 @@ namespace ClockMod { while (SettingsOpen) { char timeInformation[45]; strftime(timeInformation, sizeof(timeInformation), "Your Timezone - %Z UTC offset - %z", ClockUpdater::getInstance()->getTimeInfo()); + char UTCtime[40]; strftime(UTCtime, sizeof(UTCtime), std::string("\r\n Current Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), ClockUpdater::getInstance()->getTimeInfoUTC()); //strftime(UTCtime, sizeof(UTCtime), std::string("\r\n Current Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), gmtime(ClockUpdater::getInstance()->getRawTime())); + + std::string sessionTime = "\nSession Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getSessionTime()); + if (TimeInfo && SettingsOpen) - TimeInfo->set_text(std::string(timeInformation) + UTCtime); + TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime); co_yield reinterpret_cast(UnityEngine::WaitForSecondsRealtime::New_ctor(0.1)); } co_return; @@ -67,7 +71,7 @@ namespace ClockMod { std::string timeFormat = "Your Timezone - %Z\nUTC offset - %z"; strftime(timeInformation, sizeof(timeInformation), timeFormat.c_str(), instance->getTimeInfo()); // We have to specify sizeDelta here otherwise things will overlap - TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal, {0,0}, {0,15}); + TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal, {0,0}, {0,20}); // TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal); ColorPicker = BSML::Lite::CreateColorPickerModal(parent, getModConfig().ClockColor.GetName(), getModConfig().ClockColor.GetValue(), From 0715df61c0ab3f65959e770a869cd443d814e1c2 Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Sun, 31 Aug 2025 22:54:55 -0400 Subject: [PATCH 04/18] Add ClockTypes to mod config The ClockType is stored as an int in the mod config but can be casted to an enum that is defined in ClockValues.hpp. Seems like the correct place for it. --- include/ClockModConfig.hpp | 1 + include/ClockValues.hpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/ClockModConfig.hpp b/include/ClockModConfig.hpp index a37a8f6..13c67a6 100644 --- a/include/ClockModConfig.hpp +++ b/include/ClockModConfig.hpp @@ -3,6 +3,7 @@ DECLARE_CONFIG(ModConfig) { + CONFIG_VALUE(ClockType, int, "Clock Type", 0, "Which time the Clock should display."); CONFIG_VALUE(InSong, bool, "Show During Song", true, "If the Clock should be shown while playing a beatmap."); CONFIG_VALUE(InReplay, bool, "Show During Replay", true, "If the Clock should be shown while playing a replay."); CONFIG_VALUE(TwelveToggle, bool, "24/12 Toggle", false, "If time should be in 12 or 24 hour format."); diff --git a/include/ClockValues.hpp b/include/ClockValues.hpp index c0d4ca3..637de14 100644 --- a/include/ClockValues.hpp +++ b/include/ClockValues.hpp @@ -2,6 +2,17 @@ #include "UnityEngine/Vector3.hpp" #include "UnityEngine/UI/VerticalLayoutGroup.hpp" +enum class ClockTypes { + CurrentTime, + SessionTime + // CustomTimer +}; +static std::string_view clockTypeStrs[] = { + "Current Time", + "Session Time" + // Custom Timer +}; + // This containts all the ClockPositions struct ClockPos_t { // Clock InMenu Positions Top X Y Z From 6651c42af689560e1ab90ec03126c788649c553f Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Sun, 31 Aug 2025 22:56:35 -0400 Subject: [PATCH 05/18] Add ClockType to ClockViewController Oh cool config-utils just has an enum dropdown function already. --- src/ClockViewContoller.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp index c770147..745643b 100644 --- a/src/ClockViewContoller.cpp +++ b/src/ClockViewContoller.cpp @@ -1,5 +1,6 @@ #include "ClockModConfig.hpp" #include "ClockUpdater.hpp" +#include "ClockValues.hpp" #include "ClockViewController.hpp" using namespace ClockMod; @@ -87,6 +88,7 @@ namespace ClockMod { ); } + AddConfigValueDropdownEnum(parent, getModConfig().ClockType, clockTypeStrs); AddConfigValueToggle(parent, getModConfig().InSong); AddConfigValueToggle(parent, getModConfig().InReplay); AddConfigValueToggle(parent, getModConfig().TwelveToggle); From ccd6ef60d5123ae5cfd07cd05ec992e8dc23befc Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Sun, 31 Aug 2025 22:58:14 -0400 Subject: [PATCH 06/18] Remove space from Current Time text Could be an indent, but it was so small that it just looked like a mistake to me. --- src/ClockViewContoller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp index 745643b..cdfd3c8 100644 --- a/src/ClockViewContoller.cpp +++ b/src/ClockViewContoller.cpp @@ -45,7 +45,7 @@ namespace ClockMod { strftime(timeInformation, sizeof(timeInformation), "Your Timezone - %Z UTC offset - %z", ClockUpdater::getInstance()->getTimeInfo()); char UTCtime[40]; - strftime(UTCtime, sizeof(UTCtime), std::string("\r\n Current Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), ClockUpdater::getInstance()->getTimeInfoUTC()); + strftime(UTCtime, sizeof(UTCtime), std::string("\r\nCurrent Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), ClockUpdater::getInstance()->getTimeInfoUTC()); //strftime(UTCtime, sizeof(UTCtime), std::string("\r\n Current Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), gmtime(ClockUpdater::getInstance()->getRawTime())); std::string sessionTime = "\nSession Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getSessionTime()); From aa32363054a97b74b70cc6e448af4957936c9ffa Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Sun, 31 Aug 2025 23:07:16 -0400 Subject: [PATCH 07/18] Use selected ClockType in ClockUpdater When session time is selected, it is now displayed on the floating clock. --- src/ClockUpdater.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index 2dc82aa..05681fa 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -231,14 +231,9 @@ namespace ClockMod { ClockPos.ap1 = (timeinfo && timeinfo->tm_mon == 3 && timeinfo->tm_mday == 1); std::string clockresult; - - if (_message.empty()) { - // Gets the time using the function at the top. - clockresult = getTimeString((struct tm*)timeinfo); - } - else { - clockresult = _message; - } + if(!_message.empty()) clockresult = _message; + else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::SessionTime)) clockresult = getTimerString(sessionTime); + else clockresult = getTimeString((struct tm*)timeinfo); // Checks, if the clock is set to rainbowify if (getModConfig().RainbowClock.GetValue()) { From e80491e441f59fcefdd418b2eaba05e8bea28546 Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Sun, 31 Aug 2025 23:53:59 -0400 Subject: [PATCH 08/18] Rename sessionTime to sessionTimeSeconds I like having units on the time --- shared/ClockUpdater.hpp | 4 ++-- src/ClockUpdater.cpp | 8 ++++---- src/ClockViewContoller.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/shared/ClockUpdater.hpp b/shared/ClockUpdater.hpp index cdff6fa..28494eb 100644 --- a/shared/ClockUpdater.hpp +++ b/shared/ClockUpdater.hpp @@ -27,7 +27,7 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { time_t rawtime; struct tm* timeinfo; - double sessionTime = 0; + double sessionTimeSeconds = 0; static ClockUpdater* instance; @@ -38,7 +38,7 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { const time_t getRawTime() const; struct tm* getTimeInfo(); struct tm* getTimeInfoUTC(); - const double getSessionTime() const; + const double getSessionTimeSeconds() const; TMPro::TextMeshProUGUI* getTextMesh(); void SetColor(UnityEngine::Color color); static ClockUpdater* getInstance(); diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index 05681fa..3f6c746 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -210,7 +210,7 @@ namespace ClockMod { last_time = this_time; - sessionTime = Time::get_realtimeSinceStartup(); + sessionTimeSeconds = Time::get_realtimeSinceStartup(); if (!(time_counter > (double)(NUM_SECONDS * CLOCKS_PER_SEC))) { @@ -232,7 +232,7 @@ namespace ClockMod { std::string clockresult; if(!_message.empty()) clockresult = _message; - else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::SessionTime)) clockresult = getTimerString(sessionTime); + else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::SessionTime)) clockresult = getTimerString(sessionTimeSeconds); else clockresult = getTimeString((struct tm*)timeinfo); // Checks, if the clock is set to rainbowify @@ -281,8 +281,8 @@ namespace ClockMod { return gmtime(&time); } - const double ClockUpdater::getSessionTime() const { - return sessionTime; + const double ClockUpdater::getSessionTimeSeconds() const { + return sessionTimeSeconds; } TMPro::TextMeshProUGUI* ClockUpdater::getTextMesh() { diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp index cdfd3c8..a96eae2 100644 --- a/src/ClockViewContoller.cpp +++ b/src/ClockViewContoller.cpp @@ -48,7 +48,7 @@ namespace ClockMod { strftime(UTCtime, sizeof(UTCtime), std::string("\r\nCurrent Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), ClockUpdater::getInstance()->getTimeInfoUTC()); //strftime(UTCtime, sizeof(UTCtime), std::string("\r\n Current Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), gmtime(ClockUpdater::getInstance()->getRawTime())); - std::string sessionTime = "\nSession Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getSessionTime()); + std::string sessionTime = "\nSession Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getSessionTimeSeconds()); if (TimeInfo && SettingsOpen) TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime); From 923ad0c170ef6e9157d6d98b160f5044e7f647ce Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 00:38:00 -0400 Subject: [PATCH 09/18] Add stopwatch Renamed custom timer to stopwatch, uncommented code in ClockUpdater and ClockValues from previous outlining, and added it to the information area. --- include/ClockModConfig.hpp | 20 +++++++++++--------- include/ClockValues.hpp | 8 ++++---- shared/ClockUpdater.hpp | 2 ++ src/ClockUpdater.cpp | 10 +++++++--- src/ClockViewContoller.cpp | 6 ++++-- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/include/ClockModConfig.hpp b/include/ClockModConfig.hpp index 13c67a6..285a7c6 100644 --- a/include/ClockModConfig.hpp +++ b/include/ClockModConfig.hpp @@ -3,15 +3,17 @@ DECLARE_CONFIG(ModConfig) { - CONFIG_VALUE(ClockType, int, "Clock Type", 0, "Which time the Clock should display."); - CONFIG_VALUE(InSong, bool, "Show During Song", true, "If the Clock should be shown while playing a beatmap."); - CONFIG_VALUE(InReplay, bool, "Show During Replay", true, "If the Clock should be shown while playing a replay."); - CONFIG_VALUE(TwelveToggle, bool, "24/12 Toggle", false, "If time should be in 12 or 24 hour format."); - CONFIG_VALUE(SecToggle, bool, "Show Seconds", false, "If seconds should be displayed."); - CONFIG_VALUE(BattToggle, bool, "Show Battery Percentage", false, "Displays Battery percentage next to the clock."); - CONFIG_VALUE(RainbowClock, bool, "Rainbowify it", false, "Makes the Clock beautiful."); - CONFIG_VALUE(FontSize, float, "Font Size", 3.5, "Changes the Font Size of the Clock (Default: 3.5)"); - CONFIG_VALUE(ClockPosition, bool, "Clock Position (Top/Bottom)", false, "If the Clock should be at the top or the bottom"); + CONFIG_VALUE(ClockType, int, "Clock Type", 0, "Which time the Clock should display."); + CONFIG_VALUE(StopwatchSeconds, double, "Stopwatch Seconds", 0, "The saved time on the stopwatch."); + CONFIG_VALUE(StopwatchPaused, bool, "Stopwatch Paused", true, "If the stopwatch is locked from incrementing.") + CONFIG_VALUE(InSong, bool, "Show During Song", true, "If the Clock should be shown while playing a beatmap."); + CONFIG_VALUE(InReplay, bool, "Show During Replay", true, "If the Clock should be shown while playing a replay."); + CONFIG_VALUE(TwelveToggle, bool, "24/12 Toggle", false, "If time should be in 12 or 24 hour format."); + CONFIG_VALUE(SecToggle, bool, "Show Seconds", false, "If seconds should be displayed."); + CONFIG_VALUE(BattToggle, bool, "Show Battery Percentage", false, "Displays Battery percentage next to the clock."); + CONFIG_VALUE(RainbowClock, bool, "Rainbowify it", false, "Makes the Clock beautiful."); + CONFIG_VALUE(FontSize, float, "Font Size", 3.5, "Changes the Font Size of the Clock (Default: 3.5)"); + CONFIG_VALUE(ClockPosition, bool, "Clock Position (Top/Bottom)", false, "If the Clock should be at the top or the bottom"); // CONFIG_VALUE(ClockXOffset, double, "Clock X Offset", 0); // CONFIG_VALUE(ClockYOffset, double, "Clock Y Offset", 0); diff --git a/include/ClockValues.hpp b/include/ClockValues.hpp index 637de14..25ceba2 100644 --- a/include/ClockValues.hpp +++ b/include/ClockValues.hpp @@ -4,13 +4,13 @@ enum class ClockTypes { CurrentTime, - SessionTime - // CustomTimer + SessionTime, + Stopwatch }; static std::string_view clockTypeStrs[] = { "Current Time", - "Session Time" - // Custom Timer + "Session Time", + "Stopwatch" }; // This containts all the ClockPositions diff --git a/shared/ClockUpdater.hpp b/shared/ClockUpdater.hpp index 28494eb..a37f408 100644 --- a/shared/ClockUpdater.hpp +++ b/shared/ClockUpdater.hpp @@ -28,6 +28,7 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { struct tm* timeinfo; double sessionTimeSeconds = 0; + double stopwatchSeconds = 0; static ClockUpdater* instance; @@ -39,6 +40,7 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { struct tm* getTimeInfo(); struct tm* getTimeInfoUTC(); const double getSessionTimeSeconds() const; + const double getStopwatchSeconds() const; TMPro::TextMeshProUGUI* getTextMesh(); void SetColor(UnityEngine::Color color); static ClockUpdater* getInstance(); diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index 3f6c746..d3f4155 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -205,13 +205,12 @@ namespace ClockMod { } this_time = clock(); - + sessionTimeSeconds = Time::get_realtimeSinceStartup(); + if(!getModConfig().StopwatchPaused.GetValue()) stopwatchSeconds += (double)(this_time - last_time) / CLOCKS_PER_SEC; time_counter += (double)(this_time - last_time); last_time = this_time; - sessionTimeSeconds = Time::get_realtimeSinceStartup(); - if (!(time_counter > (double)(NUM_SECONDS * CLOCKS_PER_SEC))) { return; @@ -233,6 +232,7 @@ namespace ClockMod { std::string clockresult; if(!_message.empty()) clockresult = _message; else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::SessionTime)) clockresult = getTimerString(sessionTimeSeconds); + else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::Stopwatch)) clockresult = getTimerString(stopwatchSeconds); else clockresult = getTimeString((struct tm*)timeinfo); // Checks, if the clock is set to rainbowify @@ -285,6 +285,10 @@ namespace ClockMod { return sessionTimeSeconds; } + const double ClockUpdater::getStopwatchSeconds() const { + return stopwatchSeconds; + } + TMPro::TextMeshProUGUI* ClockUpdater::getTextMesh() { return text; } diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp index a96eae2..45c4480 100644 --- a/src/ClockViewContoller.cpp +++ b/src/ClockViewContoller.cpp @@ -50,8 +50,10 @@ namespace ClockMod { std::string sessionTime = "\nSession Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getSessionTimeSeconds()); + std::string stopwatchTime = "\nStopwatch Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getStopwatchSeconds()); + if (TimeInfo && SettingsOpen) - TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime); + TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime + stopwatchTime); co_yield reinterpret_cast(UnityEngine::WaitForSecondsRealtime::New_ctor(0.1)); } co_return; @@ -72,7 +74,7 @@ namespace ClockMod { std::string timeFormat = "Your Timezone - %Z\nUTC offset - %z"; strftime(timeInformation, sizeof(timeInformation), timeFormat.c_str(), instance->getTimeInfo()); // We have to specify sizeDelta here otherwise things will overlap - TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal, {0,0}, {0,20}); + TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal, {0,0}, {0,5*5}); // TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal); ColorPicker = BSML::Lite::CreateColorPickerModal(parent, getModConfig().ClockColor.GetName(), getModConfig().ClockColor.GetValue(), From a28416a455b1f9eb999fe13b60361044e77727c5 Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 01:14:01 -0400 Subject: [PATCH 10/18] Save and load StopwatchSeconds --- include/ClockModConfig.hpp | 2 +- src/ClockUpdater.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/ClockModConfig.hpp b/include/ClockModConfig.hpp index 285a7c6..734bc43 100644 --- a/include/ClockModConfig.hpp +++ b/include/ClockModConfig.hpp @@ -4,7 +4,7 @@ DECLARE_CONFIG(ModConfig) { CONFIG_VALUE(ClockType, int, "Clock Type", 0, "Which time the Clock should display."); - CONFIG_VALUE(StopwatchSeconds, double, "Stopwatch Seconds", 0, "The saved time on the stopwatch."); + CONFIG_VALUE(StopwatchSeconds, int, "Stopwatch Seconds", 0, "The saved time on the stopwatch."); CONFIG_VALUE(StopwatchPaused, bool, "Stopwatch Paused", true, "If the stopwatch is locked from incrementing.") CONFIG_VALUE(InSong, bool, "Show During Song", true, "If the Clock should be shown while playing a beatmap."); CONFIG_VALUE(InReplay, bool, "Show During Replay", true, "If the Clock should be shown while playing a replay."); diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index d3f4155..8dcf7ba 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -155,6 +155,7 @@ namespace ClockMod { text = get_gameObject()->GetComponent(); clockParent = get_transform()->GetParent(); + stopwatchSeconds = getModConfig().StopwatchSeconds.GetValue(); getModConfig().ClockColor.AddChangeEvent([this](UnityEngine::Color color) { if (text) text->set_color(color); @@ -217,6 +218,14 @@ namespace ClockMod { } time_counter = 0; + // Scuffed, but not any more than the rest of this codebase + static int stopwatchSaveTimer = 0; + stopwatchSaveTimer++; + if(stopwatchSaveTimer > 10 / NUM_SECONDS && !Config.IsInSong) { // Avoid dropping frames during gameplay + getModConfig().StopwatchSeconds.SetValue(stopwatchSeconds); + stopwatchSaveTimer = 0; + } + if (getModConfig().InSong.GetValue() || !Config.noTextAndHUD) { time(&rawtime); timeinfo = localtime(&rawtime); From 9a5f1381541cedf3d2250e4a3ed0d615fb27d0ad Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 01:45:01 -0400 Subject: [PATCH 11/18] Update stopwatchSeconds with realtimeSinceStartup Use Unity's timing system rather than the clock function in ctime. clock is based on CPU time rather than real time, and CLOCKS_PER_SECOND is an inaccurate constexpr. The stopwatch was going a little bit faster than it should have been. --- src/ClockUpdater.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index 8dcf7ba..1abf25a 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -205,12 +205,15 @@ namespace ClockMod { text->get_transform()->set_localScale(UnityEngine::Vector3(1, 1, 1)); } + static double lastSessionTimeSeconds = Time::get_realtimeSinceStartup(); + this_time = clock(); sessionTimeSeconds = Time::get_realtimeSinceStartup(); - if(!getModConfig().StopwatchPaused.GetValue()) stopwatchSeconds += (double)(this_time - last_time) / CLOCKS_PER_SEC; + if(!getModConfig().StopwatchPaused.GetValue()) stopwatchSeconds += sessionTimeSeconds - lastSessionTimeSeconds; time_counter += (double)(this_time - last_time); last_time = this_time; + lastSessionTimeSeconds = sessionTimeSeconds; if (!(time_counter > (double)(NUM_SECONDS * CLOCKS_PER_SEC))) { From d8da31f1f8560e7fe8554f537644596ec54f0ac5 Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 11:48:12 -0400 Subject: [PATCH 12/18] Remove two digit requirement on the first digit of a timer Duration 0 will now show as 0:00 instead of 00:00. The double zero should only appear if another number comes before, such as 1:00:00. Looks and reads nicer. --- src/ClockUpdater.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index 1abf25a..e327339 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -65,8 +65,8 @@ namespace ClockMod { std::string timerStr; if(days > 0) timerStr += fmt::format("{}:", days); - if(hours > 0 || !timerStr.empty() || !showSeconds) timerStr += fmt::format("{:02}:", hours); - timerStr += fmt::format("{:02}", minutes); + if(hours > 0 || !timerStr.empty() || !showSeconds) timerStr += timerStr.empty() ? fmt::format("{}:", hours) : fmt::format("{:02}:", hours); + timerStr += timerStr.empty() ? fmt::format("{}", minutes) : fmt::format("{:02}", minutes); if(showSeconds) timerStr += fmt::format(":{:02}", seconds); return timerStr; From cf10d9545d326f3b5afc5e644da68d66321f26ff Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 13:06:24 -0400 Subject: [PATCH 13/18] Add stopwatch pause and reset button to ClockViewController Make it possible to control the stopwatch with UI. --- shared/ClockUpdater.hpp | 1 + src/ClockUpdater.cpp | 4 ++++ src/ClockViewContoller.cpp | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/shared/ClockUpdater.hpp b/shared/ClockUpdater.hpp index a37f408..19f3a7c 100644 --- a/shared/ClockUpdater.hpp +++ b/shared/ClockUpdater.hpp @@ -41,6 +41,7 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { struct tm* getTimeInfoUTC(); const double getSessionTimeSeconds() const; const double getStopwatchSeconds() const; + void resetStopwatch(); TMPro::TextMeshProUGUI* getTextMesh(); void SetColor(UnityEngine::Color color); static ClockUpdater* getInstance(); diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index e327339..2e065aa 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -301,6 +301,10 @@ namespace ClockMod { return stopwatchSeconds; } + void ClockUpdater::resetStopwatch() { + stopwatchSeconds = 0; + } + TMPro::TextMeshProUGUI* ClockUpdater::getTextMesh() { return text; } diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp index 45c4480..108a071 100644 --- a/src/ClockViewContoller.cpp +++ b/src/ClockViewContoller.cpp @@ -10,6 +10,7 @@ using namespace ClockMod; #include "bsml/shared/BSML/Components/ModalColorPicker.hpp" #include "custom-types/shared/coroutine.hpp" #include "custom-types/shared/macros.hpp" +#include "custom-types/shared/delegate.hpp" #include "HMUI/CurvedTextMeshPro.hpp" #include "HMUI/ScrollView.hpp" @@ -23,6 +24,8 @@ using namespace ClockMod; #include "UnityEngine/Canvas.hpp" #include "UnityEngine/Color.hpp" #include "UnityEngine/GameObject.hpp" +#include "UnityEngine/UI/Button.hpp" +#include "UnityEngine/UI/LayoutElement.hpp" #include "UnityEngine/WaitForSecondsRealtime.hpp" @@ -90,6 +93,19 @@ namespace ClockMod { ); } + auto stopwatchPauseButton = BSML::Lite::CreateUIButton(parent, getModConfig().StopwatchPaused.GetValue() ? "Start" : "Pause", {68, -19.9}, {-5, 0}, nullptr); + stopwatchPauseButton->GetComponent()->set_ignoreLayout(true); + stopwatchPauseButton->get_onClick()->AddListener(custom_types::MakeDelegate(std::function([stopwatchPauseButton](){ + getModConfig().StopwatchPaused.SetValue(!getModConfig().StopwatchPaused.GetValue()); + if(getModConfig().StopwatchPaused.GetValue()) BSML::Lite::SetButtonText(stopwatchPauseButton, "Start"); + else BSML::Lite::SetButtonText(stopwatchPauseButton, "Pause"); + }))); + auto stopwatchResetButton = BSML::Lite::CreateUIButton(parent, "Reset", {83, -19.9}, {-5, 8}, nullptr); + stopwatchResetButton->GetComponent()->set_ignoreLayout(true); + stopwatchResetButton->get_onClick()->AddListener(custom_types::MakeDelegate(std::function([](){ + if(ClockMod::ClockUpdater::getInstance()) ClockMod::ClockUpdater::getInstance()->resetStopwatch(); + }))); + AddConfigValueDropdownEnum(parent, getModConfig().ClockType, clockTypeStrs); AddConfigValueToggle(parent, getModConfig().InSong); AddConfigValueToggle(parent, getModConfig().InReplay); From 390816cc05ed354b3af798c05039a922c0e44488 Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 21:28:40 -0400 Subject: [PATCH 14/18] Add stopwatch 2 Renamed stopwatch to stopwatch 1 and duplicated all of the code to make stopwatch 2 as well. Stopwatch could be used to remove crash vulnerability in session time, but could also track all time usage. So hard to decide... Why not both! Or do whatever! --- include/ClockModConfig.hpp | 6 +++-- include/ClockValues.hpp | 6 +++-- shared/ClockUpdater.hpp | 9 +++++--- src/ClockUpdater.cpp | 28 +++++++++++++++++------- src/ClockViewContoller.cpp | 45 +++++++++++++++++++++++++++----------- 5 files changed, 66 insertions(+), 28 deletions(-) diff --git a/include/ClockModConfig.hpp b/include/ClockModConfig.hpp index 734bc43..bbd606c 100644 --- a/include/ClockModConfig.hpp +++ b/include/ClockModConfig.hpp @@ -4,8 +4,10 @@ DECLARE_CONFIG(ModConfig) { CONFIG_VALUE(ClockType, int, "Clock Type", 0, "Which time the Clock should display."); - CONFIG_VALUE(StopwatchSeconds, int, "Stopwatch Seconds", 0, "The saved time on the stopwatch."); - CONFIG_VALUE(StopwatchPaused, bool, "Stopwatch Paused", true, "If the stopwatch is locked from incrementing.") + CONFIG_VALUE(Stopwatch1Seconds, int, "Stopwatch 1 Seconds", 0, "The saved time on stopwatch 1."); + CONFIG_VALUE(Stopwatch2Seconds, int, "Stopwatch 2 Seconds", 0, "The saved time on stopwatch 2."); + CONFIG_VALUE(Stopwatch1Paused, bool, "Stopwatch 1 Paused", true, "If stopwatch 1 is locked from incrementing."); + CONFIG_VALUE(Stopwatch2Paused, bool, "Stopwatch 2 Paused", true, "If stopwatch 2 is locked from incrementing."); CONFIG_VALUE(InSong, bool, "Show During Song", true, "If the Clock should be shown while playing a beatmap."); CONFIG_VALUE(InReplay, bool, "Show During Replay", true, "If the Clock should be shown while playing a replay."); CONFIG_VALUE(TwelveToggle, bool, "24/12 Toggle", false, "If time should be in 12 or 24 hour format."); diff --git a/include/ClockValues.hpp b/include/ClockValues.hpp index 25ceba2..517fd04 100644 --- a/include/ClockValues.hpp +++ b/include/ClockValues.hpp @@ -5,12 +5,14 @@ enum class ClockTypes { CurrentTime, SessionTime, - Stopwatch + Stopwatch1, + Stopwatch2 }; static std::string_view clockTypeStrs[] = { "Current Time", "Session Time", - "Stopwatch" + "Stopwatch 1", + "Stopwatch 2", }; // This containts all the ClockPositions diff --git a/shared/ClockUpdater.hpp b/shared/ClockUpdater.hpp index 19f3a7c..7239e12 100644 --- a/shared/ClockUpdater.hpp +++ b/shared/ClockUpdater.hpp @@ -28,7 +28,8 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { struct tm* timeinfo; double sessionTimeSeconds = 0; - double stopwatchSeconds = 0; + double stopwatch1Seconds = 0; + double stopwatch2Seconds = 0; static ClockUpdater* instance; @@ -40,8 +41,10 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { struct tm* getTimeInfo(); struct tm* getTimeInfoUTC(); const double getSessionTimeSeconds() const; - const double getStopwatchSeconds() const; - void resetStopwatch(); + const double getStopwatch1Seconds() const; + const double getStopwatch2Seconds() const; + void resetStopwatch1(); + void resetStopwatch2(); TMPro::TextMeshProUGUI* getTextMesh(); void SetColor(UnityEngine::Color color); static ClockUpdater* getInstance(); diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index 2e065aa..ae72e4a 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -155,7 +155,8 @@ namespace ClockMod { text = get_gameObject()->GetComponent(); clockParent = get_transform()->GetParent(); - stopwatchSeconds = getModConfig().StopwatchSeconds.GetValue(); + stopwatch1Seconds = getModConfig().Stopwatch1Seconds.GetValue(); + stopwatch2Seconds = getModConfig().Stopwatch2Seconds.GetValue(); getModConfig().ClockColor.AddChangeEvent([this](UnityEngine::Color color) { if (text) text->set_color(color); @@ -209,7 +210,8 @@ namespace ClockMod { this_time = clock(); sessionTimeSeconds = Time::get_realtimeSinceStartup(); - if(!getModConfig().StopwatchPaused.GetValue()) stopwatchSeconds += sessionTimeSeconds - lastSessionTimeSeconds; + if(!getModConfig().Stopwatch1Paused.GetValue()) stopwatch1Seconds += sessionTimeSeconds - lastSessionTimeSeconds; + if(!getModConfig().Stopwatch2Paused.GetValue()) stopwatch2Seconds += sessionTimeSeconds - lastSessionTimeSeconds; time_counter += (double)(this_time - last_time); last_time = this_time; @@ -225,7 +227,8 @@ namespace ClockMod { static int stopwatchSaveTimer = 0; stopwatchSaveTimer++; if(stopwatchSaveTimer > 10 / NUM_SECONDS && !Config.IsInSong) { // Avoid dropping frames during gameplay - getModConfig().StopwatchSeconds.SetValue(stopwatchSeconds); + getModConfig().Stopwatch1Seconds.SetValue(stopwatch1Seconds); + getModConfig().Stopwatch2Seconds.SetValue(stopwatch2Seconds); stopwatchSaveTimer = 0; } @@ -244,7 +247,8 @@ namespace ClockMod { std::string clockresult; if(!_message.empty()) clockresult = _message; else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::SessionTime)) clockresult = getTimerString(sessionTimeSeconds); - else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::Stopwatch)) clockresult = getTimerString(stopwatchSeconds); + else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::Stopwatch1)) clockresult = getTimerString(stopwatch1Seconds); + else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::Stopwatch2)) clockresult = getTimerString(stopwatch2Seconds); else clockresult = getTimeString((struct tm*)timeinfo); // Checks, if the clock is set to rainbowify @@ -297,12 +301,20 @@ namespace ClockMod { return sessionTimeSeconds; } - const double ClockUpdater::getStopwatchSeconds() const { - return stopwatchSeconds; + const double ClockUpdater::getStopwatch1Seconds() const { + return stopwatch1Seconds; } - void ClockUpdater::resetStopwatch() { - stopwatchSeconds = 0; + const double ClockUpdater::getStopwatch2Seconds() const { + return stopwatch2Seconds; + } + + void ClockUpdater::resetStopwatch1() { + stopwatch1Seconds = 0; + } + + void ClockUpdater::resetStopwatch2() { + stopwatch2Seconds = 0; } TMPro::TextMeshProUGUI* ClockUpdater::getTextMesh() { diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp index 108a071..f5060db 100644 --- a/src/ClockViewContoller.cpp +++ b/src/ClockViewContoller.cpp @@ -53,10 +53,11 @@ namespace ClockMod { std::string sessionTime = "\nSession Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getSessionTimeSeconds()); - std::string stopwatchTime = "\nStopwatch Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getStopwatchSeconds()); + std::string stopwatch1Time = "\nStopwatch 1 Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getStopwatch1Seconds()); + std::string stopwatch2Time = "\nStopwatch 2 Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getStopwatch2Seconds()); if (TimeInfo && SettingsOpen) - TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime + stopwatchTime); + TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime + stopwatch1Time + stopwatch2Time); co_yield reinterpret_cast(UnityEngine::WaitForSecondsRealtime::New_ctor(0.1)); } co_return; @@ -77,7 +78,7 @@ namespace ClockMod { std::string timeFormat = "Your Timezone - %Z\nUTC offset - %z"; strftime(timeInformation, sizeof(timeInformation), timeFormat.c_str(), instance->getTimeInfo()); // We have to specify sizeDelta here otherwise things will overlap - TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal, {0,0}, {0,5*5}); + TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal, {0,0}, {0,5*6}); // TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal); ColorPicker = BSML::Lite::CreateColorPickerModal(parent, getModConfig().ClockColor.GetName(), getModConfig().ClockColor.GetValue(), @@ -93,17 +94,35 @@ namespace ClockMod { ); } - auto stopwatchPauseButton = BSML::Lite::CreateUIButton(parent, getModConfig().StopwatchPaused.GetValue() ? "Start" : "Pause", {68, -19.9}, {-5, 0}, nullptr); - stopwatchPauseButton->GetComponent()->set_ignoreLayout(true); - stopwatchPauseButton->get_onClick()->AddListener(custom_types::MakeDelegate(std::function([stopwatchPauseButton](){ - getModConfig().StopwatchPaused.SetValue(!getModConfig().StopwatchPaused.GetValue()); - if(getModConfig().StopwatchPaused.GetValue()) BSML::Lite::SetButtonText(stopwatchPauseButton, "Start"); - else BSML::Lite::SetButtonText(stopwatchPauseButton, "Pause"); + // Could optimize these into a small lambda or #define, but there's only two as of now so it's not that big a deal + auto stopwatch1PauseButton = BSML::Lite::CreateUIButton(parent, getModConfig().Stopwatch1Paused.GetValue() ? "Start" : "Pause", {70, -19.9}, {-5, 0}, nullptr); + stopwatch1PauseButton->GetComponent()->set_ignoreLayout(true); + stopwatch1PauseButton->get_transform()->set_localScale({0.9, 0.9, 0.9}); + stopwatch1PauseButton->get_onClick()->AddListener(custom_types::MakeDelegate(std::function([stopwatch1PauseButton](){ + getModConfig().Stopwatch1Paused.SetValue(!getModConfig().Stopwatch1Paused.GetValue()); + if(getModConfig().Stopwatch1Paused.GetValue()) BSML::Lite::SetButtonText(stopwatch1PauseButton, "Start"); + else BSML::Lite::SetButtonText(stopwatch1PauseButton, "Pause"); }))); - auto stopwatchResetButton = BSML::Lite::CreateUIButton(parent, "Reset", {83, -19.9}, {-5, 8}, nullptr); - stopwatchResetButton->GetComponent()->set_ignoreLayout(true); - stopwatchResetButton->get_onClick()->AddListener(custom_types::MakeDelegate(std::function([](){ - if(ClockMod::ClockUpdater::getInstance()) ClockMod::ClockUpdater::getInstance()->resetStopwatch(); + auto stopwatch1ResetButton = BSML::Lite::CreateUIButton(parent, "Reset", {83.5, -19.9}, {-5, 0}, nullptr); + stopwatch1ResetButton->GetComponent()->set_ignoreLayout(true); + stopwatch1ResetButton->get_transform()->set_localScale({0.9, 0.9, 0.9}); + stopwatch1ResetButton->get_onClick()->AddListener(custom_types::MakeDelegate(std::function([](){ + if(ClockMod::ClockUpdater::getInstance()) ClockMod::ClockUpdater::getInstance()->resetStopwatch1(); + }))); + + auto stopwatch2PauseButton = BSML::Lite::CreateUIButton(parent, getModConfig().Stopwatch2Paused.GetValue() ? "Start" : "Pause", {70, -25.5}, {-5, 0}, nullptr); + stopwatch2PauseButton->GetComponent()->set_ignoreLayout(true); + stopwatch2PauseButton->get_transform()->set_localScale({0.9, 0.9, 0.9}); + stopwatch2PauseButton->get_onClick()->AddListener(custom_types::MakeDelegate(std::function([stopwatch2PauseButton](){ + getModConfig().Stopwatch2Paused.SetValue(!getModConfig().Stopwatch2Paused.GetValue()); + if(getModConfig().Stopwatch2Paused.GetValue()) BSML::Lite::SetButtonText(stopwatch2PauseButton, "Start"); + else BSML::Lite::SetButtonText(stopwatch2PauseButton, "Pause"); + }))); + auto stopwatch2ResetButton = BSML::Lite::CreateUIButton(parent, "Reset", {83.5, -25.5}, {-5, 0}, nullptr); + stopwatch2ResetButton->GetComponent()->set_ignoreLayout(true); + stopwatch2ResetButton->get_transform()->set_localScale({0.9, 0.9, 0.9}); + stopwatch2ResetButton->get_onClick()->AddListener(custom_types::MakeDelegate(std::function([](){ + if(ClockMod::ClockUpdater::getInstance()) ClockMod::ClockUpdater::getInstance()->resetStopwatch2(); }))); AddConfigValueDropdownEnum(parent, getModConfig().ClockType, clockTypeStrs); From 2aae1f383187eaf82321951d2773875c34bc0c4f Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 21:36:28 -0400 Subject: [PATCH 15/18] Save stopwatches every 5 seconds Quickened the save interval from every 10 seconds to every 5 seconds. The stopwatched isn't saved while in a beatmap for performace, and it takes less than 10 seconds to exit the game after finishing a beatmap. This should reduce the chance of time getting lost. --- src/ClockUpdater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index ae72e4a..0f46c98 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -226,7 +226,7 @@ namespace ClockMod { // Scuffed, but not any more than the rest of this codebase static int stopwatchSaveTimer = 0; stopwatchSaveTimer++; - if(stopwatchSaveTimer > 10 / NUM_SECONDS && !Config.IsInSong) { // Avoid dropping frames during gameplay + if(stopwatchSaveTimer > 5 / NUM_SECONDS && !Config.IsInSong) { // Avoid dropping frames during gameplay getModConfig().Stopwatch1Seconds.SetValue(stopwatch1Seconds); getModConfig().Stopwatch2Seconds.SetValue(stopwatch2Seconds); stopwatchSaveTimer = 0; From 8303062a46bf47a70000b987e2759a2b635f7daa Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 21:51:55 -0400 Subject: [PATCH 16/18] Set version to 1.15.0-Dev This number appears to have gotten left behind at 1.11.0-Dev. New features should mean new version. --- qpm.json | 2 +- qpm.shared.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qpm.json b/qpm.json index ea18ef3..88d80ce 100644 --- a/qpm.json +++ b/qpm.json @@ -6,7 +6,7 @@ "info": { "name": "Clock Mod", "id": "ClockMod", - "version": "1.11.0-Dev", + "version": "1.15.0-Dev", "url": null, "additionalData": { "overrideSoName": "libClockMod.so", diff --git a/qpm.shared.json b/qpm.shared.json index bcb8bad..14c0f37 100644 --- a/qpm.shared.json +++ b/qpm.shared.json @@ -7,7 +7,7 @@ "info": { "name": "Clock Mod", "id": "ClockMod", - "version": "1.11.0-Dev", + "version": "1.15.0-Dev", "url": null, "additionalData": { "overrideSoName": "libClockMod.so", From 865288ffbfa0d84f968ed6b1b86a35c383bce83a Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 22:01:41 -0400 Subject: [PATCH 17/18] Use stopwatch name instead of timer Additions were originally named timers, but midway through I realized that stopwatch was a more accurate name. Fixed a few variable and function names to use the updated term. --- shared/ClockUpdater.hpp | 2 +- src/ClockUpdater.cpp | 20 ++++++++++---------- src/ClockViewContoller.cpp | 7 +++---- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/shared/ClockUpdater.hpp b/shared/ClockUpdater.hpp index 7239e12..1a1fe13 100644 --- a/shared/ClockUpdater.hpp +++ b/shared/ClockUpdater.hpp @@ -49,7 +49,7 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) { void SetColor(UnityEngine::Color color); static ClockUpdater* getInstance(); static std::string getTimeFormat(); - static std::string getTimerString(const double totalSeconds); + static std::string getStopwatchString(const double totalSeconds); void ShowMessage(std::string message, int duration = 4); }; diff --git a/src/ClockUpdater.cpp b/src/ClockUpdater.cpp index 0f46c98..7fd96d2 100644 --- a/src/ClockUpdater.cpp +++ b/src/ClockUpdater.cpp @@ -55,7 +55,7 @@ namespace ClockMod { } // Turns an uncapped duration in seconds into a nicely formatted string - std::string ClockUpdater::getTimerString(const double totalSeconds) { + std::string ClockUpdater::getStopwatchString(const double totalSeconds) { int seconds = (int)totalSeconds % 60; int minutes = (int)(totalSeconds / 60) % 60; int hours = (int)(totalSeconds / 60 / 60) % 24; @@ -63,13 +63,13 @@ namespace ClockMod { bool showSeconds = getModConfig().SecToggle.GetValue(); - std::string timerStr; - if(days > 0) timerStr += fmt::format("{}:", days); - if(hours > 0 || !timerStr.empty() || !showSeconds) timerStr += timerStr.empty() ? fmt::format("{}:", hours) : fmt::format("{:02}:", hours); - timerStr += timerStr.empty() ? fmt::format("{}", minutes) : fmt::format("{:02}", minutes); - if(showSeconds) timerStr += fmt::format(":{:02}", seconds); + std::string stopwatchStr; + if(days > 0) stopwatchStr += fmt::format("{}:", days); + if(hours > 0 || !stopwatchStr.empty() || !showSeconds) stopwatchStr += stopwatchStr.empty() ? fmt::format("{}:", hours) : fmt::format("{:02}:", hours); + stopwatchStr += stopwatchStr.empty() ? fmt::format("{}", minutes) : fmt::format("{:02}", minutes); + if(showSeconds) stopwatchStr += fmt::format(":{:02}", seconds); - return timerStr; + return stopwatchStr; } // New Battery Percentage Formatting @@ -246,9 +246,9 @@ namespace ClockMod { std::string clockresult; if(!_message.empty()) clockresult = _message; - else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::SessionTime)) clockresult = getTimerString(sessionTimeSeconds); - else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::Stopwatch1)) clockresult = getTimerString(stopwatch1Seconds); - else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::Stopwatch2)) clockresult = getTimerString(stopwatch2Seconds); + else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::SessionTime)) clockresult = getStopwatchString(sessionTimeSeconds); + else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::Stopwatch1)) clockresult = getStopwatchString(stopwatch1Seconds); + else if(getModConfig().ClockType.GetValue() == static_cast(ClockTypes::Stopwatch2)) clockresult = getStopwatchString(stopwatch2Seconds); else clockresult = getTimeString((struct tm*)timeinfo); // Checks, if the clock is set to rainbowify diff --git a/src/ClockViewContoller.cpp b/src/ClockViewContoller.cpp index f5060db..68c5f89 100644 --- a/src/ClockViewContoller.cpp +++ b/src/ClockViewContoller.cpp @@ -51,10 +51,9 @@ namespace ClockMod { strftime(UTCtime, sizeof(UTCtime), std::string("\r\nCurrent Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), ClockUpdater::getInstance()->getTimeInfoUTC()); //strftime(UTCtime, sizeof(UTCtime), std::string("\r\n Current Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), gmtime(ClockUpdater::getInstance()->getRawTime())); - std::string sessionTime = "\nSession Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getSessionTimeSeconds()); - - std::string stopwatch1Time = "\nStopwatch 1 Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getStopwatch1Seconds()); - std::string stopwatch2Time = "\nStopwatch 2 Time - " + ClockUpdater::getTimerString(ClockUpdater::getInstance()->getStopwatch2Seconds()); + std::string sessionTime = "\nSession Time - " + ClockUpdater::getStopwatchString(ClockUpdater::getInstance()->getSessionTimeSeconds()); + std::string stopwatch1Time = "\nStopwatch 1 Time - " + ClockUpdater::getStopwatchString(ClockUpdater::getInstance()->getStopwatch1Seconds()); + std::string stopwatch2Time = "\nStopwatch 2 Time - " + ClockUpdater::getStopwatchString(ClockUpdater::getInstance()->getStopwatch2Seconds()); if (TimeInfo && SettingsOpen) TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime + stopwatch1Time + stopwatch2Time); From 093e77bf39869986a010fbdf2b18c1dc6507e6c4 Mon Sep 17 00:00:00 2001 From: CatsaCode Date: Mon, 1 Sep 2025 23:18:35 -0400 Subject: [PATCH 18/18] Include string_view Classes that are included from another include shouldn't be relied upon. Include string_view manually in case it disappears from the two UnityEngine includes in the future. Jokes on you CodeRabbit, I wrote each of those 22 characters on my own keyboard >:P --- include/ClockValues.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/ClockValues.hpp b/include/ClockValues.hpp index 517fd04..063f72b 100644 --- a/include/ClockValues.hpp +++ b/include/ClockValues.hpp @@ -1,6 +1,7 @@ #pragma once #include "UnityEngine/Vector3.hpp" #include "UnityEngine/UI/VerticalLayoutGroup.hpp" +#include enum class ClockTypes { CurrentTime,