mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2024-12-22 20:17:24 +08:00
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.
This commit is contained in:
parent
bc58716118
commit
eaeb54b728
@ -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<void()> 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<void()> cb = nullptr);
|
||||
|
||||
static void input_text(const std::string_view label, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function<void()> cb = nullptr);
|
||||
static bool input_text(const std::string_view label, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function<void()> cb = nullptr);
|
||||
static bool input_text(const std::string_view label, std::string& buf, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function<void()> cb = nullptr);
|
||||
|
||||
static bool selectable(const std::string_view, bool);
|
||||
static bool selectable(const std::string_view, bool, ImGuiSelectableFlags);
|
||||
|
@ -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<void()> cb)
|
||||
bool components::input_text(const std::string_view label, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag, std::function<void()> 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<void()> 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;
|
||||
}
|
||||
}
|
@ -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<int>("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<std::string, local> locals_with_names;
|
||||
for (auto& l : m_locals)
|
||||
{
|
||||
locals_with_names.insert(std::pair<std::string, local>(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";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
@ -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<local_offset> 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<int*>();
|
||||
m_internal_address_vector3 = actual_local.as<Vector3*>();
|
||||
|
||||
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<local> m_locals;
|
||||
bool m_running = false;
|
||||
};
|
||||
|
||||
inline locals_service g_locals_service{};
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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_debug_inner> 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<local_debug>();
|
||||
}
|
||||
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<int64_t*>();
|
||||
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<std::string, local_debug> list_locals()
|
||||
{
|
||||
auto json = get_locals_json();
|
||||
std::map<std::string, local_debug> 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<float*>(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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user