Skip to content

Commit cda6e05

Browse files
Merge pull request #24 from CatsaCode/main
Added session time and stopwatches
2 parents e2d3d2c + 093e77b commit cda6e05

File tree

7 files changed

+145
-22
lines changed

7 files changed

+145
-22
lines changed

include/ClockModConfig.hpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33

44
DECLARE_CONFIG(ModConfig) {
55

6-
CONFIG_VALUE(InSong, bool, "Show During Song", true, "If the Clock should be shown while playing a beatmap.");
7-
CONFIG_VALUE(InReplay, bool, "Show During Replay", true, "If the Clock should be shown while playing a replay.");
8-
CONFIG_VALUE(TwelveToggle, bool, "24/12 Toggle", false, "If time should be in 12 or 24 hour format.");
9-
CONFIG_VALUE(SecToggle, bool, "Show Seconds", false, "If seconds should be displayed.");
10-
CONFIG_VALUE(BattToggle, bool, "Show Battery Percentage", false, "Displays Battery percentage next to the clock.");
11-
CONFIG_VALUE(RainbowClock, bool, "Rainbowify it", false, "Makes the Clock beautiful.");
12-
CONFIG_VALUE(FontSize, float, "Font Size", 3.5, "Changes the Font Size of the Clock (Default: 3.5)");
13-
CONFIG_VALUE(ClockPosition, bool, "Clock Position (Top/Bottom)", false, "If the Clock should be at the top or the bottom");
6+
CONFIG_VALUE(ClockType, int, "Clock Type", 0, "Which time the Clock should display.");
7+
CONFIG_VALUE(Stopwatch1Seconds, int, "Stopwatch 1 Seconds", 0, "The saved time on stopwatch 1.");
8+
CONFIG_VALUE(Stopwatch2Seconds, int, "Stopwatch 2 Seconds", 0, "The saved time on stopwatch 2.");
9+
CONFIG_VALUE(Stopwatch1Paused, bool, "Stopwatch 1 Paused", true, "If stopwatch 1 is locked from incrementing.");
10+
CONFIG_VALUE(Stopwatch2Paused, bool, "Stopwatch 2 Paused", true, "If stopwatch 2 is locked from incrementing.");
11+
CONFIG_VALUE(InSong, bool, "Show During Song", true, "If the Clock should be shown while playing a beatmap.");
12+
CONFIG_VALUE(InReplay, bool, "Show During Replay", true, "If the Clock should be shown while playing a replay.");
13+
CONFIG_VALUE(TwelveToggle, bool, "24/12 Toggle", false, "If time should be in 12 or 24 hour format.");
14+
CONFIG_VALUE(SecToggle, bool, "Show Seconds", false, "If seconds should be displayed.");
15+
CONFIG_VALUE(BattToggle, bool, "Show Battery Percentage", false, "Displays Battery percentage next to the clock.");
16+
CONFIG_VALUE(RainbowClock, bool, "Rainbowify it", false, "Makes the Clock beautiful.");
17+
CONFIG_VALUE(FontSize, float, "Font Size", 3.5, "Changes the Font Size of the Clock (Default: 3.5)");
18+
CONFIG_VALUE(ClockPosition, bool, "Clock Position (Top/Bottom)", false, "If the Clock should be at the top or the bottom");
1419

1520
// CONFIG_VALUE(ClockXOffset, double, "Clock X Offset", 0);
1621
// CONFIG_VALUE(ClockYOffset, double, "Clock Y Offset", 0);

include/ClockValues.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
#pragma once
22
#include "UnityEngine/Vector3.hpp"
33
#include "UnityEngine/UI/VerticalLayoutGroup.hpp"
4+
#include <string_view>
5+
6+
enum class ClockTypes {
7+
CurrentTime,
8+
SessionTime,
9+
Stopwatch1,
10+
Stopwatch2
11+
};
12+
static std::string_view clockTypeStrs[] = {
13+
"Current Time",
14+
"Session Time",
15+
"Stopwatch 1",
16+
"Stopwatch 2",
17+
};
418

519
// This containts all the ClockPositions
620
struct ClockPos_t {

qpm.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"info": {
77
"name": "Clock Mod",
88
"id": "ClockMod",
9-
"version": "1.11.0-Dev",
9+
"version": "1.15.0-Dev",
1010
"url": null,
1111
"additionalData": {
1212
"overrideSoName": "libClockMod.so",

qpm.shared.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"info": {
88
"name": "Clock Mod",
99
"id": "ClockMod",
10-
"version": "1.11.0-Dev",
10+
"version": "1.15.0-Dev",
1111
"url": null,
1212
"additionalData": {
1313
"overrideSoName": "libClockMod.so",

shared/ClockUpdater.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) {
2727
time_t rawtime;
2828
struct tm* timeinfo;
2929

30+
double sessionTimeSeconds = 0;
31+
double stopwatch1Seconds = 0;
32+
double stopwatch2Seconds = 0;
33+
3034
static ClockUpdater* instance;
3135

3236
std::string _message;
@@ -36,10 +40,16 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) {
3640
const time_t getRawTime() const;
3741
struct tm* getTimeInfo();
3842
struct tm* getTimeInfoUTC();
43+
const double getSessionTimeSeconds() const;
44+
const double getStopwatch1Seconds() const;
45+
const double getStopwatch2Seconds() const;
46+
void resetStopwatch1();
47+
void resetStopwatch2();
3948
TMPro::TextMeshProUGUI* getTextMesh();
4049
void SetColor(UnityEngine::Color color);
4150
static ClockUpdater* getInstance();
4251
static std::string getTimeFormat();
52+
static std::string getStopwatchString(const double totalSeconds);
4353
void ShowMessage(std::string message, int duration = 4);
4454

4555
};

src/ClockUpdater.cpp

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "UnityEngine/BatteryStatus.hpp"
1111
#include "UnityEngine/GradientColorKey.hpp"
1212
#include "UnityEngine/SystemInfo.hpp"
13+
#include "UnityEngine/Time.hpp"
1314

1415
using namespace UnityEngine;
1516
using namespace TMPro;
@@ -53,6 +54,24 @@ namespace ClockMod {
5354
return time;
5455
}
5556

57+
// Turns an uncapped duration in seconds into a nicely formatted string
58+
std::string ClockUpdater::getStopwatchString(const double totalSeconds) {
59+
int seconds = (int)totalSeconds % 60;
60+
int minutes = (int)(totalSeconds / 60) % 60;
61+
int hours = (int)(totalSeconds / 60 / 60) % 24;
62+
int days = (int)(totalSeconds / 60 / 60 / 24);
63+
64+
bool showSeconds = getModConfig().SecToggle.GetValue();
65+
66+
std::string stopwatchStr;
67+
if(days > 0) stopwatchStr += fmt::format("{}:", days);
68+
if(hours > 0 || !stopwatchStr.empty() || !showSeconds) stopwatchStr += stopwatchStr.empty() ? fmt::format("{}:", hours) : fmt::format("{:02}:", hours);
69+
stopwatchStr += stopwatchStr.empty() ? fmt::format("{}", minutes) : fmt::format("{:02}", minutes);
70+
if(showSeconds) stopwatchStr += fmt::format(":{:02}", seconds);
71+
72+
return stopwatchStr;
73+
}
74+
5675
// New Battery Percentage Formatting
5776
std::string getBatteryString(float level, UnityEngine::BatteryStatus status, ClockMod::ClockUpdater* instance)
5877
{
@@ -136,6 +155,8 @@ namespace ClockMod {
136155

137156
text = get_gameObject()->GetComponent<TextMeshProUGUI*>();
138157
clockParent = get_transform()->GetParent();
158+
stopwatch1Seconds = getModConfig().Stopwatch1Seconds.GetValue();
159+
stopwatch2Seconds = getModConfig().Stopwatch2Seconds.GetValue();
139160
getModConfig().ClockColor.AddChangeEvent([this](UnityEngine::Color color) {
140161
if (text)
141162
text->set_color(color);
@@ -185,18 +206,32 @@ namespace ClockMod {
185206
text->get_transform()->set_localScale(UnityEngine::Vector3(1, 1, 1));
186207
}
187208

188-
this_time = clock();
209+
static double lastSessionTimeSeconds = Time::get_realtimeSinceStartup();
189210

211+
this_time = clock();
212+
sessionTimeSeconds = Time::get_realtimeSinceStartup();
213+
if(!getModConfig().Stopwatch1Paused.GetValue()) stopwatch1Seconds += sessionTimeSeconds - lastSessionTimeSeconds;
214+
if(!getModConfig().Stopwatch2Paused.GetValue()) stopwatch2Seconds += sessionTimeSeconds - lastSessionTimeSeconds;
190215
time_counter += (double)(this_time - last_time);
191216

192217
last_time = this_time;
218+
lastSessionTimeSeconds = sessionTimeSeconds;
193219

194220
if (!(time_counter > (double)(NUM_SECONDS * CLOCKS_PER_SEC)))
195221
{
196222
return;
197223
}
198224
time_counter = 0;
199225

226+
// Scuffed, but not any more than the rest of this codebase
227+
static int stopwatchSaveTimer = 0;
228+
stopwatchSaveTimer++;
229+
if(stopwatchSaveTimer > 5 / NUM_SECONDS && !Config.IsInSong) { // Avoid dropping frames during gameplay
230+
getModConfig().Stopwatch1Seconds.SetValue(stopwatch1Seconds);
231+
getModConfig().Stopwatch2Seconds.SetValue(stopwatch2Seconds);
232+
stopwatchSaveTimer = 0;
233+
}
234+
200235
if (getModConfig().InSong.GetValue() || !Config.noTextAndHUD) {
201236
time(&rawtime);
202237
timeinfo = localtime(&rawtime);
@@ -210,14 +245,11 @@ namespace ClockMod {
210245
ClockPos.ap1 = (timeinfo && timeinfo->tm_mon == 3 && timeinfo->tm_mday == 1);
211246

212247
std::string clockresult;
213-
214-
if (_message.empty()) {
215-
// Gets the time using the function at the top.
216-
clockresult = getTimeString((struct tm*)timeinfo);
217-
}
218-
else {
219-
clockresult = _message;
220-
}
248+
if(!_message.empty()) clockresult = _message;
249+
else if(getModConfig().ClockType.GetValue() == static_cast<int>(ClockTypes::SessionTime)) clockresult = getStopwatchString(sessionTimeSeconds);
250+
else if(getModConfig().ClockType.GetValue() == static_cast<int>(ClockTypes::Stopwatch1)) clockresult = getStopwatchString(stopwatch1Seconds);
251+
else if(getModConfig().ClockType.GetValue() == static_cast<int>(ClockTypes::Stopwatch2)) clockresult = getStopwatchString(stopwatch2Seconds);
252+
else clockresult = getTimeString((struct tm*)timeinfo);
221253

222254
// Checks, if the clock is set to rainbowify
223255
if (getModConfig().RainbowClock.GetValue()) {
@@ -265,6 +297,26 @@ namespace ClockMod {
265297
return gmtime(&time);
266298
}
267299

300+
const double ClockUpdater::getSessionTimeSeconds() const {
301+
return sessionTimeSeconds;
302+
}
303+
304+
const double ClockUpdater::getStopwatch1Seconds() const {
305+
return stopwatch1Seconds;
306+
}
307+
308+
const double ClockUpdater::getStopwatch2Seconds() const {
309+
return stopwatch2Seconds;
310+
}
311+
312+
void ClockUpdater::resetStopwatch1() {
313+
stopwatch1Seconds = 0;
314+
}
315+
316+
void ClockUpdater::resetStopwatch2() {
317+
stopwatch2Seconds = 0;
318+
}
319+
268320
TMPro::TextMeshProUGUI* ClockUpdater::getTextMesh() {
269321
return text;
270322
}

src/ClockViewContoller.cpp

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "ClockModConfig.hpp"
22
#include "ClockUpdater.hpp"
3+
#include "ClockValues.hpp"
34
#include "ClockViewController.hpp"
45
using namespace ClockMod;
56

@@ -9,6 +10,7 @@ using namespace ClockMod;
910
#include "bsml/shared/BSML/Components/ModalColorPicker.hpp"
1011
#include "custom-types/shared/coroutine.hpp"
1112
#include "custom-types/shared/macros.hpp"
13+
#include "custom-types/shared/delegate.hpp"
1214

1315
#include "HMUI/CurvedTextMeshPro.hpp"
1416
#include "HMUI/ScrollView.hpp"
@@ -22,6 +24,8 @@ using namespace ClockMod;
2224
#include "UnityEngine/Canvas.hpp"
2325
#include "UnityEngine/Color.hpp"
2426
#include "UnityEngine/GameObject.hpp"
27+
#include "UnityEngine/UI/Button.hpp"
28+
#include "UnityEngine/UI/LayoutElement.hpp"
2529
#include "UnityEngine/WaitForSecondsRealtime.hpp"
2630

2731

@@ -42,11 +46,17 @@ namespace ClockMod {
4246
while (SettingsOpen) {
4347
char timeInformation[45];
4448
strftime(timeInformation, sizeof(timeInformation), "Your Timezone - %Z UTC offset - %z", ClockUpdater::getInstance()->getTimeInfo());
49+
4550
char UTCtime[40];
46-
strftime(UTCtime, sizeof(UTCtime), std::string("\r\n Current Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), ClockUpdater::getInstance()->getTimeInfoUTC());
51+
strftime(UTCtime, sizeof(UTCtime), std::string("\r\nCurrent Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), ClockUpdater::getInstance()->getTimeInfoUTC());
4752
//strftime(UTCtime, sizeof(UTCtime), std::string("\r\n Current Time in UTC - " + ClockUpdater::getTimeFormat()).c_str(), gmtime(ClockUpdater::getInstance()->getRawTime()));
53+
54+
std::string sessionTime = "\nSession Time - " + ClockUpdater::getStopwatchString(ClockUpdater::getInstance()->getSessionTimeSeconds());
55+
std::string stopwatch1Time = "\nStopwatch 1 Time - " + ClockUpdater::getStopwatchString(ClockUpdater::getInstance()->getStopwatch1Seconds());
56+
std::string stopwatch2Time = "\nStopwatch 2 Time - " + ClockUpdater::getStopwatchString(ClockUpdater::getInstance()->getStopwatch2Seconds());
57+
4858
if (TimeInfo && SettingsOpen)
49-
TimeInfo->set_text(std::string(timeInformation) + UTCtime);
59+
TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime + stopwatch1Time + stopwatch2Time);
5060
co_yield reinterpret_cast<System::Collections::IEnumerator*>(UnityEngine::WaitForSecondsRealtime::New_ctor(0.1));
5161
}
5262
co_return;
@@ -67,7 +77,7 @@ namespace ClockMod {
6777
std::string timeFormat = "Your Timezone - %Z\nUTC offset - %z";
6878
strftime(timeInformation, sizeof(timeInformation), timeFormat.c_str(), instance->getTimeInfo());
6979
// We have to specify sizeDelta here otherwise things will overlap
70-
TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal, {0,0}, {0,15});
80+
TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal, {0,0}, {0,5*6});
7181
// TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal);
7282

7383
ColorPicker = BSML::Lite::CreateColorPickerModal(parent, getModConfig().ClockColor.GetName(), getModConfig().ClockColor.GetValue(),
@@ -83,6 +93,38 @@ namespace ClockMod {
8393
);
8494
}
8595

96+
// 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
97+
auto stopwatch1PauseButton = BSML::Lite::CreateUIButton(parent, getModConfig().Stopwatch1Paused.GetValue() ? "Start" : "Pause", {70, -19.9}, {-5, 0}, nullptr);
98+
stopwatch1PauseButton->GetComponent<UI::LayoutElement*>()->set_ignoreLayout(true);
99+
stopwatch1PauseButton->get_transform()->set_localScale({0.9, 0.9, 0.9});
100+
stopwatch1PauseButton->get_onClick()->AddListener(custom_types::MakeDelegate<Events::UnityAction*>(std::function<void()>([stopwatch1PauseButton](){
101+
getModConfig().Stopwatch1Paused.SetValue(!getModConfig().Stopwatch1Paused.GetValue());
102+
if(getModConfig().Stopwatch1Paused.GetValue()) BSML::Lite::SetButtonText(stopwatch1PauseButton, "Start");
103+
else BSML::Lite::SetButtonText(stopwatch1PauseButton, "Pause");
104+
})));
105+
auto stopwatch1ResetButton = BSML::Lite::CreateUIButton(parent, "Reset", {83.5, -19.9}, {-5, 0}, nullptr);
106+
stopwatch1ResetButton->GetComponent<UI::LayoutElement*>()->set_ignoreLayout(true);
107+
stopwatch1ResetButton->get_transform()->set_localScale({0.9, 0.9, 0.9});
108+
stopwatch1ResetButton->get_onClick()->AddListener(custom_types::MakeDelegate<Events::UnityAction*>(std::function<void()>([](){
109+
if(ClockMod::ClockUpdater::getInstance()) ClockMod::ClockUpdater::getInstance()->resetStopwatch1();
110+
})));
111+
112+
auto stopwatch2PauseButton = BSML::Lite::CreateUIButton(parent, getModConfig().Stopwatch2Paused.GetValue() ? "Start" : "Pause", {70, -25.5}, {-5, 0}, nullptr);
113+
stopwatch2PauseButton->GetComponent<UI::LayoutElement*>()->set_ignoreLayout(true);
114+
stopwatch2PauseButton->get_transform()->set_localScale({0.9, 0.9, 0.9});
115+
stopwatch2PauseButton->get_onClick()->AddListener(custom_types::MakeDelegate<Events::UnityAction*>(std::function<void()>([stopwatch2PauseButton](){
116+
getModConfig().Stopwatch2Paused.SetValue(!getModConfig().Stopwatch2Paused.GetValue());
117+
if(getModConfig().Stopwatch2Paused.GetValue()) BSML::Lite::SetButtonText(stopwatch2PauseButton, "Start");
118+
else BSML::Lite::SetButtonText(stopwatch2PauseButton, "Pause");
119+
})));
120+
auto stopwatch2ResetButton = BSML::Lite::CreateUIButton(parent, "Reset", {83.5, -25.5}, {-5, 0}, nullptr);
121+
stopwatch2ResetButton->GetComponent<UI::LayoutElement*>()->set_ignoreLayout(true);
122+
stopwatch2ResetButton->get_transform()->set_localScale({0.9, 0.9, 0.9});
123+
stopwatch2ResetButton->get_onClick()->AddListener(custom_types::MakeDelegate<Events::UnityAction*>(std::function<void()>([](){
124+
if(ClockMod::ClockUpdater::getInstance()) ClockMod::ClockUpdater::getInstance()->resetStopwatch2();
125+
})));
126+
127+
AddConfigValueDropdownEnum(parent, getModConfig().ClockType, clockTypeStrs);
86128
AddConfigValueToggle(parent, getModConfig().InSong);
87129
AddConfigValueToggle(parent, getModConfig().InReplay);
88130
AddConfigValueToggle(parent, getModConfig().TwelveToggle);

0 commit comments

Comments
 (0)