Skip to content

Commit

Permalink
Janky support for executing commands
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed Jun 1, 2023
1 parent 17ac30d commit e3684cd
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 3 deletions.
80 changes: 80 additions & 0 deletions shared/sdk/CVar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,85 @@ float IConsoleVariable::GetFloat() {
return func(this);
}

struct FakeOutputDevice {
virtual ~FakeOutputDevice() {};
virtual void Serialize(const wchar_t* text, size_t verbosity, void* category, void* r9) {
spdlog::info("{}", utility::narrow(text));
};
virtual size_t a2(void* rcx, void* rdx, void* r8, void* r9) {return 0;}
virtual size_t a3(void* rcx, void* rdx, void* r8, void* r9) {return 0;}
virtual size_t a4(void* rcx, void* rdx, void* r8, void* r9) {return 0;}
virtual size_t a5(void* rcx, void* rdx, void* r8, void* r9) {return 0;}
virtual size_t a6(void* rcx, void* rdx, void* r8, void* r9) {return 0;}
virtual size_t a7(void* rcx, void* rdx, void* r8, void* r9) {return 0;}
virtual size_t a8(void* rcx, void* rdx, void* r8, void* r9) {return 0;}
virtual size_t a9(void* rcx, void* rdx, void* r8, void* r9) {return 0;}
virtual size_t a10(void* rcx, void* rdx, void* r8, void* r9) {return 0;}

private:
char unk_padding[0x100]{}; // just in case
};

bool IConsoleCommand::Execute(const std::wstring& args) {
return Execute(args.c_str());
}

bool IConsoleCommand::Execute(const wchar_t* args) {
std::vector<std::wstring> args_vec{};
std::wstringstream ss{};

// Split by spaces
while(ss.good()) {
std::wstring substr{};
std::getline(ss, substr, L' ');
args_vec.push_back(substr);
}

return Execute(args_vec);
}

bool IConsoleCommand::Execute(const std::vector<std::wstring>& args) {
std::vector<sdk::TArray<wchar_t>> args_vec{};

for (const auto& arg : args) {
auto& arr = args_vec.emplace_back();

arr.data = (wchar_t*)arg.c_str();
arr.count = arg.size();
arr.capacity = arg.size();
}

FakeOutputDevice fake_output_device{};
sdk::TArray<sdk::TArray<wchar_t>> fake_args_vec{};

fake_args_vec.data = args_vec.data();
fake_args_vec.count = args_vec.size();
fake_args_vec.capacity = args_vec.size();

// TODO: Pass in world...
return execute_internal(fake_args_vec, nullptr, &fake_output_device);
}

bool IConsoleCommand::execute_internal(const sdk::TArray<sdk::TArray<wchar_t>>& args, void* world, void* output_device) {
const auto info = locate_vtable_indices();

if (!info) {
static bool once = true;

if (once) {
SPDLOG_ERROR("s_execute_vtable_index is not initialized! Cannot call IConsoleCommand::execute_internal()!");
once = false;
}

return false;
}

using ExecuteFn = bool(*)(IConsoleCommand*, sdk::TArray<sdk::TArray<wchar_t>> const*, void*, void*);
const auto func = (*(ExecuteFn**)this)[info->execute_index];

return func(this, &args, world, output_device);
}

std::optional<IConsoleObject::VtableInfo> IConsoleObject::locate_vtable_indices() {
std::scoped_lock _{ s_vtable_mutex };

Expand Down Expand Up @@ -817,6 +896,7 @@ std::optional<IConsoleObject::VtableInfo> IConsoleObject::locate_vtable_indices(

vtable_info.as_console_command_index = destructor_index - 1;
vtable_info.release_index = destructor_index;
vtable_info.execute_index = destructor_index + 1;
vtable_info.set_vtable_index = destructor_index + 1;
auto potential_get_int_index = vtable_info.set_vtable_index + 1;

Expand Down
10 changes: 9 additions & 1 deletion shared/sdk/CVar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <spdlog/spdlog.h>
#include <windows.h>

#include "TArray.hpp"

namespace sdk {
template <typename T>
struct TConsoleVariableData {
Expand Down Expand Up @@ -79,6 +81,7 @@ struct IConsoleObject {
struct VtableInfo {
uint32_t as_console_command_index;
uint32_t release_index;
uint32_t execute_index;
uint32_t set_vtable_index;
uint32_t get_int_vtable_index;
uint32_t get_float_vtable_index;
Expand All @@ -91,7 +94,12 @@ struct IConsoleObject {
};

struct IConsoleCommand : IConsoleObject {
// TODO: Implement
bool Execute(const wchar_t* args);
bool Execute(const std::wstring& args);
bool Execute(const std::vector<std::wstring>& args);

protected:
bool execute_internal(const sdk::TArray<sdk::TArray<wchar_t>>& args, void* world, void* output_device);
};

struct IConsoleVariable : IConsoleObject {
Expand Down
10 changes: 10 additions & 0 deletions shared/sdk/TArray.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

namespace sdk {
template<typename T>
struct TArray {
T* data{nullptr};
int32_t count{0};
int32_t capacity{0};
};
}
16 changes: 14 additions & 2 deletions src/mods/vr/CVarManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ void CVarManager::display_console() {
description = utility::narrow(help_string);
}
} catch(...) {
description = "Failed to get description.";
}

m_console.autocomplete.emplace_back(AutoComplete{
Expand Down Expand Up @@ -295,13 +296,25 @@ void CVarManager::display_console() {
// Execute the command.
if (args.size() >= 2) {
auto object = console_manager->find(utility::widen(args[0]));
const auto is_command = object != nullptr && object->AsCommand() != nullptr;

if (object != nullptr && object->AsCommand() == nullptr) {
if (object != nullptr && !is_command) {
auto var = (sdk::IConsoleVariable*)object;

GameThreadWorker::get().enqueue([var, value = utility::widen(args[1])]() {
var->Set(value.c_str());
});
} else if (object != nullptr && is_command) {
auto command = (sdk::IConsoleCommand*)object;

std::vector<std::wstring> widened_args{};
for (auto i = 1; i < args.size(); ++i) {
widened_args.push_back(utility::widen(args[i]));
}

GameThreadWorker::get().enqueue([command, widened_args]() {
command->Execute(widened_args);
});
}
}

Expand All @@ -314,7 +327,6 @@ void CVarManager::display_console() {

// Display autocomplete
if (!m_console.autocomplete.empty()) {
//ImGui::TextUnformatted(m_console.last_autocomplete_string.c_str());
// Create a table of all the possible commands.
if (ImGui::BeginTable("##UEVRAutocomplete", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) {
ImGui::TableSetupColumn("Command", ImGuiTableColumnFlags_WidthFixed, 300.0f);
Expand Down

0 comments on commit e3684cd

Please sign in to comment.