Skip to content

Commit

Permalink
UObjectHook: Add basic field/function browser
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Oct 22, 2023
1 parent b8a19f0 commit 29a8e59
Showing 1 changed file with 114 additions and 2 deletions.
116 changes: 114 additions & 2 deletions src/mods/UObjectHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include <sdk/UObjectBase.hpp>
#include <sdk/UObjectArray.hpp>
#include <sdk/UClass.hpp>
#include <sdk/FField.hpp>
#include <sdk/FProperty.hpp>
#include <sdk/UFunction.hpp>
#include <sdk/threading/GameThreadWorker.hpp>

#include "UObjectHook.hpp"
Expand Down Expand Up @@ -141,8 +144,13 @@ void UObjectHook::on_draw_ui() {
}

if (ImGui::TreeNode("Objects by class")) {
static char filter[256]{};
ImGui::InputText("Filter", filter, sizeof(filter));

const bool filter_empty = std::string_view{filter}.empty();

const auto now = std::chrono::steady_clock::now();
bool needs_sort = now - m_last_sort_time >= std::chrono::seconds(1) || m_sorted_classes.empty();
bool needs_sort = true;

if (sorting_task.valid()) {
// Check if the sorting task is finished
Expand Down Expand Up @@ -182,18 +190,122 @@ void UObjectHook::on_draw_ui() {
m_last_sort_time = now;
}

const auto wide_filter = utility::widen(filter);

for (auto uclass : m_sorted_classes) {
const auto& objects = m_objects_by_class[uclass];

if (objects.empty()) {
continue;
}

if (!m_meta_objects.contains(uclass)) {
continue;
}

const auto uclass_name = utility::narrow(m_meta_objects[uclass]->full_name);
bool valid = true;

if (!filter_empty) {
valid = false;

for (auto super = (sdk::UStruct*)uclass; super; super = super->get_super_struct()) {
if (auto it = m_meta_objects.find(super); it != m_meta_objects.end()) {
if (it->second->full_name.find(wide_filter) != std::wstring::npos) {
valid = true;
break;
}
}
}
}

if (!valid) {
continue;
}

if (ImGui::TreeNode(uclass_name.data())) {
for (const auto& object : objects) {
ImGui::Text("%s", utility::narrow(m_meta_objects[object]->full_name).data());
if (ImGui::TreeNode(utility::narrow(m_meta_objects[object]->full_name).data())) {
std::vector<sdk::FField*> sorted_fields{};
std::vector<sdk::UFunction*> sorted_functions{};

const auto ufunction_t = sdk::UFunction::static_class();

for (auto super = (sdk::UStruct*)uclass; super != nullptr; super = super->get_super_struct()) {
auto props = super->get_child_properties();

for (auto prop = props; prop != nullptr; prop = prop->get_next()) {
sorted_fields.push_back(prop);
}

auto funcs = super->get_children();

for (auto func = funcs; func != nullptr; func = func->get_next()) {
if (func->get_class()->is_a(ufunction_t)) {
sorted_functions.push_back((sdk::UFunction*)func);
}
}
}

std::sort(sorted_fields.begin(), sorted_fields.end(), [](sdk::FField* a, sdk::FField* b) {
return a->get_field_name().to_string() < b->get_field_name().to_string();
});

std::sort(sorted_functions.begin(), sorted_functions.end(), [](sdk::UFunction* a, sdk::UFunction* b) {
return a->get_fname().to_string() < b->get_fname().to_string();
});

if (ImGui::TreeNode("Functions")) {
for (auto func : sorted_functions) {
/*if (ImGui::Button(utility::narrow(func->get_class()->get_fname().to_string()).data())) {
func->process_event(object, nullptr);
}*/

if (ImGui::TreeNode(utility::narrow(func->get_fname().to_string()).data())) {
auto parameters = func->get_child_properties();

for (auto param = parameters; param != nullptr; param = param->get_next()) {
ImGui::Text("%s %s", utility::narrow(param->get_class()->get_name().to_string()), utility::narrow(param->get_field_name().to_string()).data());
}

ImGui::TreePop();
}
}

ImGui::TreePop();
}

for (auto prop : sorted_fields) {
auto propc = prop->get_class();

const auto propc_type = utility::narrow(propc->get_name().to_string());

switch (utility::hash(propc_type)) {
case "FloatProperty"_fnv:
{
auto& value = *(float*)((uintptr_t)object + ((sdk::FProperty*)prop)->get_offset());
ImGui::DragFloat(utility::narrow(prop->get_field_name().to_string()).data(), &value, 0.01f);
}
break;
case "IntProperty"_fnv:
{
auto& value = *(int32_t*)((uintptr_t)object + ((sdk::FProperty*)prop)->get_offset());
ImGui::DragInt(utility::narrow(prop->get_field_name().to_string()).data(), &value, 1);
}
break;
case "BoolProperty"_fnv:
{
auto& value = *(bool*)((uintptr_t)object + ((sdk::FProperty*)prop)->get_offset());
ImGui::Checkbox(utility::narrow(prop->get_field_name().to_string()).data(), &value);
}
break;
default:
ImGui::Text("%s %s", utility::narrow(propc->get_name().to_string()), utility::narrow(prop->get_field_name().to_string()).data());
};
}

ImGui::TreePop();
}
}

ImGui::TreePop();
Expand Down

0 comments on commit 29a8e59

Please sign in to comment.