feat: command executor (search bar) (#1029)

This commit is contained in:
Johann 2023-03-11 00:06:09 +01:00 committed by GitHub
parent 4af9c7f258
commit 10bbf1f4bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 250 additions and 73 deletions

View File

@ -2,9 +2,10 @@
namespace big
{
bool_command::bool_command(const std::string& name, const std::string& label, const std::string& description, bool& toggle) :
bool_command::bool_command(const std::string& name, const std::string& label, const std::string& description, bool& toggle, bool show_notify) :
command(name, label, description, std::nullopt),
m_toggle(toggle)
m_toggle(toggle),
m_show_notify(show_notify)
{
}
@ -15,11 +16,15 @@ namespace big
if (is_enabled())
{
m_toggle = false;
if (m_show_notify)
ctx->report_output(std::format("{} has been disabled", m_label));
}
else
{
m_toggle = true;
if (m_show_notify)
ctx->report_output(std::format("{} has been enabled", m_label));
}
}

View File

@ -7,11 +7,12 @@ namespace big
{
protected:
bool& m_toggle;
bool m_show_notify;
virtual void execute(const std::vector<std::uint64_t>& args, const std::shared_ptr<command_context> ctx = std::make_shared<default_command_context>()) override;
virtual std::optional<std::vector<std::uint64_t>> parse_args(const std::vector<std::string>& args, const std::shared_ptr<command_context> ctx = std::make_shared<default_command_context>()) override;
public:
bool_command(const std::string& name, const std::string& label, const std::string& description, bool& toggle);
bool_command(const std::string& name, const std::string& label, const std::string& description, bool& toggle, bool show_notify = true);
inline bool& is_enabled()
{
return m_toggle;

View File

@ -99,23 +99,85 @@ namespace big
g_commands[command]->call(args, ctx);
}
void command::process(const std::string& text, const std::shared_ptr<command_context> ctx)
std::vector<command*> command::get_suggestions(std::string search, const int limit)
{
auto args = split(text, ' ');
std::vector<command*> result_cmds{};
for (auto& [hash, command] : g_commands)
{
if (command->get_label().length() == 0)
continue;
std::string cmd_name = command->get_name();
std::string cmd_label = command->get_label();
//transform all strings to lower case
std::transform(cmd_name.begin(), cmd_name.end(), cmd_name.begin(), tolower);
std::transform(cmd_label.begin(), cmd_label.end(), cmd_label.begin(), tolower);
std::transform(search.begin(), search.end(), search.begin(), tolower);
for (auto& cmd : split(search, ';'))
{
std::string search_label = split(cmd, ' ')[0];
if (cmd_name.contains(search_label))
result_cmds.push_back(command);
else if (cmd_label.contains(search_label))
result_cmds.push_back(command);
}
// apply our maximum vector size..
if (result_cmds.size() >= limit)
break;
}
return result_cmds;
}
bool command::process(const std::string& text, const std::shared_ptr<command_context> ctx, bool use_best_suggestion)
{
bool success = true;
for (auto& cmd : split(text, ';'))
{
auto args = split(cmd, ' ');
if (args.size() == 0 || args[0].empty())
{
ctx->report_error("No command to call");
return;
success = false;
continue;
}
//build the best command based on the input
if (use_best_suggestion)
{
const auto cmd_suggestions = get_suggestions(args[0]);
//is valid suggestion
if (cmd_suggestions.size() >= 1)
{
args[0] = cmd_suggestions[0]->get_name();
}
else
{
ctx->report_error(std::format("Command {} does not exist", args[0]));
success = false;
continue;
}
}
std::uint32_t hash = rage::joaat(args[0]);
if (!g_commands.contains(hash))
{
ctx->report_error(std::format("Command {} does not exist", args[0]));
return;
success = false;
continue;
}
args.erase(args.begin());
call(hash, args, ctx);
}
return success;
}
}

View File

@ -39,16 +39,21 @@ namespace big
{
return m_description;
}
inline const std::optional<std::uint8_t>& get_num_args()
{
return m_num_args;
}
void call(const std::vector<std::uint64_t>& args, const std::shared_ptr<command_context> ctx = std::make_shared<default_command_context>());
void call(const std::vector<std::string>& args, const std::shared_ptr<command_context> ctx = std::make_shared<default_command_context>());
static std::vector<command*> get_suggestions(std::string, int limit = 7);
static command* get(rage::joaat_t command);
static void call(rage::joaat_t command, const std::vector<std::uint64_t>& args, const std::shared_ptr<command_context> ctx = std::make_shared<default_command_context>());
static void call(rage::joaat_t command, const std::vector<std::string>& args, const std::shared_ptr<command_context> ctx = std::make_shared<default_command_context>());
static void process(const std::string& text, const std::shared_ptr<command_context> ctx = std::make_shared<default_command_context>());
static bool process(const std::string& text, const std::shared_ptr<command_context> ctx = std::make_shared<default_command_context>(), bool use_best_suggestion = false);
};
inline std::unordered_map<rage::joaat_t, command*> g_commands;

View File

@ -366,4 +366,10 @@ namespace big
{CommandAccessLevel::TOXIC, "toxic"},
{CommandAccessLevel::ADMIN, "admin"},
})
enum eKeyState : unsigned int
{
RELEASE = WM_KEYUP,
DOWN = WM_KEYDOWN
};
}

View File

@ -64,8 +64,12 @@ namespace big
rage::scrThread* m_mission_creator_thread = nullptr;
rage::scrThread* m_modshop_thread = nullptr;
struct cmd_executor
{
bool enabled = false;
} cmd_executor{};
rage::scrThread* m_modshop_thread = nullptr;
bool in_script_vm = false;
struct debug
@ -377,8 +381,9 @@ namespace big
int invisveh = 0;
int localinvisveh = 0;
int fast_quit = 0;
int cmd_excecutor = 0x55; // U
NLOHMANN_DEFINE_TYPE_INTRUSIVE(hotkeys, editing_menu_toggle, menu_toggle, teleport_waypoint, teleport_objective, noclip, bringvehicle, invis, heal, fill_inventory, skip_cutscene, freecam, superrun, superjump, beastjump, invisveh, localinvisveh, fast_quit)
NLOHMANN_DEFINE_TYPE_INTRUSIVE(hotkeys, editing_menu_toggle, menu_toggle, teleport_waypoint, teleport_objective, noclip, bringvehicle, invis, heal, fill_inventory, skip_cutscene, freecam, superrun, superjump, beastjump, invisveh, localinvisveh, fast_quit, cmd_excecutor)
} hotkeys{};
bool dev_dlc = false;

View File

@ -4,6 +4,7 @@
#include "natives.hpp"
#include "renderer.hpp"
#include "script.hpp"
#include "util/is_key_pressed.hpp"
#include "views/view.hpp"
#include <imgui.h>
@ -13,14 +14,15 @@ namespace big
gui::gui() :
m_is_open(false)
{
g_renderer->add_dx_callback(view::gta_data, -1); // -1 highest priority of drawing
g_renderer->add_dx_callback(view::notifications, -2);// second highest priority
g_renderer->add_dx_callback(view::overlay, -3); // 3rd highest priority
g_renderer->add_dx_callback(view::gta_data, -1);
g_renderer->add_dx_callback(view::notifications, -2);
g_renderer->add_dx_callback(view::overlay, -3);
g_renderer->add_dx_callback(view::cmd_executor, -4);
g_renderer->add_dx_callback(
[this] {
dx_on_tick();
},
-4);// 4th highest priority
-5);
g_renderer->add_wndproc_callback([this](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
wndproc(hwnd, msg, wparam, lparam);
@ -161,6 +163,21 @@ namespace big
PAD::DISABLE_CONTROL_ACTION(2, 262, true);
PAD::DISABLE_CONTROL_ACTION(2, 331, true);
}
//wndproc will not work here. the timing here is very difficult. mayby can we hook the creation of the pause menu?
//this should be improved..
if (is_key_pressed(VK_ESCAPE) && g.cmd_executor.enabled)
{
g_fiber_pool->queue_job([] {
g.cmd_executor.enabled = false;
//50 should run stable, IMPROVE THIS!!!
for (uint8_t i = 0; i <= 50; i++)
{
HUD::SET_PAUSE_MENU_ACTIVE(false);
script::get_current()->yield();
}
});
}
}
void gui::script_func()

View File

@ -172,11 +172,9 @@ namespace big
for (const auto& cb : m_wndproc_callbacks)
cb(hwnd, msg, wparam, lparam);
if (g_gui->is_open())
{
ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam);
}
}
void renderer::new_frame()
{

View File

@ -24,6 +24,8 @@ namespace big
register_hotkey("invisveh", g.settings.hotkeys.invisveh, RAGE_JOAAT("invisveh"));
register_hotkey("localinvisveh", g.settings.hotkeys.localinvisveh, RAGE_JOAAT("localinvisveh"));
register_hotkey("fastquit", g.settings.hotkeys.fast_quit, RAGE_JOAAT("fastquit"));
register_hotkey("quicksearch", g.settings.hotkeys.cmd_excecutor, RAGE_JOAAT("cmdexecutor"));
g_renderer->add_wndproc_callback([this](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
wndproc(static_cast<eKeyState>(msg), wparam);
@ -70,6 +72,10 @@ namespace big
if (const auto chat_data = *g_pointers->m_chat_data; chat_data && (chat_data->m_chat_open || chat_data->m_timer_two))
return;
//command executer is opened
if (g.cmd_executor.enabled)
return;
if (g_gui->is_open())
return;

View File

@ -1,15 +1,10 @@
#pragma once
#include "common.hpp"
#include "core/enums.hpp"
#include "hotkey.hpp"
namespace big
{
enum eKeyState : unsigned int
{
RELEASE = WM_KEYUP,
DOWN = WM_KEYDOWN
};
using hotkey_map = std::multimap<key_t, hotkey>;
class hotkey_service final

View File

@ -29,5 +29,6 @@ namespace big
g_gui_service->get_selected()->func();
ImGui::PopStyleVar();
}
ImGui::End();
}
}

View File

@ -0,0 +1,72 @@
#include "backend/context/default_command_context.hpp"
#include "gui.hpp"
#include "pointers.hpp"
#include "services/hotkey/hotkey_service.hpp"
#include "views/view.hpp"
namespace big
{
void view::cmd_executor()
{
if (!g.cmd_executor.enabled)
return;
float screen_x = (float)*g_pointers->m_resolution_x;
float screen_y = (float)*g_pointers->m_resolution_y;
ImGui::SetNextWindowPos(ImVec2(screen_x * 0.25f, screen_y * 0.2f), ImGuiCond_Always);
ImGui::SetNextWindowBgAlpha(0.65f);
ImGui::SetNextWindowSize({screen_x * 0.5f, -1});
if (ImGui::Begin("cmd_executor", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
{
static char command_buffer[255];
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {10.f, 15.f});
components::sub_title("CMD_EXECUTOR_TITLE"_T);
// set focus by default on input box
ImGui::SetKeyboardFocusHere(0);
ImGui::SetNextItemWidth(screen_x * 0.5f);
components::input_text_with_hint("", "CMD_EXECUTOR_TYPE_CMD"_T, command_buffer, sizeof(command_buffer), ImGuiInputTextFlags_EnterReturnsTrue, [] {
if (command::process(command_buffer, std::make_shared<default_command_context>(), true))
{
g.cmd_executor.enabled = false;
command_buffer[0] = 0;
}
});
components::small_text("CMD_EXECUTOR_MULTIPLE_CMDS"_T);
ImGui::Spacing();
auto possible_commands = command::get_suggestions(command_buffer);
if (possible_commands.size() == 0)
{
ImGui::Text("CMD_EXECUTOR_NO_CMD"_T.data());
}
else
{
for (auto cmd : possible_commands)
{
ImGui::Text(std::vformat("CMD_EXECUTOR_CMD_TEMPLATE"_T,
std::make_format_args(cmd->get_name(),
cmd->get_label(),
cmd->get_description(),
cmd->get_num_args() ? cmd->get_num_args().value() : 0))
.data());
// check if we aren't on the last iteration
if (cmd != possible_commands.back())
ImGui::Separator();
}
}
ImGui::PopStyleVar();
}
ImGui::End();
}
bool_command
g_cmd_executor("cmdexecutor", "Toggle Command Executor", "Toggles the command executor window", g.cmd_executor.enabled, false);
}

View File

@ -35,5 +35,6 @@ namespace big
}
ImGui::PopStyleColor();
}
ImGui::End();
}
}

View File

@ -8,7 +8,7 @@ namespace big
ImGui::SetNextWindowPos({10.f, 100.f * g.window.gui_scale}, ImGuiCond_Always);
ImGui::SetNextWindowSize({300.f * g.window.gui_scale, 0.f}, ImGuiCond_Always);
if (ImGui::Begin("navigation", 0, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNav))
if (ImGui::Begin("navigation", 0, window_flags))
{
g_gui_service->reset_nav_size();
for (std::pair<tabs, navigation_struct> navItem : g_gui_service->get_navigation())

View File

@ -42,6 +42,8 @@ namespace big
g_hotkey_service->update_hotkey("localinvisveh", g.settings.hotkeys.localinvisveh);
if (ImGui::Hotkey("Rage Quit (Like Alt + F4)", &g.settings.hotkeys.fast_quit))
g_hotkey_service->update_hotkey("fastquit", g.settings.hotkeys.fast_quit);
if (ImGui::Hotkey("Toggle Command Executor", &g.settings.hotkeys.cmd_excecutor))
g_hotkey_service->update_hotkey("cmdexecutor", g.settings.hotkeys.cmd_excecutor);
ImGui::PopItemWidth();
}

View File

@ -63,6 +63,7 @@ namespace big
static void player_kick();
static void player_toxic();
static void player_misc();
static void cmd_executor();
static void player_vehicle();
};
}