Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions include/ClockModConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@

DECLARE_CONFIG(ModConfig) {

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(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.");
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);
Expand Down
14 changes: 14 additions & 0 deletions include/ClockValues.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
#pragma once
#include "UnityEngine/Vector3.hpp"
#include "UnityEngine/UI/VerticalLayoutGroup.hpp"
#include <string_view>

enum class ClockTypes {
CurrentTime,
SessionTime,
Stopwatch1,
Stopwatch2
};
static std::string_view clockTypeStrs[] = {
"Current Time",
"Session Time",
"Stopwatch 1",
"Stopwatch 2",
};

// This containts all the ClockPositions
struct ClockPos_t {
Expand Down
2 changes: 1 addition & 1 deletion qpm.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion qpm.shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 10 additions & 0 deletions shared/ClockUpdater.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) {
time_t rawtime;
struct tm* timeinfo;

double sessionTimeSeconds = 0;
double stopwatch1Seconds = 0;
double stopwatch2Seconds = 0;

static ClockUpdater* instance;

std::string _message;
Expand All @@ -36,10 +40,16 @@ DECLARE_CLASS_CODEGEN(ClockMod, ClockUpdater, UnityEngine::MonoBehaviour) {
const time_t getRawTime() const;
struct tm* getTimeInfo();
struct tm* getTimeInfoUTC();
const double getSessionTimeSeconds() const;
const double getStopwatch1Seconds() const;
const double getStopwatch2Seconds() const;
void resetStopwatch1();
void resetStopwatch2();
TMPro::TextMeshProUGUI* getTextMesh();
void SetColor(UnityEngine::Color color);
static ClockUpdater* getInstance();
static std::string getTimeFormat();
static std::string getStopwatchString(const double totalSeconds);
void ShowMessage(std::string message, int duration = 4);

};
70 changes: 61 additions & 9 deletions src/ClockUpdater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -53,6 +54,24 @@ namespace ClockMod {
return time;
}

// Turns an uncapped duration in seconds into a nicely formatted string
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;
int days = (int)(totalSeconds / 60 / 60 / 24);

bool showSeconds = getModConfig().SecToggle.GetValue();

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 stopwatchStr;
}

// New Battery Percentage Formatting
std::string getBatteryString(float level, UnityEngine::BatteryStatus status, ClockMod::ClockUpdater* instance)
{
Expand Down Expand Up @@ -136,6 +155,8 @@ namespace ClockMod {

text = get_gameObject()->GetComponent<TextMeshProUGUI*>();
clockParent = get_transform()->GetParent();
stopwatch1Seconds = getModConfig().Stopwatch1Seconds.GetValue();
stopwatch2Seconds = getModConfig().Stopwatch2Seconds.GetValue();
getModConfig().ClockColor.AddChangeEvent([this](UnityEngine::Color color) {
if (text)
text->set_color(color);
Expand Down Expand Up @@ -185,18 +206,32 @@ namespace ClockMod {
text->get_transform()->set_localScale(UnityEngine::Vector3(1, 1, 1));
}

this_time = clock();
static double lastSessionTimeSeconds = Time::get_realtimeSinceStartup();

this_time = clock();
sessionTimeSeconds = Time::get_realtimeSinceStartup();
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;
lastSessionTimeSeconds = sessionTimeSeconds;

if (!(time_counter > (double)(NUM_SECONDS * CLOCKS_PER_SEC)))
{
return;
}
time_counter = 0;

// Scuffed, but not any more than the rest of this codebase
static int stopwatchSaveTimer = 0;
stopwatchSaveTimer++;
if(stopwatchSaveTimer > 5 / NUM_SECONDS && !Config.IsInSong) { // Avoid dropping frames during gameplay
getModConfig().Stopwatch1Seconds.SetValue(stopwatch1Seconds);
getModConfig().Stopwatch2Seconds.SetValue(stopwatch2Seconds);
stopwatchSaveTimer = 0;
}

if (getModConfig().InSong.GetValue() || !Config.noTextAndHUD) {
time(&rawtime);
timeinfo = localtime(&rawtime);
Expand All @@ -210,14 +245,11 @@ 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<int>(ClockTypes::SessionTime)) clockresult = getStopwatchString(sessionTimeSeconds);
else if(getModConfig().ClockType.GetValue() == static_cast<int>(ClockTypes::Stopwatch1)) clockresult = getStopwatchString(stopwatch1Seconds);
else if(getModConfig().ClockType.GetValue() == static_cast<int>(ClockTypes::Stopwatch2)) clockresult = getStopwatchString(stopwatch2Seconds);
else clockresult = getTimeString((struct tm*)timeinfo);

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

const double ClockUpdater::getSessionTimeSeconds() const {
return sessionTimeSeconds;
}

const double ClockUpdater::getStopwatch1Seconds() const {
return stopwatch1Seconds;
}

const double ClockUpdater::getStopwatch2Seconds() const {
return stopwatch2Seconds;
}

void ClockUpdater::resetStopwatch1() {
stopwatch1Seconds = 0;
}

void ClockUpdater::resetStopwatch2() {
stopwatch2Seconds = 0;
}

TMPro::TextMeshProUGUI* ClockUpdater::getTextMesh() {
return text;
}
Expand Down
48 changes: 45 additions & 3 deletions src/ClockViewContoller.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ClockModConfig.hpp"
#include "ClockUpdater.hpp"
#include "ClockValues.hpp"
#include "ClockViewController.hpp"
using namespace ClockMod;

Expand All @@ -9,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"
Expand All @@ -22,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"


Expand All @@ -42,11 +46,17 @@ 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\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::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);
TimeInfo->set_text(std::string(timeInformation) + UTCtime + sessionTime + stopwatch1Time + stopwatch2Time);
co_yield reinterpret_cast<System::Collections::IEnumerator*>(UnityEngine::WaitForSecondsRealtime::New_ctor(0.1));
}
co_return;
Expand All @@ -67,7 +77,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,5*6});
// TimeInfo = BSML::Lite::CreateText(parent, std::string(timeInformation), TMPro::FontStyles::Normal);

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

// 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<UI::LayoutElement*>()->set_ignoreLayout(true);
stopwatch1PauseButton->get_transform()->set_localScale({0.9, 0.9, 0.9});
stopwatch1PauseButton->get_onClick()->AddListener(custom_types::MakeDelegate<Events::UnityAction*>(std::function<void()>([stopwatch1PauseButton](){
getModConfig().Stopwatch1Paused.SetValue(!getModConfig().Stopwatch1Paused.GetValue());
if(getModConfig().Stopwatch1Paused.GetValue()) BSML::Lite::SetButtonText(stopwatch1PauseButton, "Start");
else BSML::Lite::SetButtonText(stopwatch1PauseButton, "Pause");
})));
auto stopwatch1ResetButton = BSML::Lite::CreateUIButton(parent, "Reset", {83.5, -19.9}, {-5, 0}, nullptr);
stopwatch1ResetButton->GetComponent<UI::LayoutElement*>()->set_ignoreLayout(true);
stopwatch1ResetButton->get_transform()->set_localScale({0.9, 0.9, 0.9});
stopwatch1ResetButton->get_onClick()->AddListener(custom_types::MakeDelegate<Events::UnityAction*>(std::function<void()>([](){
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<UI::LayoutElement*>()->set_ignoreLayout(true);
stopwatch2PauseButton->get_transform()->set_localScale({0.9, 0.9, 0.9});
stopwatch2PauseButton->get_onClick()->AddListener(custom_types::MakeDelegate<Events::UnityAction*>(std::function<void()>([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<UI::LayoutElement*>()->set_ignoreLayout(true);
stopwatch2ResetButton->get_transform()->set_localScale({0.9, 0.9, 0.9});
stopwatch2ResetButton->get_onClick()->AddListener(custom_types::MakeDelegate<Events::UnityAction*>(std::function<void()>([](){
if(ClockMod::ClockUpdater::getInstance()) ClockMod::ClockUpdater::getInstance()->resetStopwatch2();
})));

AddConfigValueDropdownEnum(parent, getModConfig().ClockType, clockTypeStrs);
AddConfigValueToggle(parent, getModConfig().InSong);
AddConfigValueToggle(parent, getModConfig().InReplay);
AddConfigValueToggle(parent, getModConfig().TwelveToggle);
Expand Down