From fb20f802d48076535d0cc97e9bdfa31c82eeaeb9 Mon Sep 17 00:00:00 2001 From: Andrew Thomas Date: Sun, 1 Sep 2019 10:02:20 -0500 Subject: [PATCH 1/4] Added a new delete button and decimal place slider Added another button that allows resetting the personal times and deleting the saved file. Added an 'int' slider to configure how many decimal places we want to record to --- settings/kickofftimerplugin.set | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/settings/kickofftimerplugin.set b/settings/kickofftimerplugin.set index c99bab9..ba258ec 100644 --- a/settings/kickofftimerplugin.set +++ b/settings/kickofftimerplugin.set @@ -1,6 +1,13 @@ Kickoff timer plugin +9|Controls +8 0|Load|plugin load kickofftimerplugin 7 0|Unload|plugin unload kickofftimerplugin 7 0|Reset Personal Best|kickofftimer_reset +7 +0|Reset Personal Best and Delete file|kickofftimer_resetAndDelete +9|Config Values +8 +5|How many decimal places to record time|kickofftimer_decimalPlaces|2|4 \ No newline at end of file From ad8d7daf71aac656742cf63149b1dc760cf22f38 Mon Sep 17 00:00:00 2001 From: Andrew Thomas Date: Sun, 1 Sep 2019 10:07:41 -0500 Subject: [PATCH 2/4] Refactored color codes, added decimal support.. Refactored the color codes to make them easier to change if needed in the future Added support for the button to reset and delete a file Overall refactored some logic to reduce nesting, use some more modern looping, etc. --- KickoffTimerPlugin.cpp | 246 ++++++++++++++++++++++++++++------------- KickoffTimerPlugin.h | 15 ++- 2 files changed, 180 insertions(+), 81 deletions(-) diff --git a/KickoffTimerPlugin.cpp b/KickoffTimerPlugin.cpp index 5df7bfb..b204218 100644 --- a/KickoffTimerPlugin.cpp +++ b/KickoffTimerPlugin.cpp @@ -1,28 +1,46 @@ #include "KickoffTimerPlugin.h" -#include "bakkesmod\wrappers\includes.h" +#include "bakkesmod/wrappers/includes.h" #include "utils/parser.h" #include +#include +#include BAKKESMOD_PLUGIN(KickoffTimerPlugin, "Kickoff timer plugin", "0.1", PLUGINTYPE_FREEPLAY) -static const string savefile = "bakkesmod/data/kickofftimerplugin.data"; +string savefile = "bakkesmod/data/kickofftimerplugin.data"; +enum event_types { normal, better_than_normal, new_pb, slow_time }; +map color_mapping = +{ + { normal, { 255, 255, 255 }}, // White + { better_than_normal, { 255, 200, 0 }}, // Yellow-ish + { new_pb, { 0, 255, 0 }}, // Green + { slow_time, { 255, 0, 0 }} // Red +}; + +int DECIMAL_PRECISION; void KickoffTimerPlugin::onLoad() { spawnLocations.push_back({ "ML", {256, -3840}, 2.30312 }); spawnLocations.push_back({ "MR", {-256, -3840}, 2.30312 }); - spawnLocations.push_back({ "M", {0, -4608}, 2.62897 }); - spawnLocations.push_back({ "L", {2048, -2560}, 2.06905 }); - spawnLocations.push_back({ "R", {-2048, -2560}, 2.06905 }); + spawnLocations.push_back({ "M", {0, -4608}, 2.62897 }); + spawnLocations.push_back({ "L", {2048, -2560}, 2.06905 }); + spawnLocations.push_back({ "R", {-2048, -2560}, 2.06905 }); - load(); + loadPBFile(); cvarManager->registerNotifier("kickofftimer_reset", [this](std::vector params) { - for (int i = 0; i < spawnLocations.size(); i++) { - spawnLocations.at(i).personalBest = -1; - } + ResetAndDeleteFile(false); }, "Reset personal bests", PERMISSION_ALL); + cvarManager->registerNotifier("kickofftimer_resetAndDelete", [this](std::vector params) { + ResetAndDeleteFile(true); + }, "Reset personal bests and Delete PB file", PERMISSION_ALL); + + cvarManager->registerCvar("kickofftimer_decimalPlaces", "2", "How many decimal places to record time", true, true, 2, true, 4, true); + cvarManager->getCvar("kickofftimer_decimalPlaces").addOnValueChanged(std::bind(&KickoffTimerPlugin::updateDecimalValue, this)); + + DECIMAL_PRECISION = cvarManager->getCvar("kickofftimer_decimalPlaces").getIntValue(); pDefaultTime = {""}; pBest = { ""}; pBallHitted = { ""}; @@ -36,9 +54,23 @@ void KickoffTimerPlugin::onLoad() gameWrapper->RegisterDrawable(std::bind(&KickoffTimerPlugin::Render, this, std::placeholders::_1)); } +void KickoffTimerPlugin::ResetAndDeleteFile(const bool deleteFile) +{ + for (auto& spawn_location : spawnLocations) + { + spawn_location.personalBest = -1; + } + + if (deleteFile) + { + const auto path = experimental::filesystem::absolute(savefile); + remove(path); + } +} + void KickoffTimerPlugin::onUnload() { - save(); + savePBFile(); } void KickoffTimerPlugin::onHitBall(std::string eventName) @@ -46,34 +78,78 @@ void KickoffTimerPlugin::onHitBall(std::string eventName) if (!gameWrapper->IsInGame() || hitted || spawn == 0) return; + const int decimalMultiplyer = pow(10, DECIMAL_PRECISION); + timeHit = gameWrapper->GetGameEventAsServer().GetSecondsElapsed() - timeStart; + timeHit = roundf(timeHit * decimalMultiplyer) / decimalMultiplyer; // Round to a certain decimal place + cvarManager->log("timeHit: " + std::to_string(timeHit)); + hitted = true; - if (spawn->personalBest == -1) + const auto current_pb = spawn->personalBest; + cvarManager->log("current_pb: " + std::to_string(current_pb)); + + auto normal_time = spawn->normalTime; + normal_time = roundf(normal_time * decimalMultiplyer) / decimalMultiplyer; // Round to a certain decimal place + cvarManager->log("normal_time: " + std::to_string(normal_time)); + + // First time, set it to PB + if (current_pb == -1) { spawn->personalBest = timeHit; - pBallHitted.color = { 255,255,255 }; + + auto message = "First time! Ball hitted after " + + to_string_with_precision(timeHit, DECIMAL_PRECISION) + " seconds."; + SetHitTextWithTimeAndText(timeHit, message); + return; } - else + + // If its above normal, thats slow my friend + if (timeHit > normal_time) { - if (timeHit < spawn->personalBest) - { - pBallHitted.color = { 255,200,0 }; - spawn->personalBest = timeHit; - } - else { - pBallHitted.color = { 255,0,0 }; - } - + pBallHitted.color = color_mapping[slow_time]; + SetHitTextWithTime(timeHit); + return; + } + + // If its a new pb, congrats! + if (timeHit < current_pb) + { + spawn->personalBest = timeHit; + pBallHitted.color = color_mapping[new_pb]; + SetHitTextWithTime(timeHit); + return; } - if (timeHit < spawn->normalTime) + + // If its higher than your current pb + // (and lower than normal, since other checks failed) + // Then you can do better! + if (timeHit > current_pb) { - pBallHitted.color = { 0,255,0 }; + pBallHitted.color = color_mapping[better_than_normal]; + SetHitTextWithTime(timeHit); + return; } + // If they end up being equal to either time, just output it normally + pBallHitted.color = color_mapping[normal]; + SetHitTextWithTime(timeHit); +} + +void KickoffTimerPlugin::SetHitTextWithTime(const float time_hit) +{ + std::ostringstream os; + + os << "Ball hitted after " << to_string_with_precision(time_hit, DECIMAL_PRECISION) << " seconds."; + const auto msg = os.str(); + pBallHitted.text = msg; +} + +void KickoffTimerPlugin::SetHitTextWithTimeAndText(const float time_hit, string& message) +{ std::ostringstream os; - os << "Ball hitted after " << to_string_with_precision(timeHit, 2) << " seconds."; - std::string msg = os.str(); + os << message; + const auto msg = os.str(); pBallHitted.text = msg; } @@ -94,18 +170,25 @@ void KickoffTimerPlugin::onReset(std::string eventName) pBallHitted.text = ""; spawn = getSpawnLocation(); - if (spawn != 0) { - std::ostringstream os; - os << spawn->name << " normal Kickoff time: " << to_string_with_precision(spawn->normalTime, 2) << " seconds"; - std::string msg = os.str(); - pDefaultTime.text = msg; - - os.str(""); - os.clear(); - if(spawn->personalBest > 0) os << "Personal Best: " << to_string_with_precision(spawn->personalBest, 2) << " seconds"; - msg = os.str(); - pBest.text = msg; + + if (nullptr == spawn) + { + cvarManager->log("Can't get spawnLocation!."); + return; } + + std::ostringstream os; + os << spawn->name << " normal Kickoff time: " << + to_string_with_precision(spawn->normalTime, DECIMAL_PRECISION) << " seconds"; + auto msg = os.str(); + pDefaultTime.text = msg; + + os.str(""); + os.clear(); + if(spawn->personalBest > 0) os << "Personal Best: " << + to_string_with_precision(spawn->personalBest, DECIMAL_PRECISION) << " seconds"; + msg = os.str(); + pBest.text = msg; } void KickoffTimerPlugin::Render(CanvasWrapper canvas) @@ -113,75 +196,86 @@ void KickoffTimerPlugin::Render(CanvasWrapper canvas) if (!gameWrapper->IsInGame() || popups.empty() || !spawn != 0) return; - auto screenSize = canvas.GetSize(); - for(int i = 0; i < popups.size(); i++) + const auto screen_size = canvas.GetSize(); + for(auto i = 0; i < popups.size(); i++) { auto pop = popups.at(i); if (pop->startLocation.X < 0) { - pop->startLocation = {(int)(screenSize.X * 0.35), (int)(screenSize.Y * 0.1 + i * 0.035 * screenSize.Y)}; + pop->startLocation = + { + static_cast(screen_size.X * 0.35), + static_cast(screen_size.Y * 0.1 + i * 0.035 * screen_size.Y) + }; } - Vector2 drawLoc = { pop->startLocation.X, pop->startLocation.Y }; - canvas.SetPosition(drawLoc); - canvas.SetColor(pop->color.R, pop->color.G, pop->color.B, 255); + const Vector2 draw_loc = { pop->startLocation.X, pop->startLocation.Y }; + canvas.SetPosition(draw_loc); + canvas.SetColor(pop->color.R, pop->color.G, pop->color.B, 225); canvas.DrawString(pop->text, 3, 3); } } SpawnLocation* KickoffTimerPlugin::getSpawnLocation() { - auto location = gameWrapper->GetLocalCar().GetLocation(); - for(int i = 0; i < spawnLocations.size(); i++) + const auto location = gameWrapper->GetLocalCar().GetLocation(); + + for (auto& spawn_location : spawnLocations) { - auto it = &spawnLocations.at(i); - if (location.X == it->location.X && location.Y == it->location.Y) { + const auto it = &spawn_location; + if (location.X == it->location.X && + location.Y == it->location.Y) { return it; } } - return 0; + return nullptr; } -void KickoffTimerPlugin::save() { +void KickoffTimerPlugin::savePBFile() { ofstream myfile; myfile.open(savefile); - if (myfile.is_open()) + + if (!myfile.is_open()) { - for (int i = 0; i < spawnLocations.size(); i++) - { - myfile << spawnLocations.at(i).personalBest << "\n"; - } + cvarManager->log("Can't write savefile."); + myfile.close(); + return; } - else + + for (auto& spawn_location : spawnLocations) { - cvarManager->log("Can't write savefile."); + myfile << spawn_location.personalBest << "\n"; } + myfile.close(); } -void KickoffTimerPlugin::load() { +void KickoffTimerPlugin::loadPBFile() { ifstream myfile; myfile.open(savefile); - if (myfile.good()) + if (!myfile.good()) { - float f; - char buffer[8]; + cvarManager->log("Can't read savefile."); + return; + } + + char buffer[8]; + + for (auto& spawn_location : spawnLocations) + { + myfile.getline(buffer, 8); - for (int i = 0; i < spawnLocations.size(); i++) + // There should be the same number of lines in the file as spawnLocations + if (myfile.eof()) { - myfile.getline(buffer, 8); - if (!myfile.eof()) - { - f = (float)atof(buffer); - spawnLocations.at(i).personalBest = f; - } - else - { - cvarManager->log("End of savefile reached too early!"); - break; - } + cvarManager->log("End of savefile reached too early!"); + return; } + + const auto f = static_cast(atof(buffer)); + spawn_location.personalBest = f; } - else - { - cvarManager->log("Can't read savefile."); - } +} + +void KickoffTimerPlugin::updateDecimalValue() +{ + DECIMAL_PRECISION = cvarManager->getCvar("kickofftimer_decimalPlaces").getIntValue(); } diff --git a/KickoffTimerPlugin.h b/KickoffTimerPlugin.h index c3343d9..47a723e 100644 --- a/KickoffTimerPlugin.h +++ b/KickoffTimerPlugin.h @@ -26,24 +26,29 @@ struct SpawnLocation class KickoffTimerPlugin : public BakkesMod::Plugin::BakkesModPlugin { private: - float timeStart; - float timeHit; + float timeStart{}; + float timeHit{}; bool hitted = false; std::vector popups; Popup pDefaultTime; Popup pBallHitted; Popup pBest; std::vector spawnLocations; - SpawnLocation* spawn; + SpawnLocation* spawn{}; public: virtual void onLoad(); virtual void onUnload(); + virtual void onHitBall(std::string eventName); virtual void onStartedDriving(std::string eventName); virtual void onReset(std::string eventName); virtual void Render(CanvasWrapper canvas); virtual SpawnLocation* getSpawnLocation(); - virtual void save(); - virtual void load(); + virtual void savePBFile(); + virtual void loadPBFile(); + virtual void SetHitTextWithTime(float time_hit); + virtual void SetHitTextWithTimeAndText(float time_hit, string& message); + virtual void ResetAndDeleteFile(bool deleteFile); + virtual void updateDecimalValue(); }; From 4db3955390b775ef56b1ff1a6686bb437691706b Mon Sep 17 00:00:00 2001 From: Andrew Thomas Date: Sun, 1 Sep 2019 13:57:43 -0500 Subject: [PATCH 3/4] Removed delete functions per code review --- KickoffTimerPlugin.cpp | 32 ++++++++++++-------------------- KickoffTimerPlugin.h | 2 +- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/KickoffTimerPlugin.cpp b/KickoffTimerPlugin.cpp index b204218..e96fc6b 100644 --- a/KickoffTimerPlugin.cpp +++ b/KickoffTimerPlugin.cpp @@ -2,12 +2,10 @@ #include "bakkesmod/wrappers/includes.h" #include "utils/parser.h" #include -#include -#include BAKKESMOD_PLUGIN(KickoffTimerPlugin, "Kickoff timer plugin", "0.1", PLUGINTYPE_FREEPLAY) -string savefile = "bakkesmod/data/kickofftimerplugin.data"; +static const string savefile = "bakkesmod/data/kickofftimerplugin.data"; enum event_types { normal, better_than_normal, new_pb, slow_time }; map color_mapping = { @@ -23,19 +21,16 @@ void KickoffTimerPlugin::onLoad() { spawnLocations.push_back({ "ML", {256, -3840}, 2.30312 }); spawnLocations.push_back({ "MR", {-256, -3840}, 2.30312 }); - spawnLocations.push_back({ "M", {0, -4608}, 2.62897 }); - spawnLocations.push_back({ "L", {2048, -2560}, 2.06905 }); - spawnLocations.push_back({ "R", {-2048, -2560}, 2.06905 }); + spawnLocations.push_back({ "M", {0, -4608}, 2.62897 }); + spawnLocations.push_back({ "L", {2048, -2560}, 2.06905 }); + spawnLocations.push_back({ "R", {-2048, -2560}, 2.06905 }); loadPBFile(); cvarManager->registerNotifier("kickofftimer_reset", [this](std::vector params) { - ResetAndDeleteFile(false); + ResetPersonalBests(); }, "Reset personal bests", PERMISSION_ALL); - cvarManager->registerNotifier("kickofftimer_resetAndDelete", [this](std::vector params) { - ResetAndDeleteFile(true); - }, "Reset personal bests and Delete PB file", PERMISSION_ALL); cvarManager->registerCvar("kickofftimer_decimalPlaces", "2", "How many decimal places to record time", true, true, 2, true, 4, true); cvarManager->getCvar("kickofftimer_decimalPlaces").addOnValueChanged(std::bind(&KickoffTimerPlugin::updateDecimalValue, this)); @@ -54,18 +49,12 @@ void KickoffTimerPlugin::onLoad() gameWrapper->RegisterDrawable(std::bind(&KickoffTimerPlugin::Render, this, std::placeholders::_1)); } -void KickoffTimerPlugin::ResetAndDeleteFile(const bool deleteFile) +void KickoffTimerPlugin::ResetPersonalBests() { for (auto& spawn_location : spawnLocations) { spawn_location.personalBest = -1; } - - if (deleteFile) - { - const auto path = experimental::filesystem::absolute(savefile); - remove(path); - } } void KickoffTimerPlugin::onUnload() @@ -216,7 +205,8 @@ void KickoffTimerPlugin::Render(CanvasWrapper canvas) } } -SpawnLocation* KickoffTimerPlugin::getSpawnLocation() { +SpawnLocation* KickoffTimerPlugin::getSpawnLocation() +{ const auto location = gameWrapper->GetLocalCar().GetLocation(); for (auto& spawn_location : spawnLocations) @@ -230,7 +220,8 @@ SpawnLocation* KickoffTimerPlugin::getSpawnLocation() { return nullptr; } -void KickoffTimerPlugin::savePBFile() { +void KickoffTimerPlugin::savePBFile() +{ ofstream myfile; myfile.open(savefile); @@ -248,7 +239,8 @@ void KickoffTimerPlugin::savePBFile() { myfile.close(); } -void KickoffTimerPlugin::loadPBFile() { +void KickoffTimerPlugin::loadPBFile() +{ ifstream myfile; myfile.open(savefile); if (!myfile.good()) diff --git a/KickoffTimerPlugin.h b/KickoffTimerPlugin.h index 47a723e..8427ad1 100644 --- a/KickoffTimerPlugin.h +++ b/KickoffTimerPlugin.h @@ -49,6 +49,6 @@ class KickoffTimerPlugin : public BakkesMod::Plugin::BakkesModPlugin virtual void loadPBFile(); virtual void SetHitTextWithTime(float time_hit); virtual void SetHitTextWithTimeAndText(float time_hit, string& message); - virtual void ResetAndDeleteFile(bool deleteFile); + virtual void ResetPersonalBests(); virtual void updateDecimalValue(); }; From 9a66d1c62cc3c1136fdb2fecc1e656ab78009e37 Mon Sep 17 00:00:00 2001 From: Andrew Thomas Date: Sun, 1 Sep 2019 13:58:21 -0500 Subject: [PATCH 4/4] Removed delete button per code review --- settings/kickofftimerplugin.set | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/settings/kickofftimerplugin.set b/settings/kickofftimerplugin.set index ba258ec..e20f8be 100644 --- a/settings/kickofftimerplugin.set +++ b/settings/kickofftimerplugin.set @@ -6,8 +6,6 @@ Kickoff timer plugin 0|Unload|plugin unload kickofftimerplugin 7 0|Reset Personal Best|kickofftimer_reset -7 -0|Reset Personal Best and Delete file|kickofftimer_resetAndDelete 9|Config Values 8 -5|How many decimal places to record time|kickofftimer_decimalPlaces|2|4 \ No newline at end of file +5|How many decimal places to record time|kickofftimer_decimalPlaces|2|4