Skip to content

Commit

Permalink
UObjectHook: Add "Add Component", add ObjectProperty support
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Oct 22, 2023
1 parent 29a8e59 commit ef4598d
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 70 deletions.
220 changes: 150 additions & 70 deletions src/mods/UObjectHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <sdk/FField.hpp>
#include <sdk/FProperty.hpp>
#include <sdk/UFunction.hpp>
#include <sdk/AActor.hpp>
#include <sdk/threading/GameThreadWorker.hpp>

#include "UObjectHook.hpp"
Expand Down Expand Up @@ -226,94 +227,173 @@ void UObjectHook::on_draw_ui() {
if (ImGui::TreeNode(uclass_name.data())) {
for (const auto& object : objects) {
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();
ui_handle_object((sdk::UObject*)object);

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

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

auto funcs = super->get_children();
ImGui::TreePop();
}
}
}

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);
}
}
}
void UObjectHook::ui_handle_object(sdk::UObject* object) {
if (object == nullptr) {
return;
}

const auto uclass = object->get_class();

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::vector<sdk::FField*> sorted_fields{};
std::vector<sdk::UFunction*> sorted_functions{};

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();
});
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();

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 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);
}
}
}

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());
}
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();
});

ImGui::TreePop();
}
}
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();
});

ImGui::TreePop();
}
if (uclass->is_a(sdk::AActor::static_class())) {
static char component_add_name[256]{};

if (ImGui::InputText("Add Component", component_add_name, sizeof(component_add_name), ImGuiInputTextFlags_::ImGuiInputTextFlags_EnterReturnsTrue)) {
const auto component_c = sdk::find_uobject<sdk::UClass>(utility::widen(component_add_name));

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());
};
if (component_c != nullptr) {
GameThreadWorker::get().enqueue([=, this]() {
if (!this->exists(object)) {
return;
}

auto actor = (sdk::AActor*)object;
auto component = (sdk::UObject*)actor->add_component_by_class(component_c);

if (component != nullptr) {
if (component->get_class()->is_a(sdk::find_uobject<sdk::UClass>(L"Class /Script/Engine.SphereComponent"))) {
struct SphereRadiusParams {
float radius{};
};

auto params = SphereRadiusParams{};
params.radius = 100.f;

const auto fn = component->get_class()->find_function(L"SetSphereRadius");

if (fn != nullptr) {
component->process_event(fn, &params);
}

ImGui::TreePop();
}

struct {
bool hidden{false};
bool propagate{true};
} set_hidden_params{};

const auto fn = component->get_class()->find_function(L"SetHiddenInGame");

if (fn != nullptr) {
component->process_event(fn, &set_hidden_params);
}

actor->finish_add_component(component);

// Set component_add_name to empty
component_add_name[0] = '\0';
} else {
component_add_name[0] = 'e';
component_add_name[1] = 'r';
component_add_name[2] = 'r';
component_add_name[3] = '\0';
}
});
} else {
strcpy_s(component_add_name, "Nonexistent component");
}
}
}

ImGui::TreePop();
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();
}
}

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;
case "ObjectProperty"_fnv:
{
auto& value = *(sdk::UObject**)((uintptr_t)object + ((sdk::FProperty*)prop)->get_offset());

if (ImGui::TreeNode(utility::narrow(prop->get_field_name().to_string()).data())) {
ui_handle_object(value);
ImGui::TreePop();
}
}
break;
default:
ImGui::Text("%s %s", utility::narrow(propc->get_name().to_string()), utility::narrow(prop->get_field_name().to_string()).data());
};
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/mods/UObjectHook.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ class UObjectHook : public Mod {
return {};
}

bool exists(sdk::UObjectBase* object) const {
std::shared_lock _{m_mutex};
return m_objects.contains(object);
}

void activate();

protected:
Expand All @@ -37,6 +42,8 @@ class UObjectHook : public Mod {
void hook();
void add_new_object(sdk::UObjectBase* object);

void ui_handle_object(sdk::UObject* object);

static void* add_object(void* rcx, void* rdx, void* r8, void* r9);
static void* destructor(sdk::UObjectBase* object, void* rdx, void* r8, void* r9);

Expand Down

0 comments on commit ef4598d

Please sign in to comment.