From 23fb885e09e03226b7a966b0242707488c4f4fe9 Mon Sep 17 00:00:00 2001 From: Kenix3 Date: Tue, 9 Aug 2022 23:50:21 -0400 Subject: [PATCH] Console class is now a proper object oriented class. --- libultraship/libultraship/Console.cpp | 146 +++++++++++------- libultraship/libultraship/Console.h | 51 +++--- libultraship/libultraship/GameOverlay.cpp | 3 +- libultraship/libultraship/ImGuiImpl.cpp | 20 ++- .../include/spdlog/sinks/sohconsole_sink.h | 2 +- 5 files changed, 136 insertions(+), 86 deletions(-) diff --git a/libultraship/libultraship/Console.cpp b/libultraship/libultraship/Console.cpp index d93a4e500..5780453e7 100644 --- a/libultraship/libultraship/Console.cpp +++ b/libultraship/libultraship/Console.cpp @@ -16,7 +16,7 @@ namespace Ship { return usage; } - static bool HelpCommand(std::shared_ptr Console, const std::vector& args) { + bool Console::HelpCommand(std::shared_ptr Console, const std::vector& args) { SohImGui::console->SendInfoMessage("SoH Commands:"); for (const auto& cmd : SohImGui::console->Commands) { SohImGui::console->SendInfoMessage(" - " + cmd.first); @@ -24,12 +24,12 @@ namespace Ship { return CMD_SUCCESS; } - static bool ClearCommand(std::shared_ptr Console, const std::vector& args) { - SohImGui::console->Log[SohImGui::console->selected_channel].clear(); + bool Console::ClearCommand(std::shared_ptr Console, const std::vector& args) { + Console->ClearLogs(Console->GetCurrentChannel()); return CMD_SUCCESS; } - static bool BindCommand(std::shared_ptr Console, const std::vector& args) { + bool Console::BindCommand(std::shared_ptr Console, const std::vector& args) { if (args.size() > 2) { const ImGuiIO* io = &ImGui::GetIO();; for (size_t k = 0; k < std::size(io->KeysData); k++) { @@ -49,7 +49,7 @@ namespace Ship { return CMD_SUCCESS; } - static bool BindToggleCommand(std::shared_ptr Console, const std::vector& args) { + bool Console::BindToggleCommand(std::shared_ptr Console, const std::vector& args) { if (args.size() > 2) { const ImGuiIO* io = &ImGui::GetIO();; for (size_t k = 0; k < std::size(io->KeysData); k++) { @@ -66,14 +66,14 @@ namespace Ship { } void Console::Init() { - this->InputBuffer = new char[MAX_BUFFER_SIZE]; - strcpy(this->InputBuffer, ""); - this->FilterBuffer = new char[MAX_BUFFER_SIZE]; - strcpy(this->FilterBuffer, ""); - this->Commands["help"] = { HelpCommand, "Shows all the commands" }; - this->Commands["clear"] = { ClearCommand, "Clear the console history" }; - this->Commands["bind"] = { BindCommand, "Binds key to commands" }; - this->Commands["bind-toggle"] = { BindToggleCommand, "Bind key as a bool toggle" }; + this->inputBuffer = new char[MAX_BUFFER_SIZE]; + strcpy(this->inputBuffer, ""); + this->filterBuffer = new char[MAX_BUFFER_SIZE]; + strcpy(this->filterBuffer, ""); + AddCommand("help", { HelpCommand, "Shows all the commands" }); + AddCommand("help", { ClearCommand, "Clear the console history" }); + AddCommand("help", { BindCommand, "Binds key to commands" }); + AddCommand("help", { BindToggleCommand, "Bind key as a bool toggle" }); } void Console::Update() { @@ -103,7 +103,7 @@ namespace Ship { // SohImGui::ShowCursor(ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows | ImGuiHoveredFlags_RectOnly), SohImGui::Dialogues::dConsole); // Renders autocomplete window - if (this->OpenAutocomplete) { + if (this->openAutocomplete) { ImGui::SetNextWindowSize(ImVec2(350, std::min(static_cast(this->Autocomplete.size()), 3) * 20.f), ImGuiCond_Once); ImGui::SetNextWindowPos(ImVec2(pos.x + 8, pos.y + size.y - 1)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(3, 3)); @@ -118,16 +118,16 @@ namespace Ship { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); if (ImGui::Selectable(preview.c_str())) { - memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); - memcpy(this->InputBuffer, autocomplete.c_str(), sizeof(char) * autocomplete.size()); - this->OpenAutocomplete = false; + memset(this->inputBuffer, 0, MAX_BUFFER_SIZE); + memcpy(this->inputBuffer, autocomplete.c_str(), sizeof(char) * autocomplete.size()); + this->openAutocomplete = false; input_focus = true; } } ImGui::EndTable(); } if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { - this->OpenAutocomplete = false; + this->openAutocomplete = false; } ImGui::PopStyleColor(); ImGui::EndChild(); @@ -137,7 +137,7 @@ namespace Ship { if (ImGui::BeginPopupContextWindow("Context Menu")) { if (ImGui::MenuItem("Copy Text")) { - ImGui::SetClipboardText(this->Log[this->selected_channel][this->selectedId].text.c_str()); + ImGui::SetClipboardText(this->Log[this->currentChannel][this->selectedId].text.c_str()); this->selectedId = -1; } ImGui::EndPopup(); @@ -147,44 +147,44 @@ namespace Ship { } // Renders top bar filters - if (ImGui::Button("Clear")) this->Log[this->selected_channel].clear(); + if (ImGui::Button("Clear")) this->Log[this->currentChannel].clear(); if (CVar_GetS32("gSinkEnabled", 0)) { ImGui::SameLine(); ImGui::SetNextItemWidth(150); - if (ImGui::BeginCombo("##channel", this->selected_channel.c_str())) { - for (const auto& channel : log_channels) { - const bool is_selected = (channel == std::string(this->selected_channel)); + if (ImGui::BeginCombo("##channel", this->currentChannel.c_str())) { + for (const auto& channel : LogChannels) { + const bool is_selected = (channel == std::string(this->currentChannel)); if (ImGui::Selectable(channel.c_str(), is_selected)) - this->selected_channel = channel; + this->currentChannel = channel; if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } } else { - this->selected_channel = "Console"; + this->currentChannel = "Console"; } ImGui::SameLine(); ImGui::SetNextItemWidth(150); - if (this->selected_channel != "Console") { - if (ImGui::BeginCombo("##level", spdlog::level::to_string_view(this->level_filter).data())) { - for (const auto& priority_filter : priority_filters) { - const bool is_selected = priority_filter == this->level_filter; + if (this->currentChannel != "Console") { + if (ImGui::BeginCombo("##level", spdlog::level::to_string_view(this->levelFilter).data())) { + for (const auto& priority_filter : PriorityFilters) { + const bool is_selected = priority_filter == this->levelFilter; if (ImGui::Selectable(spdlog::level::to_string_view(priority_filter).data(), is_selected)) { - this->level_filter = priority_filter; + this->levelFilter = priority_filter; if (is_selected) ImGui::SetItemDefaultFocus(); } } ImGui::EndCombo(); } } else { - this->level_filter = spdlog::level::trace; + this->levelFilter = spdlog::level::trace; } ImGui::SameLine(); ImGui::PushItemWidth(-1); - if (ImGui::InputTextWithHint("##input", "Filter", this->FilterBuffer, MAX_BUFFER_SIZE))this->filter = std::string(this->FilterBuffer); + if (ImGui::InputTextWithHint("##input", "Filter", this->filterBuffer, MAX_BUFFER_SIZE))this->filter = std::string(this->filterBuffer); ImGui::PopItemWidth(); // Renders console history @@ -198,16 +198,16 @@ namespace Ship { if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow))) if (this->selectedId > 0)--this->selectedId; - const std::vector channel = this->Log[this->selected_channel]; + const std::vector channel = this->Log[this->currentChannel]; for (int i = 0; i < static_cast(channel.size()); i++) { ConsoleLine line = channel[i]; if (!this->filter.empty() && line.text.find(this->filter) == std::string::npos) continue; - if (this->level_filter > line.priority) continue; + if (this->levelFilter > line.priority) continue; std::string id = line.text + "##" + std::to_string(i); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); const bool is_selected = (this->selectedId == i) || std::find(this->selectedEntries.begin(), this->selectedEntries.end(), i) != this->selectedEntries.end(); - ImGui::PushStyleColor(ImGuiCol_Text, this->priority_colors[line.priority]); + ImGui::PushStyleColor(ImGuiCol_Text, this->PriorityColours[line.priority]); if (ImGui::Selectable(id.c_str(), is_selected)) { if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftCtrl)) && !is_selected) this->selectedEntries.push_back(i); @@ -225,25 +225,25 @@ namespace Ship { ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); - if (this->selected_channel == "Console") { + if (this->currentChannel == "Console") { // Renders input textfield constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; ImGui::PushItemWidth(-53); - if (ImGui::InputTextWithHint("##CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { + if (ImGui::InputTextWithHint("##CMDInput", ">", this->inputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { input_focus = true; - if (this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' ') - this->Dispatch(std::string(this->InputBuffer)); - memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); + if (this->inputBuffer[0] != '\0' && this->inputBuffer[0] != ' ') + this->Dispatch(std::string(this->inputBuffer)); + memset(this->inputBuffer, 0, MAX_BUFFER_SIZE); } - if (this->CMDHint != NULLSTR) { + if (this->cmdHint != NULLSTR) { if (ImGui::IsItemFocused()) { ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y + size.y)); ImGui::SameLine(); ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted(this->CMDHint.c_str()); + ImGui::TextUnformatted(this->cmdHint.c_str()); ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } @@ -251,9 +251,9 @@ namespace Ship { ImGui::SameLine(); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 50); - if (ImGui::Button("Submit") && !input_focus && this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' ') { - this->Dispatch(std::string(this->InputBuffer)); - memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); + if (ImGui::Button("Submit") && !input_focus && this->inputBuffer[0] != '\0' && this->inputBuffer[0] != ' ') { + this->Dispatch(std::string(this->inputBuffer)); + memset(this->inputBuffer, 0, MAX_BUFFER_SIZE); } ImGui::SetItemDefaultFocus(); @@ -264,7 +264,7 @@ namespace Ship { } void Console::Dispatch(const std::string& line) { - this->CMDHint = NULLSTR; + this->cmdHint = NULLSTR; this->History.push_back(line); SendInfoMessage("> " + line); const std::vector cmd_args = StringHelper::Split(line, " "); @@ -282,7 +282,7 @@ namespace Ship { int Console::CallbackStub(ImGuiInputTextCallbackData* data) { const auto instance = static_cast(data->UserData); const bool empty_history = instance->History.empty(); - const int history_index = instance->HistoryIndex; + const int history_index = instance->historyIndex; std::string history; switch (data->EventKey) { @@ -290,39 +290,39 @@ namespace Ship { instance->Autocomplete.clear(); for (auto& [cmd, entry] : instance->Commands) if (cmd.find(std::string(data->Buf)) != std::string::npos) instance->Autocomplete.push_back(cmd); - instance->OpenAutocomplete = !instance->Autocomplete.empty(); - instance->CMDHint = NULLSTR; + instance->openAutocomplete = !instance->Autocomplete.empty(); + instance->cmdHint = NULLSTR; break; case ImGuiKey_UpArrow: if (empty_history) break; - if (history_index < static_cast(instance->History.size()) - 1) instance->HistoryIndex += 1; + if (history_index < static_cast(instance->History.size()) - 1) instance->historyIndex += 1; data->DeleteChars(0, data->BufTextLen); - data->InsertChars(0, instance->History[instance->HistoryIndex].c_str()); - instance->CMDHint = NULLSTR; + data->InsertChars(0, instance->History[instance->historyIndex].c_str()); + instance->cmdHint = NULLSTR; break; case ImGuiKey_DownArrow: if (empty_history) break; - if (history_index > -1) instance->HistoryIndex -= 1; + if (history_index > -1) instance->historyIndex -= 1; data->DeleteChars(0, data->BufTextLen); if (history_index >= 0) data->InsertChars(0, instance->History[history_index].c_str()); - instance->CMDHint = NULLSTR; + instance->cmdHint = NULLSTR; break; case ImGuiKey_Escape: - instance->HistoryIndex = -1; + instance->historyIndex = -1; data->DeleteChars(0, data->BufTextLen); - instance->OpenAutocomplete = false; - instance->CMDHint = NULLSTR; + instance->openAutocomplete = false; + instance->cmdHint = NULLSTR; break; default: - instance->OpenAutocomplete = false; + instance->openAutocomplete = false; for (auto& [cmd, entry] : instance->Commands) { const std::vector cmd_args = StringHelper::Split(std::string(data->Buf), " "); if (data->BufTextLen > 2 && !cmd_args.empty() && cmd.find(cmd_args[0]) != std::string::npos) { - instance->CMDHint = cmd + " " + BuildUsage(entry); + instance->cmdHint = cmd + " " + BuildUsage(entry); break; } - instance->CMDHint = NULLSTR; + instance->cmdHint = NULLSTR; } } return 0; @@ -363,4 +363,30 @@ namespace Ship { void Console::SendErrorMessage(const std::string& str) { Append("Console", spdlog::level::err, str.c_str()); } + + void Console::ClearLogs(std::string channel) { + Log[channel].clear(); + } + + void Console::ClearLogs() { + for (auto [key, var] : Log) { + var.clear(); + } + } + + bool Console::HasCommand(const std::string& command) { + for (const auto& Command : Commands) { + if (Command.first == command) { + return true; + } + } + + return false; + } + + void Console::AddCommand(const std::string& command, CommandEntry entry) { + if (!HasCommand(command)) { + Commands[command] = entry; + } + } } \ No newline at end of file diff --git a/libultraship/libultraship/Console.h b/libultraship/libultraship/Console.h index e81964aee..f0b78aac9 100644 --- a/libultraship/libultraship/Console.h +++ b/libultraship/libultraship/Console.h @@ -43,13 +43,33 @@ namespace Ship { class Console : public std::enable_shared_from_this { private: + static int CallbackStub(ImGuiInputTextCallbackData* data); + static bool ClearCommand(std::shared_ptr Console, const std::vector& args); + static bool HelpCommand(std::shared_ptr Console, const std::vector& args); + static bool BindCommand(std::shared_ptr Console, const std::vector& args); + static bool BindToggleCommand(std::shared_ptr Console, const std::vector& args); + + bool opened = false; int selectedId = -1; + int historyIndex = -1; std::vector selectedEntries; std::string filter; - spdlog::level::level_enum level_filter = spdlog::level::trace; - const std::vector log_channels = { "Console", "Logs" }; - const std::vector priority_filters = { spdlog::level::off, spdlog::level::critical, spdlog::level::err, spdlog::level::warn, spdlog::level::info, spdlog::level::debug, spdlog::level::trace }; - const std::vector priority_colors = { + std::string currentChannel = "Console"; + bool openAutocomplete = false; + char* inputBuffer = nullptr; + char* filterBuffer = nullptr; + std::string cmdHint = NULLSTR; + spdlog::level::level_enum levelFilter = spdlog::level::trace; + + std::vector History; + std::vector Autocomplete; + std::map Bindings; + std::map BindingToggle; + std::map Commands; + std::map> Log; + const std::vector LogChannels = { "Console", "Logs" }; + const std::vector PriorityFilters = { spdlog::level::off, spdlog::level::critical, spdlog::level::err, spdlog::level::warn, spdlog::level::info, spdlog::level::debug, spdlog::level::trace }; + const std::vector PriorityColours = { ImVec4(0.8f, 0.8f, 0.8f, 1.0f), // TRACE ImVec4(0.9f, 0.9f, 0.9f, 1.0f), // DEBUG ImVec4(1.0f, 1.0f, 1.0f, 1.0f), // INFO @@ -62,28 +82,23 @@ namespace Ship { void Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, va_list args); public: - std::map Bindings; - std::map BindingToggle; - std::map> Log; - std::map Commands; - std::vector Autocomplete; - std::vector History; - std::string CMDHint = NULLSTR; - char* FilterBuffer = nullptr; - char* InputBuffer = nullptr; - bool OpenAutocomplete = false; - int HistoryIndex = -1; - bool opened = false; - std::string selected_channel = "Console"; + void ClearLogs(std::string channel); + void ClearLogs(); void Init(); void Update(); void Draw(); void Dispatch(const std::string& line); - static int CallbackStub(ImGuiInputTextCallbackData* data); void SendInfoMessage(const char* fmt, ...); void SendErrorMessage(const char* fmt, ...); void SendInfoMessage(const std::string& str); void SendErrorMessage(const std::string& str); void Append(const std::string& channel, spdlog::level::level_enum priority, const char* fmt, ...); + bool HasCommand(const std::string& command); + void AddCommand(const std::string& command, CommandEntry entry); + + std::string GetCurrentChannel() { return currentChannel; } + bool IsOpened() { return opened; } + void Close() { opened = false; } + void Open() { opened = true; } }; } \ No newline at end of file diff --git a/libultraship/libultraship/GameOverlay.cpp b/libultraship/libultraship/GameOverlay.cpp index 1a3a1e3bb..051669577 100644 --- a/libultraship/libultraship/GameOverlay.cpp +++ b/libultraship/libultraship/GameOverlay.cpp @@ -156,7 +156,8 @@ namespace Ship { this->CurrentFont = DefaultFont; } } - SohImGui::console->Commands["overlay"] = { OverlayCommand, "Draw an overlay using a cvar value" }; + + SohImGui::console->AddCommand("overlay", { OverlayCommand, "Draw an overlay using a cvar value" }); } void GameOverlay::DrawSettings() { diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index b76739e7a..cc16b071c 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -141,7 +141,11 @@ namespace SohImGui { Ship::RegisterHook(UpdateAudio); Ship::RegisterHook([] { gfx_get_current_rendering_api()->set_texture_filter((FilteringMode)CVar_GetS32("gTextureFilter", FILTER_THREE_POINT)); - SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0); + if (CVar_GetS32("gConsoleEnabled", 0)) { + console->Open(); + } else { + console->Close(); + } SohImGui::controller->Opened = CVar_GetS32("gControllerConfigurationEnabled", 0); UpdateAudio(); }); @@ -863,7 +867,7 @@ namespace SohImGui { if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && ImGui::IsKeyPressed(ImGuiKey_R, false)) { - console->Commands["reset"].handler(console, emptyArgs); + console->Dispatch("reset"); } #endif @@ -891,7 +895,7 @@ namespace SohImGui { "Ctrl+R" #endif )) { - console->Commands["reset"].handler(console, emptyArgs); + console->Dispatch("reset"); } ImGui::EndMenu(); } @@ -1638,7 +1642,7 @@ namespace SohImGui { CVar_SetS32("gEnableBetaQuest", betaQuestEnabled); CVar_SetS32("gBetaQuestWorld", betaQuestWorld); - console->Commands["reset"].handler(console, emptyArgs); + console->Dispatch("reset"); needs_save = true; } @@ -1695,7 +1699,11 @@ namespace SohImGui { bool currentValue = CVar_GetS32("gConsoleEnabled", 0); CVar_SetS32("gConsoleEnabled", !currentValue); needs_save = true; - console->opened = CVar_GetS32("gConsoleEnabled", 0); + if(CVar_GetS32("gConsoleEnabled", 0)){ + console->Open(); + } else { + console->Close(); + } } Tooltip("Enables the console window, allowing you to input commands, type help for some examples"); InsertPadding(); @@ -2240,7 +2248,7 @@ namespace SohImGui { } void BindCmd(const std::string& cmd, CommandEntry entry) { - console->Commands[cmd] = std::move(entry); + console->AddCommand(cmd, entry); } void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc, bool isEnabled, bool isHidden) { diff --git a/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h b/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h index 65e98610a..8a629aa1a 100644 --- a/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h +++ b/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h @@ -41,7 +41,7 @@ protected: } formatted.push_back('\0'); const char* msg_output = formatted.data(); - if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->opened) { + if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->IsOpened()) { SohImGui::console->Append("Logs", msg.level, "%s", msg_output); } }