From eaeb54b728ea604de9bb5cfc674c3410a2cb1e23 Mon Sep 17 00:00:00 2001 From: gir489 <100792176+gir489returns@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:17:46 -0500 Subject: [PATCH] Clone Debug Globals into Debug Locals (#2419) * Copied code from Debug Globals to Debug Locals. Redesigned components::input_text to return the InputText result, and add an overloaded method to take a std::string. Fixed Debug Globals having static text and not using components::input_text to prevent sending the input to the game. Fixed view_debug_threads::thread_states not properly ending its string causing ImGui to read more than it should from memory. Made Debug Globals cap the input index to UINT32, as the user could potentially overflow the get_ptr function and cause the game to crash. * Removed extraneous does_thread_exist deceleration. --- src/gui/components/components.hpp | 3 +- src/gui/components/input_text.cpp | 25 +- src/services/locals/locals_service.cpp | 123 ------ src/services/locals/locals_service.hpp | 125 ------ src/views/debug/view_debug_globals.cpp | 16 +- src/views/debug/view_debug_locals.cpp | 548 ++++++++++++++++--------- src/views/debug/view_debug_threads.cpp | 2 +- 7 files changed, 381 insertions(+), 461 deletions(-) delete mode 100644 src/services/locals/locals_service.cpp delete mode 100644 src/services/locals/locals_service.hpp diff --git a/src/gui/components/components.hpp b/src/gui/components/components.hpp index bfb224dc..08a0d405 100644 --- a/src/gui/components/components.hpp +++ b/src/gui/components/components.hpp @@ -26,7 +26,8 @@ namespace big static bool input_text_with_hint(const std::string_view label, const std::string_view hint, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function cb = nullptr); static bool input_text_with_hint(const std::string_view label, const std::string_view hint, std::string& buf, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function cb = nullptr); - static void input_text(const std::string_view label, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function cb = nullptr); + static bool input_text(const std::string_view label, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function cb = nullptr); + static bool input_text(const std::string_view label, std::string& buf, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function cb = nullptr); static bool selectable(const std::string_view, bool); static bool selectable(const std::string_view, bool, ImGuiSelectableFlags); diff --git a/src/gui/components/input_text.cpp b/src/gui/components/input_text.cpp index 12fb7370..4367e7c8 100644 --- a/src/gui/components/input_text.cpp +++ b/src/gui/components/input_text.cpp @@ -1,16 +1,39 @@ #include "fiber_pool.hpp" #include "gui/components/components.hpp" +#include "misc/cpp/imgui_stdlib.h" #include "natives.hpp" namespace big { - void components::input_text(const std::string_view label, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag, std::function cb) + bool components::input_text(const std::string_view label, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag, std::function cb) { + bool retval = false; if (ImGui::InputText(label.data(), buf, buf_size, flag)) + { if (cb) g_fiber_pool->queue_job(std::move(cb)); + retval = true; + } if (ImGui::IsItemActive()) g.self.hud.typing = TYPING_TICKS; + + return retval; + } + + bool components::input_text(const std::string_view label, std::string& buf, ImGuiInputTextFlags_ flag, std::function cb) + { + bool retval = false; + if (ImGui::InputText(label.data(), &buf, flag)) + { + if (cb) + g_fiber_pool->queue_job(std::move(cb)); + retval = true; + } + + if (ImGui::IsItemActive()) + g.self.hud.typing = TYPING_TICKS; + + return retval; } } \ No newline at end of file diff --git a/src/services/locals/locals_service.cpp b/src/services/locals/locals_service.cpp deleted file mode 100644 index 6942fa6c..00000000 --- a/src/services/locals/locals_service.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "locals_service.hpp" - -#include "core/data/all_script_names.hpp" -#include "fiber_pool.hpp" -#include "natives.hpp" -#include "pointers.hpp" - -namespace big -{ - - bool locals_service::is_script_thread_running(GtaThread* thread) - { - if (thread) - { - return thread->m_context.m_state == rage::eThreadState::running || thread->m_context.m_state == rage::eThreadState::idle; - } - return false; - } - - bool locals_service::does_script_exist(std::string script_name) - { - return SCRIPT::DOES_SCRIPT_WITH_NAME_HASH_EXIST(rage::joaat(script_name)); - } - - std::filesystem::path locals_service::get_path() - { - return g_file_manager.get_project_file("locals.json").get_path(); - } - - bool locals_service::load() - { - std::ifstream file(locals_service::get_path()); - if (!file.is_open()) - return false; - - try - { - nlohmann::json j; - file >> j; - m_locals.clear(); - for (const auto& l : j.items()) - { - if (!l.key().empty()) - { - local new_local{"", "", 0, 0, 0, 0, 0}; - new_local.m_base_address = j[l.key()]["base_address"]; - std::string script_name = j[l.key()]["script_thread_name"]; - strcpy(new_local.m_script_thread_name, script_name.data()); - new_local.m_freeze = j[l.key()]["freeze"]; - std::string name = j[l.key()]["name"]; - strcpy(new_local.m_name, name.data()); - new_local.m_value = j[l.key()]["value"]; - new_local.m_edit_mode = j[l.key()].value("editmode", 0); - if (!j[l.key()]["offsets"].is_null()) - { - for (const auto& offset : j[l.key()]["offsets"].items()) - { - if (!offset.key().empty()) - { - local_offset new_offset{0, 0}; - new_offset.m_offset = j[l.key()]["offsets"][offset.key()]["offset"]; - if (!j[l.key()]["offsets"][offset.key()]["size"].is_null()) - new_offset.m_size = j[l.key()]["offsets"][offset.key()]["size"]; - new_local.m_offsets.push_back(new_offset); - } - } - } - new_local.fetch_local_pointer(); - m_locals.push_back(new_local); - } - } - } - catch (const std::exception&) - { - LOG(WARNING) << "Failure to parse locals.json, aborting..."; - - return false; - } - - return true; - } - - void locals_service::save() - { - std::map locals_with_names; - for (auto& l : m_locals) - { - locals_with_names.insert(std::pair(std::string(l.m_name).empty() ? std::string(l.m_script_thread_name + std::string("_") + std::to_string(l.m_base_address)) : l.m_name, l)); - } - - nlohmann::json j; - for (auto& l : locals_with_names) - { - j[l.first]["script_thread_name"] = l.second.m_script_thread_name; - j[l.first]["base_address"] = l.second.m_base_address; - j[l.first]["freeze"] = l.second.m_freeze; - j[l.first]["name"] = l.second.m_name; - j[l.first]["value"] = l.second.m_value; - j[l.first]["editmode"] = l.second.m_edit_mode; - - for (int i = 0; i < l.second.m_offsets.size(); i++) - { - j[l.first]["offsets"][std::to_string(i)]["offset"] = l.second.m_offsets[i].m_offset; - if (l.second.m_offsets[i].m_size > 0) - j[l.first]["offsets"][std::to_string(i)]["size"] = l.second.m_offsets[i].m_size; - }; - } - - std::ofstream file(locals_service::get_path(), std::ios::out | std::ios::trunc); - - try - { - file << j.dump(4); - - file.close(); - } - catch (const std::exception&) - { - LOG(WARNING) << "Failed to write to locals.json"; - } - } - -}; \ No newline at end of file diff --git a/src/services/locals/locals_service.hpp b/src/services/locals/locals_service.hpp deleted file mode 100644 index db2053c1..00000000 --- a/src/services/locals/locals_service.hpp +++ /dev/null @@ -1,125 +0,0 @@ -#pragma once - -#include "file_manager.hpp" -#include "file_manager/file.hpp" -#include "gta/script_thread.hpp" -#include "gta_util.hpp" -#include "script_local.hpp" - -namespace big -{ - - struct local_offset - { - local_offset(int offset, int size = 0) - { - m_offset = offset; - - if (size) - m_size = size; - } - - int m_offset = 0; - int m_size = 0; - }; - - - struct local - { - GtaThread* m_script_thread; - char m_script_thread_name[200]; - int m_base_address; - bool m_freeze = false; - char m_name[200]; - std::vector m_offsets; - int m_value; - int m_freeze_value_int; - float m_freeze_value_float; - Vector3 m_freeze_value_vector3; - int* m_internal_address; - Vector3* m_internal_address_vector3; - int m_edit_mode = 0; - - local(const char* script_thread_name, const char* name, const int base_address, const bool freeze, const int (*offsets)[2], int offset_count, int edit_mode = 0) - { - m_internal_id = ++m_instance_count; - - strcpy(m_script_thread_name, script_thread_name); - m_base_address = base_address; - m_freeze = freeze; - strcpy(m_name, name); - m_value = 0; - - for (int i = 0; i < offset_count; i++) - m_offsets.push_back(local_offset(offsets[i][0], offsets[i][1])); - - m_edit_mode = edit_mode; - - fetch_local_pointer(); - } - - int get_id() const - { - return m_internal_id; - } - - int* fetch_local_pointer() - { - m_script_thread = gta_util::find_script_thread(rage::joaat(m_script_thread_name)); - - if (m_script_thread) - { - script_local actual_local = script_local(m_script_thread, m_base_address); - - for (auto& offset : m_offsets) - { - if (offset.m_size > 0) - actual_local = actual_local.at(offset.m_offset, offset.m_size); - else - actual_local = actual_local.at(offset.m_offset); - } - - m_internal_address = actual_local.as(); - m_internal_address_vector3 = actual_local.as(); - - return m_internal_address; - } - return nullptr; - } - - const char* get_local_chain_text() - { - static char offsetschain[200] = ""; - strcpy(offsetschain, ""); - strcat(offsetschain, std::to_string(m_base_address).data()); - for (auto o : m_offsets) - { - strcat(offsetschain, std::string(".f_" + std::to_string(o.m_offset)).data()); - if (o.m_size) - strcat(offsetschain, std::string("/" + std::to_string(o.m_size)).data()); - } - return offsetschain; - } - - private: - inline static int m_instance_count; - int m_internal_id; - }; - - - class locals_service - { - public: - std::filesystem::path get_path(); - bool load(); - void save(); - - static bool does_script_exist(std::string script); - static bool is_script_thread_running(GtaThread* thread); - - std::vector m_locals; - bool m_running = false; - }; - - inline locals_service g_locals_service{}; -} \ No newline at end of file diff --git a/src/views/debug/view_debug_globals.cpp b/src/views/debug/view_debug_globals.cpp index da48e87d..2ae3aec6 100644 --- a/src/views/debug/view_debug_globals.cpp +++ b/src/views/debug/view_debug_globals.cpp @@ -190,7 +190,7 @@ namespace big static global_debug global_test{}; static script_global glo_bal_sunday = script_global(global_test.global_index); ImGui::SetNextItemWidth(200.f); - if (ImGui::InputScalar("VIEW_DEBUG_GLOBAL"_T.data(), ImGuiDataType_U64, &global_test.global_index)) + if (ImGui::InputScalar("VIEW_DEBUG_GLOBAL"_T.data(), ImGuiDataType_U32, &global_test.global_index)) glo_bal_sunday = script_global(global_test.global_index); for (int i = 0; i < global_test.global_appendages.size(); i++) @@ -201,20 +201,20 @@ namespace big { case GlobalAppendageType_At: ImGui::SetNextItemWidth(200.f); - ImGui::InputScalar("VIEW_DEBUG_GLOBAL_AT"_T.data(), ImGuiDataType_S64, &global_test.global_appendages[i].index); + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_AT"_T.data(), ImGuiDataType_U16, &global_test.global_appendages[i].index); ImGui::SameLine(); ImGui::SetNextItemWidth(200.f); - ImGui::InputScalar("VIEW_DEBUG_GLOBAL_SIZE"_T.data(), ImGuiDataType_S64, &global_test.global_appendages[i].size); + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_SIZE"_T.data(), ImGuiDataType_U16, &global_test.global_appendages[i].size); break; case GlobalAppendageType_ReadGlobal: ImGui::Text(std::format("{} {}", "VIEW_DEBUG_GLOBAL_READ_GLOBAL"_T, item.global_name).c_str()); ImGui::SameLine(); ImGui::SetNextItemWidth(200.f); - ImGui::InputScalar("VIEW_DEBUG_GLOBAL_SIZE"_T.data(), ImGuiDataType_S64, &global_test.global_appendages[i].size); + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_SIZE"_T.data(), ImGuiDataType_U16, &global_test.global_appendages[i].size); break; case GlobalAppendageType_PlayerId: ImGui::SetNextItemWidth(200.f); - ImGui::InputScalar("VIEW_DEBUG_GLOBAL_READ_PLAYER_ID_SIZE"_T.data(), ImGuiDataType_S64, &global_test.global_appendages[i].size); + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_READ_PLAYER_ID_SIZE"_T.data(), ImGuiDataType_U16, &global_test.global_appendages[i].size); break; } ImGui::PopID(); @@ -279,7 +279,7 @@ namespace big std::string characters = (PCHAR)ptr; try { - ImGui::InputText("VIEW_DEBUG_GLOBAL_VALUE"_T.data(), (PCHAR)ptr, 255); + components::input_text("VIEW_DEBUG_GLOBAL_VALUE"_T.data(), (PCHAR)ptr, 255); } catch (...){ } //This can crash if the user tries to edit the invalid ??? scenario from ImGui, so to prevent that, just silently do nothing. break; } @@ -318,10 +318,10 @@ namespace big ImGui::BeginGroup(); static char global_name[50]{}; ImGui::SetNextItemWidth(200.f); - ImGui::InputText("##GlobalName", global_name, IM_ARRAYSIZE(global_name)); + components::input_text("##GlobalName", global_name, IM_ARRAYSIZE(global_name)); if (ImGui::IsItemActive()) g.self.hud.typing = TYPING_TICKS; - if (ImGui::Button("Save Global")) + if (ImGui::Button("VIEW_DEBUG_GLOBAL_SAVE_GLOBAL"_T.data())) { save_global(global_name, global_test); } diff --git a/src/views/debug/view_debug_locals.cpp b/src/views/debug/view_debug_locals.cpp index a1dcedc4..0bc2e3b9 100644 --- a/src/views/debug/view_debug_locals.cpp +++ b/src/views/debug/view_debug_locals.cpp @@ -1,237 +1,381 @@ #include "gui/components/components.hpp" -#include "services/locals/locals_service.hpp" +#include "script_local.hpp" +#include "thread_pool.hpp" #include "view_debug.hpp" #include "widgets/imgui_bitfield.hpp" +#include "gta_util.hpp" namespace big { - - void render_local_creator_popup_content() + enum LocalAppendageType : int { - static int base_address = 0; - static bool freeze = false; - static char name[200] = ""; - static char script_thread_name[200] = ""; - static int offsets[10][2] = {}; - static int offset_count = 0; - static int previous_offset_count = 0; - components::input_text("NAME"_T, name, sizeof(name)); - components::input_text("VIEW_DEBUG_LOCALS_SCRIPT_NAME"_T, script_thread_name, sizeof(script_thread_name)); - ImGui::Text("VIEW_DEBUG_LOCALS_BASE_ADDRESS"_T.data()); - ImGui::InputInt("##local_base_address", &base_address); - ImGui::Text("VIEW_DEBUG_LOCALS_OFFSET_COUNT"_T.data()); - ImGui::InputInt("##modal_offset_count", &offset_count); + LocalAppendageType_At, + LocalAppendageType_ReadLocal, + LocalAppendageType_PlayerId, + }; - offset_count = std::clamp(offset_count, 0, 10); + enum LocalValueType : int + { + INT, + BOOLEAN, + BITSET, + FLOAT, + VECTOR, + VARCHAR + }; - ImGui::PushItemWidth(320.f); - for (int i = 0; i < offset_count; i++) + struct local_debug_inner + { + LocalAppendageType type{}; + std::ptrdiff_t index{}; + std::size_t size{}; + std::string local_name{}; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(local_debug_inner, type, index, size, local_name) + }; + + struct local_debug + { + std::string script_name{}; + std::size_t local_index{}; + std::vector local_appendages{}; + LocalValueType local_value_type = LocalValueType::INT; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(local_debug, script_name, local_index, local_appendages, local_value_type) + }; + + nlohmann::json get_locals_json() + { + nlohmann::json locals{}; + + auto file = g_file_manager.get_project_file("./locals.json"); + if (file.exists()) { - ImGui::PushID(i); - - ImGui::Separator(); - - ImGui::Text("DEBUG_GLOBAL_OFFSET"_T.data(), i + 1); - ImGui::InputInt("##offset", &offsets[i][0]); - - ImGui::Text("DEBUG_GLOBAL_SIZE"_T.data()); - ImGui::SameLine(); - ImGui::InputInt("##size", &offsets[i][1]); - - ImGui::PopID(); + std::ifstream iffstream_file(file.get_path()); + iffstream_file >> locals; } - ImGui::PopItemWidth(); - static auto reset_values = []() -> void { - strcpy(name, ""); - freeze = false; - offset_count = 0; - previous_offset_count = 0; - }; + return locals; + } - if (components::button("CANCEL"_T)) + void load_local_menu(const std::string& selected_local, local_debug& local_obj) + { + if (!selected_local.empty()) { - reset_values(); - - ImGui::CloseCurrentPopup(); + auto locals = get_locals_json(); + if (locals[selected_local].is_null()) + return; + local_obj = locals[selected_local].get(); } - ImGui::SameLine(); - if (components::button("SAVE"_T)) + } + + int64_t* get_local_ptr(GtaThread* local_thread, local_debug& local_test) + { + if (local_thread == nullptr) + return nullptr; + + script_local local_to_read = script_local(local_thread, local_test.local_index); + for (auto item : local_test.local_appendages) { - if (locals_service::does_script_exist(script_thread_name)) + if (item.type == LocalAppendageType_At) { - auto new_local = local(script_thread_name, name, base_address, freeze, offsets, offset_count); - if (std::string(name).empty()) - strcpy(name, new_local.get_local_chain_text()); - g_locals_service.m_locals.push_back(new_local); - - reset_values(); - - ImGui::CloseCurrentPopup(); + if (item.size != 0) + local_to_read = local_to_read.at(item.index, item.size); + else + local_to_read = local_to_read.at(item.index); } - else + else if (item.type == LocalAppendageType_ReadLocal) { - g_notification_service->push_error("DEBUG_TAB_LOCALS"_T.data(), "VIEW_DEBUG_LOCALS_SCRIPT_DOES_NOT_EXIST"_T.data()); + local_debug local_read; + load_local_menu(item.local_name, local_read); + if (auto ptr = get_local_ptr(local_thread, local_read)) + if (item.size != 0) + local_to_read = local_to_read.at(*ptr, item.size); + else + local_to_read = local_to_read.at(*ptr); + else + LOG(WARNING) << "Failed to read " << item.local_name << "for get_local_ptr"; } - }; + else if (item.type == LocalAppendageType_PlayerId) + { + if (item.size != 0) + local_to_read = local_to_read.at(self::id, item.size); + else + local_to_read = local_to_read.at(self::id); + } + } + auto retn_val = local_to_read.as(); + if ((size_t)retn_val < UINT32_MAX) + return nullptr; + return retn_val; + } + + std::string get_local_display(local_debug& local_test) + { + auto local_thread = gta_util::find_script_thread(rage::joaat(local_test.script_name)); + + if (local_thread == nullptr) + return "VIEW_DEBUG_LOCALS_SCRIPT_DOES_NOT_EXIST"_T.data(); + + auto ptr = get_local_ptr(local_thread, local_test); + if (ptr != nullptr) + { + switch (local_test.local_value_type) + { + case LocalValueType::INT: + { + return std::to_string(*(PINT)ptr); + } + case LocalValueType::BOOLEAN: + { + return (*ptr == TRUE) ? "TRUE" : "FALSE"; + } + case LocalValueType::BITSET: + { + std::ostringstream o; + o << "0x" << std::hex << std::uppercase << (DWORD)*ptr; + return o.str(); + } + case LocalValueType::FLOAT: + { + return std::to_string(*(PFLOAT)ptr); + } + case LocalValueType::VECTOR: + { + std::ostringstream o; + auto vectorptr = (rage::scrVector*)ptr; + o << "X: " << std::fixed << std::setprecision(2) << vectorptr->x << " Y: " << vectorptr->y << " Z: " << vectorptr->z; + return o.str(); + } + case LocalValueType::VARCHAR: + { + return (PCHAR)ptr; + } + } + } + return "VIEW_DEBUG_LOCALS_INVALID_LOCAL_READ"_T.data(); + } + + std::map list_locals() + { + auto json = get_locals_json(); + std::map return_value; + for (auto& item : json.items()) + return_value[item.key()] = item.value(); + return return_value; + } + + void save_local(char* local_name, local_debug& local_obj) + { + std::string teleport_name_string = local_name; + if (!teleport_name_string.empty()) + { + auto json = get_locals_json(); + json[teleport_name_string] = local_obj; + + auto file_path = g_file_manager.get_project_file("./locals.json").get_path(); + std::ofstream file(file_path, std::ios::out | std::ios::trunc); + file << json.dump(4); + file.close(); + ZeroMemory(local_name, sizeof(local_name)); + } + } + + void delete_local(std::string name) + { + auto locations = get_locals_json(); + if (locations[name].is_null()) + return; + locations.erase(name); + auto file_path = g_file_manager.get_project_file("./locals.json").get_path(); + std::ofstream file(file_path, std::ios::out | std::ios::trunc); + file << locations.dump(4); + file.close(); } void debug::locals() { if (ImGui::BeginTabItem("DEBUG_TAB_LOCALS"_T.data())) { - if (components::button("LOAD"_T)) - g_locals_service.load(); - ImGui::SameLine(); - if (components::button("SAVE"_T)) - g_locals_service.save(); + static local_debug local_test{}; + static script_local local_laddie = script_local(local_test.local_index); - if (components::button("VIEW_DEBUG_LOCALS_ADD_LOCAL"_T)) + ImGui::SetNextItemWidth(300.f); + + components::input_text("VIEW_DEBUG_LOCALS_SCRIPT_NAME"_T, local_test.script_name); + + auto local_thread = gta_util::find_script_thread(rage::joaat(local_test.script_name)); + + if (local_thread == nullptr) + ImGui::Text("VIEW_DEBUG_LOCALS_SCRIPT_DOES_NOT_EXIST"_T.data()); + + ImGui::PushItemWidth(200.f); + + if (ImGui::InputScalar("VIEW_DEBUG_LOCALS_LOCAL"_T.data(), ImGuiDataType_U16, &local_test.local_index)) + local_laddie = script_local(local_thread, local_test.local_index); + + ImGui::PopItemWidth(); + + for (int i = 0; i < local_test.local_appendages.size(); i++) { - ImGui::OpenPopup("##addlocal"); - } - - if (ImGui::BeginPopupModal("##addlocal")) - { - render_local_creator_popup_content(); - - ImGui::EndPopup(); - } - - for (auto& local_ : g_locals_service.m_locals) - { - ImGui::BeginGroup(); - ImGui::PushID(local_.get_id()); - ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); - if (ImGui::TreeNode(strcmp(local_.m_name, "") == 0 ? - std::string(local_.m_script_thread_name + std::string(" ")).append(local_.get_local_chain_text()).data(): local_.m_name)) + auto item = local_test.local_appendages[i]; + ImGui::PushID(i + item.type); + switch (item.type) { - ImGui::Text("%s : %s", local_.m_script_thread_name, local_.m_name); - if (ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - ImGui::Text(local_.get_local_chain_text()); - ImGui::EndTooltip(); - } - - //Find the thread among the script threads - if (!local_.m_script_thread) - local_.m_script_thread = gta_util::find_script_thread(rage::joaat(local_.m_script_thread_name)); - - if (local_.m_script_thread && locals_service::is_script_thread_running(local_.m_script_thread)) - { - //Check whether the address is found - if (local_.m_internal_address) - { - if (ImGui::RadioButton("Int", local_.m_edit_mode == 0)) - local_.m_edit_mode = 0; - ImGui::SameLine(); - if (ImGui::RadioButton("Float", local_.m_edit_mode == 1)) - local_.m_edit_mode = 1; - ImGui::SameLine(); - if (ImGui::RadioButton("Bitfield", local_.m_edit_mode == 2)) - local_.m_edit_mode = 2; - ImGui::SameLine(); - if (ImGui::RadioButton("Vector3", local_.m_edit_mode == 3)) - local_.m_edit_mode = 3; - - - ImGui::LabelText(local_.get_local_chain_text(), "VIEW_DEBUG_GLOBAL_VALUE"_T.data()); - - ImGui::SetNextItemWidth(200); - - switch (local_.m_edit_mode) - { - case 0: - - if (ImGui::InputInt("##local_value", - local_.m_freeze ? &local_.m_freeze_value_int : local_.m_internal_address)) - { - local_.m_value = *local_.m_internal_address; - } - - if (local_.m_freeze) - { - *local_.m_internal_address = local_.m_freeze_value_int; - } - break; - case 1: - - if (ImGui::InputFloat("##local_value", - local_.m_freeze ? &local_.m_freeze_value_float : (float*)local_.m_internal_address)) - { - local_.m_value = *local_.m_internal_address; - } - - if (local_.m_freeze) - { - *(float*)local_.m_internal_address = local_.m_freeze_value_float; - } - break; - case 2: - - if (ImGui::Bitfield("##local_value", - local_.m_freeze ? &local_.m_freeze_value_int : local_.m_internal_address)) - { - local_.m_value = *local_.m_internal_address; - } - - if (local_.m_freeze) - { - *local_.m_internal_address = local_.m_freeze_value_int; - } - break; - - case 3: - ImGui::SetNextItemWidth(300); - if (ImGui::InputFloat3("##local_value", - local_.m_freeze ? (float*)&local_.m_freeze_value_vector3 : (float*)local_.m_internal_address)) - { - local_.m_value = *local_.m_internal_address; - } - - if (local_.m_freeze) - { - *local_.m_internal_address_vector3 = local_.m_freeze_value_vector3; - } - break; - } - - ImGui::SameLine(); - if (ImGui::Checkbox("VIEW_DEBUG_LOCALS_FREEZE"_T.data(), &local_.m_freeze)) - { - local_.m_freeze_value_int = *local_.m_internal_address; - local_.m_freeze_value_float = *reinterpret_cast(local_.m_internal_address); - local_.m_freeze_value_vector3 = *local_.m_internal_address_vector3; - } - } - else - { - if (components::button("VIEW_DEBUG_LOCALS_FETCH"_T)) - { - local_.fetch_local_pointer(); - } - } - } - else - { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); - ImGui::Text(std::format("{} {}", local_.m_script_thread_name, "VIEW_DEBUG_LOCALS_SCRIPT_IS_NOT_RUNNING"_T).c_str()); - ImGui::PopStyleColor(); - } - if (components::button("DELETE"_T)) - std::erase_if(g_locals_service.m_locals, [local_](local l) { - return l.get_id() == local_.get_id(); - }); - - ImGui::PopID(); - ImGui::Separator(); - - ImGui::TreePop(); + case LocalAppendageType_At: + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_AT"_T.data(), ImGuiDataType_U16, &local_test.local_appendages[i].index); + ImGui::SameLine(); + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_SIZE"_T.data(), ImGuiDataType_U16, &local_test.local_appendages[i].size); + break; + case LocalAppendageType_ReadLocal: + ImGui::Text(std::format("{} {}", "VIEW_DEBUG_LOCALS_READ_LOCAL"_T, item.local_name).c_str()); + ImGui::SameLine(); + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_SIZE"_T.data(), ImGuiDataType_U16, &local_test.local_appendages[i].size); + break; + case LocalAppendageType_PlayerId: + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_READ_PLAYER_ID_SIZE"_T.data(), ImGuiDataType_U16, &local_test.local_appendages[i].size); + break; } - ImGui::EndGroup(); + ImGui::PopID(); } + if (ImGui::Button("VIEW_DEBUG_GLOBAL_ADD_OFFSET"_T.data())) + local_test.local_appendages.push_back({LocalAppendageType_At, 0LL, 0ULL}); + ImGui::SameLine(); + if (ImGui::Button("VIEW_DEBUG_GLOBAL_ADD_READ_PLAYER_ID"_T.data())) + local_test.local_appendages.push_back({LocalAppendageType_PlayerId, 0LL, 0ULL}); + + if (local_test.local_appendages.size() > 0 && ImGui::Button("VIEW_DEBUG_GLOBAL_REMOVE_OFFSET"_T.data())) + local_test.local_appendages.pop_back(); + + if (auto ptr = get_local_ptr(local_thread, local_test)) + { + switch (local_test.local_value_type) + { + case LocalValueType::INT: + { + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_VALUE"_T.data(), ImGuiDataType_S32, ptr); + break; + } + case LocalValueType::BOOLEAN: + { + bool is_local_enabled = (*ptr == TRUE); + if (ImGui::Checkbox("VIEW_DEBUG_GLOBAL_VALUE"_T.data(), &is_local_enabled)) + { + *ptr = is_local_enabled; + } + break; + } + case LocalValueType::BITSET: + { + ImGui::Bitfield("VIEW_DEBUG_GLOBAL_VALUE"_T.data(), (PINT)ptr); + break; + } + case LocalValueType::FLOAT: + { + ImGui::InputScalar("VIEW_DEBUG_GLOBAL_VALUE"_T.data(), ImGuiDataType_Float, ptr); + break; + } + case LocalValueType::VECTOR: + { + ImGui::PushItemWidth(100.f); + auto vectorptr = (rage::scrVector*)ptr; + ImGui::InputScalar("X", ImGuiDataType_Float, &vectorptr->x); + ImGui::SameLine(); + ImGui::InputScalar("Y", ImGuiDataType_Float, &vectorptr->y); + ImGui::SameLine(); + ImGui::InputScalar("Z", ImGuiDataType_Float, &vectorptr->z); + ImGui::PopItemWidth(); + break; + } + case LocalValueType::VARCHAR: + { + std::string characters = (PCHAR)ptr; + try + { + components::input_text("VIEW_DEBUG_GLOBAL_VALUE"_T.data(), (PCHAR)ptr, 255); + } catch (...){ } //This can crash if the user tries to edit the invalid ??? scenario from ImGui, so to prevent that, just silently do nothing. + break; + } + } + } + else + { + ImGui::Text("VIEW_DEBUG_LOCALS_INVALID_LOCAL_READ"_T.data()); + } + + ImGui::PopItemWidth(); + + ImGui::SetNextItemWidth(150.f); + ImGui::Combo("VIEW_DEBUG_GLOBAL_TYPE"_T.data(), (int*)&local_test.local_value_type, "INT\0BOOLEAN\0BITSET\0FLOAT\0VECTOR\0VARCHAR\0"); + + auto locals = list_locals(); + static std::string selected_local; + ImGui::Text("VIEW_DEBUG_LOCALS_SAVED_LOCALS"_T.data()); + if (ImGui::BeginListBox("##savedlocals", ImVec2(200, 250))) + { + for (auto pair : locals) + { + if (ImGui::Selectable(pair.first.c_str(), selected_local == pair.first)) + selected_local = std::string(pair.first); + } + ImGui::EndListBox(); + } + ImGui::SameLine(); + if (ImGui::BeginListBox("##localvalues", ImVec2(250, 250))) + { + for (auto pair : locals) + { + ImGui::Selectable(get_local_display(pair.second).c_str(), false, ImGuiSelectableFlags_Disabled); + } + ImGui::EndListBox(); + } + ImGui::SameLine(); + ImGui::BeginGroup(); + static char local_name[50]{}; + ImGui::SetNextItemWidth(200.f); + components::input_text("##localname", local_name, IM_ARRAYSIZE(local_name)); + if (ImGui::IsItemActive()) + g.self.hud.typing = TYPING_TICKS; + if (ImGui::Button("VIEW_DEBUG_LOCALS_SAVE_LOCAL"_T.data())) + { + save_local(local_name, local_test); + } + ImGui::SameLine(); + if (ImGui::Button("VIEW_DEBUG_LOCALS_LOAD_LOCAL"_T.data())) + { + load_local_menu(selected_local, local_test); + } + + if (ImGui::Button("VIEW_DEBUG_LOCALS_DELETE_LOCAL"_T.data())) + { + if (!selected_local.empty()) + { + delete_local(selected_local); + selected_local.clear(); + } + } + ImGui::SameLine(); + if (ImGui::Button("VIEW_DEBUG_LOCALS_ADD_READ_LOCAL"_T.data())) + { + local_debug local_read{}; + load_local_menu(selected_local, local_read); + if (local_read.local_value_type == LocalValueType::INT) + { + local_test.local_appendages.push_back({LocalAppendageType_ReadLocal, 0LL, 0ULL, selected_local}); + } + else + { + g_notification_service->push_warning("DEBUG_TAB_LOCALS"_T.data(), "VIEW_DEBUG_LOCALS_INVALID_TYPE"_T.data()); + } + } + ImGui::SameLine(); + if (ImGui::Button("VIEW_DEBUG_GLOBAL_CLEAR"_T.data())) + { + local_test.local_index = 0; + local_test.local_appendages.clear(); + } + ImGui::EndGroup(); ImGui::EndTabItem(); } } diff --git a/src/views/debug/view_debug_threads.cpp b/src/views/debug/view_debug_threads.cpp index 0392f441..6919239c 100644 --- a/src/views/debug/view_debug_threads.cpp +++ b/src/views/debug/view_debug_threads.cpp @@ -105,7 +105,7 @@ namespace big + std::string("VIEW_DEBUG_THREADS_STATE_1"_T.data()) + '\0' + std::string("VIEW_DEBUG_THREADS_STATE_2"_T.data()) + '\0' + std::string("VIEW_DEBUG_THREADS_STATE_3"_T.data()) + '\0' - + std::string("VIEW_DEBUG_THREADS_STATE_4"_T.data()); + + std::string("VIEW_DEBUG_THREADS_STATE_4"_T.data()) + '\0'; ImGui::Combo("VIEW_DEBUG_THREADS_STATE"_T.data(), (int*)&selected_thread->m_context.m_state, thread_states.c_str()); //Script Pointer ImGui::Text(std::format("{}: ", "VIEW_DEBUG_THREADS_SCRIPT_POINTER"_T).c_str());