New Time Splitter file/window, reverting GameplayStats back to unaltered.

This commit is contained in:
Caladius 2024-02-13 19:09:18 -05:00
parent 79eb74871b
commit 4db8de6ef5
9 changed files with 198 additions and 352 deletions

View File

@ -649,181 +649,6 @@ void DrawGameplayStatsOptionsTab() {
UIWidgets::PaddedEnhancementCheckbox("Show Debug Info", "gGameplayStats.ShowDebugInfo");
}
static std::string listItem;
static std::vector<std::string> splitItem;
static std::vector<std::string> splitTime;
static std::vector<std::string> splitStatus;
static uint32_t itemReference;
std::string status = "";
ImVec4 statusColor= COLOR_WHITE;
void GameplayStatsSplitSave(const char* saveType, int itemSplit, std::string timeSplit, std::string statusSplit) {
if (saveType == "New Item") {
std::string splitItemSave(CVarGetString("gTimeSplitter.CurrentItems", ""));
std::string splitTimeSave(CVarGetString("gTimeSplitter.CurrentTimes", ""));
std::string splitStatusSave(CVarGetString("gTimeSplitter.CurrentStatus", ""));
if (splitItemSave == "NULL") {
splitItemSave = std::to_string(itemSplit);
} else {
splitItemSave += std::to_string(itemSplit);
}
splitItemSave += ",";
CVarSetString("gTimeSplitter.CurrentItems", splitItemSave.c_str());
if (splitTimeSave == "NULL") {
splitTimeSave = timeSplit;
} else {
splitTimeSave += timeSplit;
}
splitTimeSave += ",";
CVarSetString("gTimeSplitter.CurrentTimes", splitTimeSave.c_str());
if (splitStatusSave == "NULL") {
splitStatusSave = statusSplit;
} else {
splitStatusSave += statusSplit;
}
splitStatusSave += ",";
CVarSetString("gTimeSplitter.CurrentStatus", splitStatusSave.c_str());
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
if (saveType == "Collect") {
// Times
std::string inputTimes(CVarGetString("gTimeSplitter.CurrentTimes", ""));
std::stringstream timeStream(inputTimes);
std::vector<std::string> timeTokens;
std::string timeToken;
while (std::getline(timeStream, timeToken, ',')) {
timeTokens.push_back(timeToken);
}
timeTokens[itemSplit] = timeSplit;
inputTimes = "";
for (size_t i = 0; i < timeTokens.size(); i++) {
if (i > 0) {
inputTimes += ",";
}
inputTimes += timeTokens[i];
}
CVarSetString("gTimeSplitter.CurrentTimes", inputTimes.c_str());
// Status
std::string inputStatus(CVarGetString("gTimeSplitter.CurrentStatus", ""));
std::stringstream statusStream(inputStatus);
std::vector<std::string> statusTokens;
std::string statusToken;
while (std::getline(statusStream, statusToken, ',')) {
statusTokens.push_back(statusToken);
}
statusTokens[itemSplit] = statusSplit;
inputStatus = "";
for (size_t v = 0; v < statusTokens.size(); v++) {
if (v > 0) {
inputStatus += ",";
}
inputStatus += statusTokens[v];
}
CVarSetString("gTimeSplitter.CurrentStatus", inputStatus.c_str());
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
if (saveType == "Reset") {
CVarSetString("gTimeSplitter.CurrentItems", "NULL");
CVarSetString("gTimeSplitter.CurrentTimes", "NULL");
CVarSetString("gTimeSplitter.CurrentStatus", "NULL");
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
}
void GameplayStatsSplitsHandler(GetItemEntry itemEntry) {
if (itemEntry.modIndex != 0) {
return;
}
uint32_t loopCounter = 0;
for (auto &str : splitItem) {
const char* itemRef = splitEntries[itemEntry.itemId];
if (itemRef == splitItem[loopCounter]) {
uint32_t num = GAMEPLAYSTAT_TOTAL_TIME;
std::string temp = formatTimestampGameplayStat(num);
const char* itemTime = temp.c_str();
splitTime[loopCounter] = itemTime;
splitStatus[loopCounter] = "1";
GameplayStatsSplitSave("Collect", loopCounter, itemTime, "1");
}
loopCounter++;
}
}
void DrawGameplayStatsSplitsTab() {
uint32_t loopCounter = 0;
ImGui::BeginTable("Splits", 2);
for (auto &str : splitItem) {
std::string itemEntry = splitItem[loopCounter];
uint32_t num = GAMEPLAYSTAT_TOTAL_TIME;
std::string temp = formatTimestampGameplayStat(num);
//std::string str = std::to_string(temp);
const char* itemTime = temp.c_str();
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_WHITE, itemEntry.c_str());
ImGui::TableNextColumn();
if (splitStatus[loopCounter] == "0") {
ImGui::TextColored(COLOR_WHITE, itemTime);
} else {
ImGui::TextColored(COLOR_GREEN, splitTime[loopCounter].c_str());
}
loopCounter++;
}
ImGui::EndTable();
}
void DrawGameplayStatsSplitsOptionsTab() {
itemReference = SplitItemList(CVarGetInteger("gSelectedSplitItem", 0));
if (UIWidgets::EnhancementCombobox("gSelectedSplitItem", splitEntries, 0)) {
itemReference = SplitItemList(CVarGetInteger("gSelectedSplitItem", 0));
}
if (ImGui::Button("Add Item")) {
splitItem.push_back(splitEntries[itemReference]);
splitTime.push_back("");
splitStatus.push_back("0");
status = (splitEntries[itemReference]) + std::string(" Added to List");
statusColor = COLOR_GREEN;
GameplayStatsSplitSave("New Item", itemReference, "", "0");
}
ImGui::SameLine(0);
if (ImGui::Button("Reset List")) {
splitItem.clear();
splitTime.clear();
status = "List Cleared";
statusColor = COLOR_RED;
GameplayStatsSplitSave("Reset", 0, "", "");
}
ImGui::TextColored(statusColor, status.c_str());
}
void DrawGameplayStatsTimeSplitterTab() {
if (ImGui::BeginTabBar("Time Splitter")) {
if (ImGui::BeginTabItem("Splits")) {
DrawGameplayStatsSplitsTab();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Split Options")) {
DrawGameplayStatsSplitsOptionsTab();
ImGui::EndTabItem();
}
}
ImGui::EndTabBar();
}
void GameplayStatsWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(480, 550), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Gameplay Stats", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
@ -850,10 +675,6 @@ void GameplayStatsWindow::DrawElement() {
DrawGameplayStatsOptionsTab();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Time Splitter")) {
DrawGameplayStatsTimeSplitterTab();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
@ -1069,10 +890,4 @@ void GameplayStatsWindow::InitElement() {
SaveManager::Instance->AddSaveFunction("entrances", 1, SaveStats, false, SECTION_ID_STATS);
SaveManager::Instance->AddSaveFunction("scenes", 1, SaveStats, false, SECTION_ID_STATS);
SaveManager::Instance->AddInitFunction(InitStats);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>([](GetItemEntry itemEntry) {
// to do: call GameplayStatsSplitsHandler() here
GameplayStatsSplitsHandler(itemEntry);
});
}

View File

@ -155,167 +155,3 @@ typedef enum {
COUNT_MAX
} GameplayStatCount;
typedef enum {
SPLIT_STICK,
SPLIT_NUT,
SPLIT_BOMB,
SPLIT_BOW,
SPLIT_ARROW_FIRE,
SPLIT_DINS_FIRE,
SPLIT_SLINGSHOT,
SPLIT_OCARINA_FAIRY,
SPLIT_OCARINA_TIME,
SPLIT_BOMBCHU,
SPLIT_HOOKSHOT,
SPLIT_LONGSHOT,
SPLIT_ARROW_ICE,
SPLIT_FARORES_WIND,
SPLIT_BOOMERANG,
SPLIT_LENS,
SPLIT_BEAN,
SPLIT_HAMMER,
SPLIT_ARROW_LIGHT,
SPLIT_NAYRUS_LOVE,
SPLIT_BOTTLE,
SPLIT_POTION_RED,
SPLIT_POTION_GREEN,
SPLIT_POTION_BLUE,
SPLIT_FAIRY,
SPLIT_FISH,
SPLIT_MILK_BOTTLE,
SPLIT_LETTER_RUTO,
SPLIT_BLUE_FIRE,
SPLIT_BUG,
SPLIT_BIG_POE,
SPLIT_MILK_HALF,
SPLIT_POE,
SPLIT_WEIRD_EGG,
SPLIT_CHICKEN,
SPLIT_LETTER_ZELDA,
SPLIT_MASK_KEATON,
SPLIT_MASK_SKULL,
SPLIT_MASK_SPOOKY,
SPLIT_MASK_BUNNY,
SPLIT_MASK_GORON,
SPLIT_MASK_ZORA,
SPLIT_MASK_GERUDO,
SPLIT_MASK_TRUTH,
SPLIT_SOLD_OUT,
SPLIT_POCKET_EGG,
SPLIT_POCKET_CUCCO,
SPLIT_COJIRO,
SPLIT_ODD_MUSHROOM,
SPLIT_ODD_POTION,
SPLIT_SAW,
SPLIT_SWORD_BROKEN,
SPLIT_PRESCRIPTION,
SPLIT_FROG,
SPLIT_EYEDROPS,
SPLIT_CLAIM_CHECK,
SPLIT_BOW_ARROW_FIRE,
SPLIT_BOW_ARROW_ICE,
SPLIT_BOW_ARROW_LIGHT,
SPLIT_SWORD_KOKIRI,
SPLIT_SWORD_MASTER,
SPLIT_SWORD_BGS,
SPLIT_SHIELD_DEKU,
SPLIT_SHIELD_HYLIAN,
SPLIT_SHIELD_MIRROR,
SPLIT_TUNIC_KOKIRI,
SPLIT_TUNIC_GORON,
SPLIT_TUNIC_ZORA,
SPLIT_BOOTS_KOKIRI,
SPLIT_BOOTS_IRON,
SPLIT_BOOTS_HOVER,
SPLIT_BULLET_BAG_30,
SPLIT_BULLET_BAG_40,
SPLIT_BULLET_BAG_50,
SPLIT_QUIVER_30,
SPLIT_QUIVER_40,
SPLIT_QUIVER_50,
SPLIT_BOMB_BAG_20,
SPLIT_BOMB_BAG_30,
SPLIT_BOMB_BAG_40,
SPLIT_BRACELET,
SPLIT_GAUNTLETS_SILVER,
SPLIT_GAUNTLETS_GOLD,
SPLIT_SCALE_SILVER,
SPLIT_SCALE_GOLDEN,
SPLIT_SWORD_KNIFE,
SPLIT_WALLET_ADULT,
SPLIT_WALLET_GIANT,
SPLIT_SEEDS,
SPLIT_FISHING_POLE,
SPLIT_SONG_MINUET,
SPLIT_SONG_BOLERO,
SPLIT_SONG_SERENADE,
SPLIT_SONG_REQUIEM,
SPLIT_SONG_NOCTURNE,
SPLIT_SONG_PRELUDE,
SPLIT_SONG_LULLABY,
SPLIT_SONG_EPONA,
SPLIT_SONG_SARIA,
SPLIT_SONG_SUN,
SPLIT_SONG_TIME,
SPLIT_SONG_STORMS,
SPLIT_MEDALLION_FOREST,
SPLIT_MEDALLION_FIRE,
SPLIT_MEDALLION_WATER,
SPLIT_MEDALLION_SPIRIT,
SPLIT_MEDALLION_SHADOW,
SPLIT_MEDALLION_LIGHT,
SPLIT_KOKIRI_EMERALD,
SPLIT_GORON_RUBY,
SPLIT_ZORA_SAPPHIRE,
SPLIT_STONE_OF_AGONY,
SPLIT_GERUDO_CARD,
SPLIT_SKULL_TOKEN,
SPLIT_HEART_CONTAINER,
SPLIT_HEART_PIECE,
SPLIT_KEY_BOSS,
SPLIT_COMPASS,
SPLIT_DUNGEON_MAP,
SPLIT_KEY_SMALL,
SPLIT_MAGIC_SMALL,
SPLIT_MAGIC_LARGE,
SPLIT_HEART_PIECE_2,
SPLIT_SINGLE_MAGIC,
SPLIT_DOUBLE_MAGIC,
SPLIT_DOUBLE_DEFENSE,
SPLIT_INVALID_4,
SPLIT_INVALID_5,
SPLIT_INVALID_6,
SPLIT_INVALID_7,
SPLIT_MILK,
SPLIT_HEART,
SPLIT_RUPEE_GREEN,
SPLIT_RUPEE_BLUE,
SPLIT_RUPEE_RED,
SPLIT_RUPEE_PURPLE,
SPLIT_RUPEE_GOLD,
SPLIT_INVALID_8,
SPLIT_STICKS_5,
SPLIT_STICKS_10,
SPLIT_NUTS_5,
SPLIT_NUTS_10,
SPLIT_BOMBS_5,
SPLIT_BOMBS_10,
SPLIT_BOMBS_20,
SPLIT_BOMBS_30,
SPLIT_ARROWS_SMALL,
SPLIT_ARROWS_MEDIUM,
SPLIT_ARROWS_LARGE,
SPLIT_SEEDS_30,
SPLIT_BOMBCHUS_5,
SPLIT_BOMBCHUS_20,
SPLIT_STICK_UPGRADE_20,
SPLIT_STICK_UPGRADE_30,
SPLIT_NUT_UPGRADE_30,
SPLIT_NUT_UPGRADE_40,
} SplitItemList;
typedef enum {
COLLECTED,
SKIPPED,
} SplitEvent;

View File

@ -0,0 +1,161 @@
#include "TimeSplits.h"
#include "soh/UIWidgets.hpp"
#include "soh/Enhancements/randomizer/3drando/item_list.hpp"
#include "soh/Enhancements/gameplaystats.h"
#include "soh/SaveManager.h"
#include "soh/util.h"
#include <vector>
#include "soh/OTRGlobals.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
extern "C" {
extern SaveContext gSaveContext;
}
// ImVec4 Colors
#define COLOR_WHITE ImVec4(1.00f, 1.00f, 1.00f, 1.00f)
#define COLOR_RED ImVec4(1.00f, 0.00f, 0.00f, 1.00f)
#define COLOR_GREEN ImVec4(0.10f, 1.00f, 0.10f, 1.00f)
#define COLOR_BLUE ImVec4(0.00f, 0.33f, 1.00f, 1.00f)
#define COLOR_PURPLE ImVec4(0.54f, 0.19f, 0.89f, 1.00f)
#define COLOR_YELLOW ImVec4(1.00f, 1.00f, 0.00f, 1.00f)
#define COLOR_ORANGE ImVec4(1.00f, 0.67f, 0.11f, 1.00f)
#define COLOR_LIGHT_BLUE ImVec4(0.00f, 0.88f, 1.00f, 1.00f)
#define COLOR_GREY ImVec4(0.78f, 0.78f, 0.78f, 1.00f)
static std::vector<int> splitItem;
static std::vector<std::string> splitTime;
static std::vector<int> splitStatus;
static uint32_t itemReference = ITEM_STICK;
static std::string status = "";
static ImVec4 statusColor = COLOR_WHITE;
std::time_t convertedTime;
const char* itemTime;
std::string formatTimestampTimeSplit(uint32_t value) {
uint32_t sec = value / 10;
uint32_t hh = sec / 3600;
uint32_t mm = (sec - hh * 3600) / 60;
uint32_t ss = sec - hh * 3600 - mm * 60;
uint32_t ds = value % 10;
return fmt::format("{}:{:0>2}:{:0>2}.{}", hh, mm, ss, ds);
}
void TimeSplitTimeHandler() {
uint32_t num = GAMEPLAYSTAT_TOTAL_TIME;
std::string temp = formatTimestampTimeSplit(num);
itemTime = temp.c_str();
}
void TimeSplitSplitsHandler(GetItemEntry itemEntry) {
if (itemEntry.modIndex != 0) {
return;
}
uint32_t loopCounter = 0;
for (auto& str : splitItem) {
uint32_t num = GAMEPLAYSTAT_TOTAL_TIME;
std::string temp = formatTimestampTimeSplit(num);
const char* timeValue = temp.c_str();
if (itemEntry.itemId == splitItem[loopCounter]) {
splitTime[loopCounter] = timeValue;
splitStatus[loopCounter] = 1;
}
loopCounter++;
}
}
void DrawTimeSplitSplits(){
uint32_t loopCounter = 0;
ImGui::BeginTable("Splits", 4);
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_LIGHT_BLUE, "Items");
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_LIGHT_BLUE, "Current Times");
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_LIGHT_BLUE, "+/-");
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_LIGHT_BLUE, "Previous Best");
for (auto& str : splitItem) {
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_WHITE, SohUtils::itemNames[splitItem[loopCounter]].c_str());
ImGui::TableNextColumn();
if (splitStatus[loopCounter] == 0) {
uint32_t num = GAMEPLAYSTAT_TOTAL_TIME;
std::string temp = formatTimestampTimeSplit(num);
itemTime = temp.c_str();
//TimeSplitTimeHandler();
ImGui::TextColored(COLOR_WHITE, itemTime);
} else {
ImGui::TextColored(COLOR_GREEN, splitTime[loopCounter].c_str());
}
ImGui::TableNextColumn();
// to-do: split difference +/- with colored indicators
ImGui::TextColored(COLOR_WHITE, "Not Supported");
ImGui::TableNextColumn();
ImGui::Text("0:00:00.0");
loopCounter++;
}
ImGui::EndTable();
}
void DrawTimeSplitOptions() {
if (ImGui::BeginCombo("Item List", SohUtils::itemNames[itemReference].c_str())) {
for (int i = 0; i < SohUtils::itemNames.size(); i++) {
if (ImGui::Selectable(SohUtils::itemNames[i].c_str())) {
itemReference = i;
}
}
ImGui::EndCombo();
}
if (ImGui::Button("Add Item")) {
splitItem.push_back(itemReference);
splitTime.push_back("");
splitStatus.push_back(0);
std::string itemEntry = SohUtils::itemNames[itemReference];
status = itemEntry + std::string(" Added to List");
statusColor = COLOR_GREEN;
}
ImGui::SameLine(0);
if (ImGui::Button("Reset List")) {
splitItem.clear();
splitTime.clear();
splitStatus.clear();
status = "List has been reset";
statusColor = COLOR_RED;
}
ImGui::SameLine(0);
if (ImGui::Button("Load List")) {
}
ImGui::TextColored(statusColor, status.c_str());
UIWidgets::PaddedSeparator();
}
void TimeSplitWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Time Splitter Window", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::End();
return;
}
if (ImGui::CollapsingHeader("Time Splitter")) {
DrawTimeSplitOptions();
}
DrawTimeSplitSplits();
ImGui::End();
}
void TimeSplitWindow::InitElement() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>([](GetItemEntry itemEntry) {
TimeSplitSplitsHandler(itemEntry);
});
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <libultraship/libultraship.h>
#ifdef __cplusplus
class TimeSplitWindow : public LUS::GuiWindow {
public:
using GuiWindow::GuiWindow;
void InitElement() override;
void DrawElement() override;
void UpdateElement() override{};
};
#endif

View File

@ -130,6 +130,8 @@ namespace SohGui {
std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
std::shared_ptr<RandomizerSettingsWindow> mRandomizerSettingsWindow;
std::shared_ptr<TimeSplitWindow> mTimeSplitWindow;
std::shared_ptr<AdvancedResolutionSettings::AdvancedResolutionSettingsWindow> mAdvancedResolutionSettingsWindow;
void SetupGuiElements() {
@ -191,6 +193,9 @@ namespace SohGui {
gui->AddGuiWindow(mRandomizerSettingsWindow);
mAdvancedResolutionSettingsWindow = std::make_shared<AdvancedResolutionSettings::AdvancedResolutionSettingsWindow>("gAdvancedResolutionEditorEnabled", "Advanced Resolution Settings");
gui->AddGuiWindow(mAdvancedResolutionSettingsWindow);
mTimeSplitWindow = std::make_shared<TimeSplitWindow>("gTimeSplitEnabled", "Time Splits");
gui->AddGuiWindow(mTimeSplitWindow);
}
void Destroy() {
@ -213,5 +218,6 @@ namespace SohGui {
mStatsWindow = nullptr;
mConsoleWindow = nullptr;
mSohMenuBar = nullptr;
mTimeSplitWindow = nullptr;
}
}

View File

@ -22,6 +22,7 @@
#include "Enhancements/randomizer/randomizer_entrance_tracker.h"
#include "Enhancements/randomizer/randomizer_item_tracker.h"
#include "Enhancements/randomizer/randomizer_settings_window.h"
#include "Enhancements/timesplits/TimeSplits.h"
#ifdef __cplusplus
extern "C" {

View File

@ -34,6 +34,8 @@
#include "Enhancements/randomizer/randomizer_settings_window.h"
#include "Enhancements/resolution-editor/ResolutionEditor.h"
#include "Enhancements/timesplits/TimeSplits.h"
extern bool ToggleAltAssetsAtEndOfFrame;
extern bool isBetaQuestEnabled;
@ -533,6 +535,7 @@ void DrawSettingsMenu() {
extern std::shared_ptr<AudioEditor> mAudioEditorWindow;
extern std::shared_ptr<CosmeticsEditorWindow> mCosmeticsEditorWindow;
extern std::shared_ptr<GameplayStatsWindow> mGameplayStatsWindow;
extern std::shared_ptr<TimeSplitWindow> mTimeSplitWindow;
void DrawEnhancementsMenu() {
if (ImGui::BeginMenu("Enhancements"))
@ -1371,6 +1374,12 @@ void DrawEnhancementsMenu() {
mGameplayStatsWindow->ToggleVisibility();
}
}
if (mTimeSplitWindow) {
if (ImGui::Button(GetWindowButtonText("Time Splits", CVarGetInteger("gTimeSplitEnabled", 0)).c_str(), ImVec2(-1.0f, 0.0f))) {
mTimeSplitWindow->ToggleVisibility();
}
}
ImGui::PopStyleVar(3);
ImGui::PopStyleColor(1);

View File

@ -117,7 +117,7 @@ std::vector<std::string> sceneNames = {
"Treasure Chest Room",
};
std::vector<std::string> itemNames = {
std::vector<std::string> SohUtils::itemNames = {
"Deku Stick",
"Deku Nut",
"Bomb",

View File

@ -1,8 +1,11 @@
#pragma once
#include <string>
#include <stdint.h>
#include <vector>
namespace SohUtils {
extern std::vector<std::string> itemNames;
const std::string& GetSceneName(int32_t scene);
const std::string& GetItemName(int32_t item);