mirror of
https://github.com/YimMenu/YimMenuV2.git
synced 2026-10-10 03:43:15 +08:00
feat(invoker): add a native invoker (#11)
This commit is contained in:
+2
-1
@@ -1 +1,2 @@
|
||||
build/
|
||||
build/
|
||||
.vs
|
||||
@@ -7,6 +7,7 @@ include(cmake/async-logger.cmake)
|
||||
include(cmake/imgui.cmake)
|
||||
include(cmake/json.cmake)
|
||||
include(cmake/minhook.cmake)
|
||||
include(cmake/gtav-classes.cmake)
|
||||
|
||||
# source
|
||||
set(SRC_DIR "${PROJECT_SOURCE_DIR}/src")
|
||||
@@ -25,6 +26,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
"${SRC_DIR}"
|
||||
"${imgui_SOURCE_DIR}"
|
||||
"${minhook_SOURCE_DIR}/include"
|
||||
"${gtav_classes_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
message(STATUS "Setting up linked libraries")
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"variables": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
gtav_classes
|
||||
GIT_REPOSITORY https://github.com/maybegreat48/GTAV-Classes.git
|
||||
GIT_TAG fb7ec7fe0a8ac08823ab7a0a2e68c08b027fce2f
|
||||
GIT_PROGRESS TRUE
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
)
|
||||
message("GTAV-Classes")
|
||||
if(NOT gtav_classes_POPULATED)
|
||||
FetchContent_Populate(gtav_classes)
|
||||
endif()
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,113 @@
|
||||
import json
|
||||
|
||||
crossmap = {}
|
||||
natives = {}
|
||||
current_idx = 0
|
||||
crossmap_hash_list = []
|
||||
|
||||
class Arg:
|
||||
def __init__(self, name: str, type: str):
|
||||
self.name = name
|
||||
self.type = type.replace("BOOL", "bool").replace("Any*", "void*")
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.type) + " " + str(self.name)
|
||||
|
||||
class NativeFunc:
|
||||
def __init__(self, namespace: str, name: str, hash: int, args: list[dict], return_type: str):
|
||||
self.namespace = namespace
|
||||
self.name = name
|
||||
self.hash = hash
|
||||
self.args: list[Arg] = []
|
||||
self.return_type = return_type.replace("BOOL", "bool").replace("Any*", "void*")
|
||||
self.native_index = -1
|
||||
|
||||
for arg in args:
|
||||
self.args.append(Arg(arg["name"], arg["type"]))
|
||||
|
||||
def get_native_def_str(self) -> str:
|
||||
assert self.native_index != -1
|
||||
|
||||
param_decl = ""
|
||||
param_pass = ""
|
||||
if len(self.args) > 0:
|
||||
for arg in self.args:
|
||||
param_decl += str(arg) + ", "
|
||||
param_pass += arg.name + ", "
|
||||
param_decl = param_decl[:-2]
|
||||
param_pass = param_pass[:-2]
|
||||
|
||||
return f"FORCEINLINE constexpr {self.return_type} {self.name}({param_decl}) {{ return YimMenu::NativeInvoker::Invoke<{self.native_index}, {self.return_type}>({param_pass}); }}"
|
||||
|
||||
class CrossmapEntry:
|
||||
def __init__(self, translated_hash: int):
|
||||
self.hash = translated_hash
|
||||
self.native_index = -1
|
||||
|
||||
def load_crossmap_data():
|
||||
global crossmap
|
||||
|
||||
data = open("crossmap.txt").readlines()
|
||||
for item in data:
|
||||
translation = item.split(",")
|
||||
crossmap[int(translation[0], 16)] = CrossmapEntry(int(translation[1], 16))
|
||||
|
||||
def load_natives_data():
|
||||
global natives
|
||||
|
||||
data = json.load(open("natives.json"))
|
||||
for ns, natives_list in data.items():
|
||||
natives[ns] = []
|
||||
for hash_str, native_data in natives_list.items():
|
||||
natives[ns].append(NativeFunc(ns, native_data["name"], int(hash_str, 16), native_data["params"], native_data["return_type"]))
|
||||
|
||||
def allocate_indices():
|
||||
global current_idx, crossmap_hash_list
|
||||
|
||||
for _, n in natives.items():
|
||||
for native in n:
|
||||
hash = native.hash
|
||||
if hash in crossmap:
|
||||
crossmap[hash].native_index = current_idx
|
||||
native.native_index = current_idx
|
||||
crossmap_hash_list.append(crossmap[hash].hash)
|
||||
current_idx += 1
|
||||
|
||||
|
||||
def write_crossmap_header():
|
||||
open("Crossmap.hpp", "w+").write(f"""#pragma once
|
||||
#include <script/scrNativeHandler.hpp>
|
||||
|
||||
namespace YimMenu
|
||||
{{
|
||||
constexpr std::array<rage::scrNativeHash, {len(crossmap_hash_list)}> g_Crossmap = {{{",".join([f"0x{x:X}" for x in crossmap_hash_list])}}};
|
||||
}}
|
||||
""")
|
||||
|
||||
def write_natives_header():
|
||||
natives_buf = ""
|
||||
|
||||
for ns, nvs in natives.items():
|
||||
natives_buf += f"namespace {ns}\n{{\n"
|
||||
for nat_data in nvs:
|
||||
if nat_data.native_index == -1:
|
||||
continue
|
||||
|
||||
natives_buf += f"\t{nat_data.get_native_def_str()}\n"
|
||||
natives_buf += "}\n\n"
|
||||
|
||||
natives_buf = natives_buf[:-2]
|
||||
open("../Natives.hpp", "w+").write(f"""#pragma once
|
||||
#include "invoker/Invoker.hpp"
|
||||
|
||||
// clang-format off
|
||||
{natives_buf}
|
||||
// clang-format on
|
||||
""")
|
||||
|
||||
if __name__ == "__main__":
|
||||
load_crossmap_data()
|
||||
load_natives_data()
|
||||
allocate_indices()
|
||||
write_crossmap_header()
|
||||
write_natives_header()
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "Invoker.hpp"
|
||||
|
||||
#include "Crossmap.hpp"
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
void NativeInvoker::CacheHandlers()
|
||||
{
|
||||
if (m_AreHandlersCached)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < g_Crossmap.size(); i++)
|
||||
{
|
||||
m_Handlers[i] = Pointers.GetNativeHandler(Pointers.NativeRegistrationTable, g_Crossmap[i]);
|
||||
}
|
||||
|
||||
m_AreHandlersCached = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
#include "Crossmap.hpp"
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
|
||||
#include <script/scrNativeHandler.hpp>
|
||||
#include <script/types.hpp>
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
class CustomCallContext : public rage::scrNativeCallContext
|
||||
{
|
||||
public:
|
||||
constexpr CustomCallContext()
|
||||
{
|
||||
m_return_value = &m_return_stack[0];
|
||||
m_args = &m_arg_stack[0];
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t m_return_stack[10];
|
||||
uint64_t m_arg_stack[40];
|
||||
};
|
||||
|
||||
class NativeInvoker
|
||||
{
|
||||
static inline rage::scrNativeHandler m_Handlers[g_Crossmap.size()];
|
||||
static inline bool m_AreHandlersCached{false};
|
||||
|
||||
public:
|
||||
constexpr NativeInvoker(){};
|
||||
|
||||
constexpr void BeginCall()
|
||||
{
|
||||
m_CallContext.reset();
|
||||
}
|
||||
|
||||
template<int index, bool fix_vectors>
|
||||
constexpr void EndCall()
|
||||
{
|
||||
// TODO: try to get rid of this
|
||||
if (!m_AreHandlersCached)
|
||||
CacheHandlers();
|
||||
|
||||
m_Handlers[index](&m_CallContext);
|
||||
if constexpr (fix_vectors)
|
||||
Pointers.FixVectors(&m_CallContext);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr void PushArg(T&& value)
|
||||
{
|
||||
m_CallContext.push_arg(std::forward<T>(value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T& GetReturnValue()
|
||||
{
|
||||
return *m_CallContext.get_return_value<T>();
|
||||
}
|
||||
|
||||
public:
|
||||
static void CacheHandlers();
|
||||
|
||||
template<int index, typename Ret, typename... Args>
|
||||
static constexpr FORCEINLINE Ret Invoke(Args&&... args)
|
||||
{
|
||||
NativeInvoker invoker{};
|
||||
|
||||
invoker.BeginCall();
|
||||
(invoker.PushArg(std::forward<Args>(args)), ...);
|
||||
invoker.EndCall<index, std::is_same_v<Ret, Vector3>>();
|
||||
|
||||
if constexpr (!std::is_same_v<Ret, void>)
|
||||
{
|
||||
return invoker.GetReturnValue<Ret>();
|
||||
}
|
||||
}
|
||||
|
||||
CustomCallContext m_CallContext{};
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -31,11 +31,22 @@ namespace YimMenu
|
||||
|
||||
constexpr auto debugTrap = Pattern<"48 83 EC 28 33 C9 FF 15 ? ? ? ? 45 33 C9">("DebugTrap");
|
||||
scanner.Add(debugTrap, [this](PointerCalculator ptr) {
|
||||
BytePatch::Make(ptr.As<void*>(), std::to_array({ 0xC3, 0x90, 0x90, 0x90 }))->Apply();
|
||||
BytePatch::Make(ptr.As<void*>(), std::to_array({0xC3, 0x90, 0x90, 0x90}))->Apply();
|
||||
|
||||
UnhookWindowsHookEx(*ptr.Add(45).Rip().As<HHOOK*>());
|
||||
});
|
||||
|
||||
constexpr auto nativeHandlersPtrn = Pattern<"48 8D 0D ? ? ? ? 48 8B 14 FA E8 ? ? ? ? 48 85 C0 75 0A">("NativeHandlers");
|
||||
scanner.Add(nativeHandlersPtrn, [this](PointerCalculator ptr) {
|
||||
NativeRegistrationTable = ptr.Add(3).Rip().As<void*>();
|
||||
GetNativeHandler = ptr.Add(12).Rip().As<Functions::GetNativeHandler>();
|
||||
});
|
||||
|
||||
constexpr auto fixVectorsPtrn = Pattern<"83 79 18 00 48 8B D1 74 4A FF 4A 18 48 63 4A 18 48 8D 41 04 48 8B 4C CA">("FixVectors");
|
||||
scanner.Add(fixVectorsPtrn, [this](PointerCalculator ptr) {
|
||||
FixVectors = ptr.As<Functions::FixVectors>();
|
||||
});
|
||||
|
||||
if (!scanner.Scan())
|
||||
{
|
||||
LOG(FATAL) << "Some patterns could not be found, unloading.";
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
#include <script/scrNativeHandler.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
namespace Functions
|
||||
{
|
||||
using GetNativeHandler = rage::scrNativeHandler (*)(void* registration_table, rage::scrNativeHash hash);
|
||||
using FixVectors = void (*)(rage::scrNativeCallContext* call_ctx);
|
||||
}
|
||||
|
||||
struct PointerData
|
||||
{
|
||||
IDXGISwapChain** SwapChain;
|
||||
HWND Hwnd;
|
||||
WNDPROC WndProc;
|
||||
std::int64_t** ScriptGlobals;
|
||||
void* NativeRegistrationTable;
|
||||
Functions::GetNativeHandler GetNativeHandler;
|
||||
Functions::FixVectors FixVectors;
|
||||
};
|
||||
|
||||
struct Pointers : PointerData
|
||||
|
||||
+2
-1
@@ -4,9 +4,9 @@
|
||||
#include "core/memory/ModuleMgr.hpp"
|
||||
#include "core/renderer/Renderer.hpp"
|
||||
#include "game/frontend/GUI.hpp"
|
||||
#include "game/gta/Natives.hpp"
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
DWORD Main(void*)
|
||||
@@ -28,6 +28,7 @@ namespace YimMenu
|
||||
while (g_Running)
|
||||
{
|
||||
std::this_thread::sleep_for(100ms);
|
||||
LOG(INFO) << ENTITY::GET_ENTITY_HEALTH(PLAYER::PLAYER_PED_ID());
|
||||
}
|
||||
|
||||
unload:
|
||||
|
||||
Reference in New Issue
Block a user