Console window progress
This commit is contained in:
parent
bedc3c94f8
commit
bc52202b01
2
deps/imgui
vendored
2
deps/imgui
vendored
@ -1 +1 @@
|
|||||||
Subproject commit f791ff33702d55603d182b586a2850418ec49e3d
|
Subproject commit e55dce841b4a5a738ae41745b534248596df7f5e
|
@ -31,7 +31,7 @@ namespace console
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
std::getline(std::cin, cmd);
|
std::getline(std::cin, cmd);
|
||||||
command::execute(cmd.data(), false);
|
game_console::add(cmd.data(), false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ namespace game_console
|
|||||||
matches.clear();
|
matches.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(const std::string& data)
|
void print(const std::string& data, bool print_ = true)
|
||||||
{
|
{
|
||||||
if (con.visible_line_count > 0 && con.display_line_offset == (con.output.size() - con.visible_line_count))
|
if (con.visible_line_count > 0 && con.display_line_offset == (con.output.size() - con.visible_line_count))
|
||||||
{
|
{
|
||||||
@ -78,7 +78,10 @@ namespace game_console
|
|||||||
|
|
||||||
con.output.push_back(data);
|
con.output.push_back(data);
|
||||||
|
|
||||||
printf("%s\n", data.data());
|
if (print_)
|
||||||
|
{
|
||||||
|
printf("%s\n", data.data());
|
||||||
|
}
|
||||||
|
|
||||||
if (con.output.size() > 1024)
|
if (con.output.size() > 1024)
|
||||||
{
|
{
|
||||||
@ -182,50 +185,6 @@ namespace game_console
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void find_matches(std::string input, std::vector<std::string>& suggestions, const bool exact)
|
|
||||||
{
|
|
||||||
input = utils::string::to_lower(input);
|
|
||||||
|
|
||||||
for (const auto& dvar : dvars::dvar_list)
|
|
||||||
{
|
|
||||||
auto name = utils::string::to_lower(dvar);
|
|
||||||
if (match_compare(input, name, exact))
|
|
||||||
{
|
|
||||||
suggestions.push_back(dvar);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exact && suggestions.size() > 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (suggestions.size() == 0 && game::Dvar_FindVar(input.data()))
|
|
||||||
{
|
|
||||||
suggestions.push_back(input.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
game::cmd_function_s* cmd = (*game::cmd_functions);
|
|
||||||
while (cmd)
|
|
||||||
{
|
|
||||||
if (cmd->name)
|
|
||||||
{
|
|
||||||
std::string name = utils::string::to_lower(cmd->name);
|
|
||||||
|
|
||||||
if (match_compare(input, name, exact))
|
|
||||||
{
|
|
||||||
suggestions.push_back(cmd->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exact && suggestions.size() > 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmd = cmd->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_input()
|
void draw_input()
|
||||||
{
|
{
|
||||||
con.globals.font_height = static_cast<float>(console_font->pixelHeight);
|
con.globals.font_height = static_cast<float>(console_font->pixelHeight);
|
||||||
@ -534,21 +493,16 @@ namespace game_console
|
|||||||
|
|
||||||
void execute(const char* cmd)
|
void execute(const char* cmd)
|
||||||
{
|
{
|
||||||
const auto sv_running = game::Dvar_FindVar("sv_running")->current.enabled;
|
|
||||||
|
|
||||||
if (sv_running)
|
|
||||||
{
|
|
||||||
std::string command = cmd;
|
|
||||||
|
|
||||||
scheduler::once([command]()
|
|
||||||
{
|
|
||||||
scripting::notify(*game::levelEntityId, "console_command", {command});
|
|
||||||
}, scheduler::pipeline::server);
|
|
||||||
}
|
|
||||||
|
|
||||||
game::Cbuf_AddText(0, utils::string::va("%s \n", cmd));
|
game::Cbuf_AddText(0, utils::string::va("%s \n", cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add(const std::string& cmd, bool print_)
|
||||||
|
{
|
||||||
|
print(cmd, print_);
|
||||||
|
history.push_front(cmd);
|
||||||
|
game::Cbuf_AddText(0, utils::string::va("%s \n", cmd.data()));
|
||||||
|
}
|
||||||
|
|
||||||
bool console_key_event(const int localClientNum, const int key, const int down)
|
bool console_key_event(const int localClientNum, const int key, const int down)
|
||||||
{
|
{
|
||||||
if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE)
|
if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE)
|
||||||
@ -678,6 +632,69 @@ namespace game_console
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void find_matches(std::string input, std::vector<std::string>& suggestions, const bool exact)
|
||||||
|
{
|
||||||
|
input = utils::string::to_lower(input);
|
||||||
|
|
||||||
|
for (const auto& dvar : dvars::dvar_list)
|
||||||
|
{
|
||||||
|
auto name = utils::string::to_lower(dvar);
|
||||||
|
if (match_compare(input, name, exact))
|
||||||
|
{
|
||||||
|
suggestions.push_back(dvar);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exact && suggestions.size() > 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suggestions.size() == 0 && game::Dvar_FindVar(input.data()))
|
||||||
|
{
|
||||||
|
suggestions.push_back(input.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
game::cmd_function_s* cmd = (*game::cmd_functions);
|
||||||
|
while (cmd)
|
||||||
|
{
|
||||||
|
if (cmd->name)
|
||||||
|
{
|
||||||
|
std::string name = utils::string::to_lower(cmd->name);
|
||||||
|
|
||||||
|
if (match_compare(input, name, exact))
|
||||||
|
{
|
||||||
|
suggestions.push_back(cmd->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exact && suggestions.size() > 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd = cmd->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<std::string>& get_output()
|
||||||
|
{
|
||||||
|
return con.output;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<std::string>& get_history()
|
||||||
|
{
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_console()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
con.line_count = 0;
|
||||||
|
con.output.clear();
|
||||||
|
history_index = -1;
|
||||||
|
history.clear();
|
||||||
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -699,14 +716,7 @@ namespace game_console
|
|||||||
strncpy_s(con.globals.auto_complete_choice, "", 64);
|
strncpy_s(con.globals.auto_complete_choice, "", 64);
|
||||||
|
|
||||||
// add clear command
|
// add clear command
|
||||||
command::add("clear", [&]()
|
command::add("clear", clear_console);
|
||||||
{
|
|
||||||
clear();
|
|
||||||
con.line_count = 0;
|
|
||||||
con.output.clear();
|
|
||||||
history_index = -1;
|
|
||||||
history.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
// add our dvars
|
// add our dvars
|
||||||
dvars::con_inputBoxColor = dvars::register_vec4(
|
dvars::con_inputBoxColor = dvars::register_vec4(
|
||||||
|
@ -16,5 +16,11 @@ namespace game_console
|
|||||||
bool console_char_event(int local_client_num, int key);
|
bool console_char_event(int local_client_num, int key);
|
||||||
bool console_key_event(int local_client_num, int key, int down);
|
bool console_key_event(int local_client_num, int key, int down);
|
||||||
|
|
||||||
|
void find_matches(std::string input, std::vector<std::string>& suggestions, const bool exact);
|
||||||
void execute(const char* cmd);
|
void execute(const char* cmd);
|
||||||
|
void clear_console();
|
||||||
|
void add(const std::string& cmd, bool print_ = true);
|
||||||
|
|
||||||
|
std::deque<std::string>& get_output();
|
||||||
|
std::deque<std::string>& get_history();
|
||||||
}
|
}
|
@ -113,12 +113,15 @@ namespace gui
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ImGui::ShowDemoWindow();
|
||||||
|
|
||||||
if (ImGui::BeginMainMenuBar())
|
if (ImGui::BeginMainMenuBar())
|
||||||
{
|
{
|
||||||
if (ImGui::BeginMenu("Windows"))
|
if (ImGui::BeginMenu("Windows"))
|
||||||
{
|
{
|
||||||
ImGui::Checkbox("Asset list", &enabled_menus["asset_list"]);
|
ImGui::Checkbox("Asset list", &enabled_menus["asset_list"]);
|
||||||
ImGui::Checkbox("Entity list", &enabled_menus["entity_list"]);
|
ImGui::Checkbox("Entity list", &enabled_menus["entity_list"]);
|
||||||
|
ImGui::Checkbox("Console", &enabled_menus["console"]);
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,9 @@ namespace asset_list
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
bool shown_assets[game::XAssetType::ASSET_TYPE_COUNT];
|
||||||
|
std::string filter_buffer{};
|
||||||
|
|
||||||
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool includeOverride)
|
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool includeOverride)
|
||||||
{
|
{
|
||||||
game::DB_EnumXAssets_Internal(type, static_cast<void(*)(game::XAssetHeader, void*)>([](game::XAssetHeader header, void* data)
|
game::DB_EnumXAssets_Internal(type, static_cast<void(*)(game::XAssetHeader, void*)>([](game::XAssetHeader header, void* data)
|
||||||
@ -31,19 +34,16 @@ namespace asset_list
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool shown_assets[game::XAssetType::ASSET_TYPE_COUNT];
|
|
||||||
|
|
||||||
{
|
{
|
||||||
ImGui::Begin("Asset list", &gui::enabled_menus["asset_list"]);
|
ImGui::Begin("Asset list", &gui::enabled_menus["asset_list"]);
|
||||||
|
|
||||||
static char filter[0x200]{};
|
ImGui::InputText("asset type", &filter_buffer);
|
||||||
ImGui::InputText("asset type", filter, IM_ARRAYSIZE(filter));
|
|
||||||
for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
|
for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
|
||||||
{
|
{
|
||||||
const auto name = game::g_assetNames[i];
|
const auto name = game::g_assetNames[i];
|
||||||
const auto type = static_cast<game::XAssetType>(i);
|
const auto type = static_cast<game::XAssetType>(i);
|
||||||
|
|
||||||
if (strstr(name, filter))
|
if (strstr(name, filter_buffer.data()))
|
||||||
{
|
{
|
||||||
ImGui::Checkbox(name, &shown_assets[type]);
|
ImGui::Checkbox(name, &shown_assets[type]);
|
||||||
}
|
}
|
||||||
|
192
src/client/component/gui_console.cpp
Normal file
192
src/client/component/gui_console.cpp
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
#include "command.hpp"
|
||||||
|
#include "game_console.hpp"
|
||||||
|
#include "gui.hpp"
|
||||||
|
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/concurrency.hpp>
|
||||||
|
|
||||||
|
namespace gui_console
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool auto_scroll = true;
|
||||||
|
int history_index = -1;
|
||||||
|
std::string input{};
|
||||||
|
std::string filter{};
|
||||||
|
std::vector<std::string> matches{};
|
||||||
|
|
||||||
|
int input_text_edit(ImGuiInputTextCallbackData* data)
|
||||||
|
{
|
||||||
|
switch (data->EventFlag)
|
||||||
|
{
|
||||||
|
case ImGuiInputTextFlags_CallbackCompletion:
|
||||||
|
{
|
||||||
|
matches.clear();
|
||||||
|
const std::string text = data->Buf;
|
||||||
|
|
||||||
|
if (text.find(" ") != std::string::npos)
|
||||||
|
{
|
||||||
|
game_console::find_matches(text.substr(0, text.find(" ")), matches, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
game_console::find_matches(text, matches, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches.size() == 1)
|
||||||
|
{
|
||||||
|
const auto match = matches[0].data();
|
||||||
|
data->DeleteChars(0, data->BufTextLen);
|
||||||
|
data->InsertChars(0, match, match + strlen(match));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ImGuiInputTextFlags_CallbackHistory:
|
||||||
|
{
|
||||||
|
const auto history = game_console::get_history();
|
||||||
|
|
||||||
|
if (data->EventKey == ImGuiKey_UpArrow)
|
||||||
|
{
|
||||||
|
if (++history_index >= history.size())
|
||||||
|
{
|
||||||
|
history_index = static_cast<int>(history.size()) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->DeleteChars(0, data->BufTextLen);
|
||||||
|
|
||||||
|
if (history_index != -1)
|
||||||
|
{
|
||||||
|
const auto text = history.at(history_index).data();
|
||||||
|
data->InsertChars(0, text, text + strlen(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (data->EventKey == ImGuiKey_DownArrow)
|
||||||
|
{
|
||||||
|
if (--history_index < -1)
|
||||||
|
{
|
||||||
|
history_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->DeleteChars(0, data->BufTextLen);
|
||||||
|
|
||||||
|
if (history_index != -1)
|
||||||
|
{
|
||||||
|
const auto text = history.at(history_index).data();
|
||||||
|
data->InsertChars(0, text, text + strlen(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_filtered_text()
|
||||||
|
{
|
||||||
|
std::string text{};
|
||||||
|
|
||||||
|
const auto history = game_console::get_output();
|
||||||
|
for (const auto& line : history)
|
||||||
|
{
|
||||||
|
if (strstr(line.data(), filter.data()))
|
||||||
|
{
|
||||||
|
text.append(line.data());
|
||||||
|
text.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text[text.size() - 1] == '\n')
|
||||||
|
{
|
||||||
|
text.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_frame()
|
||||||
|
{
|
||||||
|
auto* open = &gui::enabled_menus["console"];
|
||||||
|
if (!*open)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto filtered_text = get_filtered_text();
|
||||||
|
static auto input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion |
|
||||||
|
ImGuiInputTextFlags_CallbackHistory;
|
||||||
|
|
||||||
|
ImGui::Begin("Console", open);
|
||||||
|
|
||||||
|
if (ImGui::BeginPopup("Options"))
|
||||||
|
{
|
||||||
|
ImGui::Checkbox("Auto-scroll", &auto_scroll);
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button("Clear"))
|
||||||
|
{
|
||||||
|
game_console::clear_console();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::Button("Copy"))
|
||||||
|
{
|
||||||
|
utils::string::set_clipboard_data(filtered_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::Button("Options"))
|
||||||
|
{
|
||||||
|
ImGui::OpenPopup("Options");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::InputText("Filter", &filter);
|
||||||
|
|
||||||
|
const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
|
||||||
|
ImGui::BeginChild("console_scroll", ImVec2(0, -footer_height_to_reserve), false);
|
||||||
|
|
||||||
|
ImGui::Text(filtered_text.data(), ImVec2(-1, -1));
|
||||||
|
|
||||||
|
if (auto_scroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
|
||||||
|
{
|
||||||
|
ImGui::SetScrollHereY(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if (ImGui::InputText("Input", &input, input_text_flags, input_text_edit))
|
||||||
|
{
|
||||||
|
game_console::add(input.data());
|
||||||
|
input.clear();
|
||||||
|
ImGui::SetKeyboardFocusHere(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
gui::on_frame(on_frame);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(gui_console::component)
|
Loading…
x
Reference in New Issue
Block a user