mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2025-01-03 16:13:36 +08:00
Locals editor (#1211)
This commit is contained in:
parent
5ed00303bf
commit
a6dc40b890
126
src/services/locals/locals_service.cpp
Normal file
126
src/services/locals/locals_service.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include "locals_service.hpp"
|
||||
|
||||
#include "core/data/all_script_names.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "fiber_pool.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)
|
||||
{
|
||||
for (auto s : all_script_names)
|
||||
if (script_name == s)
|
||||
return true;
|
||||
bool script_exists = false;
|
||||
g_fiber_pool->queue_job([&] {script_exists = SCRIPT::DOES_SCRIPT_EXIST(script_name.data());});
|
||||
return script_exists;
|
||||
}
|
||||
|
||||
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};
|
||||
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"];
|
||||
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;
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
104
src/services/locals/locals_service.hpp
Normal file
104
src/services/locals/locals_service.hpp
Normal file
@ -0,0 +1,104 @@
|
||||
#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* m_internal_address;
|
||||
|
||||
local(const char* script_thread_name, const char* name, const int base_address, const bool freeze, const int (*offsets)[2], int offset_count)
|
||||
{
|
||||
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]));
|
||||
|
||||
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*>();
|
||||
|
||||
return m_internal_address;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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{};
|
||||
}
|
@ -1,11 +1,183 @@
|
||||
#include "gui/components/components.hpp"
|
||||
#include "services/locals/locals_service.hpp"
|
||||
#include "view_debug.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
||||
void render_local_creator_popup_content()
|
||||
{
|
||||
static int base_address = 0;
|
||||
static bool freeze = false;
|
||||
static char name[200] = "";
|
||||
static char script_thread_name[200] = "";
|
||||
static int(*offsets)[2] = nullptr;
|
||||
static int offset_count = 0;
|
||||
static int previous_offset_count = 0;
|
||||
components::input_text_with_hint("##local_name", "Name", name, sizeof(name));
|
||||
components::input_text_with_hint("##local_script_thread_name", "Script thread", script_thread_name, sizeof(script_thread_name));
|
||||
ImGui::Text("Base address");
|
||||
ImGui::InputInt("##local_base_address", &base_address);
|
||||
ImGui::Text("Offsetcount");
|
||||
ImGui::InputInt("##modal_offset_count", &offset_count);
|
||||
|
||||
if (offset_count < 0)
|
||||
offset_count = 0;
|
||||
else if (offset_count > 10)
|
||||
offset_count = 10;
|
||||
|
||||
if (offset_count != previous_offset_count)
|
||||
{
|
||||
int(*new_offsets)[2] = new int[offset_count][2]{0};
|
||||
memcpy(new_offsets, offsets, sizeof(int) * std::min(offset_count, previous_offset_count) * 2);
|
||||
|
||||
delete[] offsets;
|
||||
offsets = new_offsets;
|
||||
|
||||
previous_offset_count = offset_count;
|
||||
}
|
||||
|
||||
ImGui::PushItemWidth(320.f);
|
||||
for (int i = 0; i < offset_count; i++)
|
||||
{
|
||||
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();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
static auto reset_values = []() -> void {
|
||||
strcpy(name, "");
|
||||
freeze = false;
|
||||
delete[] offsets;
|
||||
offsets = nullptr;
|
||||
offset_count = 0;
|
||||
previous_offset_count = 0;
|
||||
};
|
||||
|
||||
if (components::button("CANCEL"_T))
|
||||
{
|
||||
reset_values();
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (components::button("SAVE"_T))
|
||||
{
|
||||
if (locals_service::does_script_exist(script_thread_name))
|
||||
{
|
||||
auto new_local = local(script_thread_name, name, base_address, freeze, offsets, offset_count);
|
||||
g_locals_service.m_locals.push_back(new_local);
|
||||
|
||||
reset_values();
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_notification_service->push_error("Locals editor", "Script does not exist");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (components::button("Add local"))
|
||||
{
|
||||
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::Text("%s : %s", local_.m_name, local_.m_script_thread_name);
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
char offsetschain[200] = "";
|
||||
strcat(offsetschain, std::to_string(local_.m_base_address).data());
|
||||
for (auto o : local_.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());
|
||||
}
|
||||
ImGui::Text(offsetschain);
|
||||
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)
|
||||
{
|
||||
ImGui::Text("Value");
|
||||
ImGui::SetNextItemWidth(200);
|
||||
if (ImGui::InputInt("##local_value", local_.m_internal_address))
|
||||
{
|
||||
local_.m_value = *local_.m_internal_address;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("Freeze", &local_.m_freeze))
|
||||
local_.m_freeze_value = *local_.m_internal_address;
|
||||
|
||||
if (local_.m_freeze)
|
||||
*local_.m_internal_address = local_.m_freeze_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (components::button("Fetch"))
|
||||
{
|
||||
local_.fetch_local_pointer();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
ImGui::Text("%s isn't running", local_.m_script_thread_name);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if (components::button("Delete"))
|
||||
std::erase_if(g_locals_service.m_locals, [local_](local l) {
|
||||
return l.get_id() == local_.get_id();
|
||||
});
|
||||
|
||||
ImGui::PopID();
|
||||
ImGui::Separator();
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user