Removed StackWalker and replaced it with g3log exception handling.

Updated natives for 1.50.
Added settings JSON implementation.
Refactored spawn vehicle bypass to not crash. (removed VMT hook)
This commit is contained in:
gir489 2020-02-22 18:37:42 -05:00
parent 87599327c5
commit 01d48cd314
33 changed files with 13323 additions and 12123 deletions

6
.gitmodules vendored
View File

@ -14,7 +14,7 @@
path = vendor/ImGui path = vendor/ImGui
url = https://github.com/ocornut/imgui url = https://github.com/ocornut/imgui
ignore = dirty ignore = dirty
[submodule "vendor/StackWalker"] [submodule "vendor/g3log"]
path = vendor/StackWalker path = vendor/g3log
url = https://github.com/JochenKalmbach/StackWalker url = https://github.com/KjellKod/g3log.git
ignore = dirty ignore = dirty

BIN
BigBaseV2.lnk Normal file

Binary file not shown.

View File

@ -47,10 +47,11 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <StackWalker.h>
#include "logger.hpp" #include "logger.hpp"
#include "settings.h"
namespace big namespace big
{ {
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -62,16 +63,4 @@ namespace big
inline HANDLE g_main_thread{}; inline HANDLE g_main_thread{};
inline DWORD g_main_thread_id{}; inline DWORD g_main_thread_id{};
inline std::atomic_bool g_running{ true }; inline std::atomic_bool g_running{ true };
struct stackwalker : public StackWalker
{
using StackWalker::StackWalker;
void OnOutput(LPCSTR szText) override
{
g_logger->raw(log_color::red, szText);
}
};
inline stackwalker g_stackwalker;
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,11 +2,11 @@
#include "detour_hook.hpp" #include "detour_hook.hpp"
#include "logger.hpp" #include "logger.hpp"
#include "memory/handle.hpp" #include "memory/handle.hpp"
#include <MinHook.h> #include <..\MinHook\include\MinHook.h>
namespace big namespace big
{ {
detour_hook::detour_hook(std::string name, void *target, void *detour) : detour_hook::detour_hook(std::string name, void* target, void* detour) :
m_name(std::move(name)), m_name(std::move(name)),
m_target(target), m_target(target),
m_detour(detour) m_detour(detour)
@ -15,12 +15,11 @@ namespace big
if (auto status = MH_CreateHook(m_target, m_detour, &m_original); status == MH_OK) if (auto status = MH_CreateHook(m_target, m_detour, &m_original); status == MH_OK)
{ {
LOG_INFO("Created hook '{}'.", m_name); LOG(INFO_TO_FILE) << "Created hook '" << m_name << "'.";
} }
else else
{ {
throw std::runtime_error(fmt::format("Failed to create hook '{}' at 0x{:X} (error: {})", m_name, reinterpret_cast<std::uintptr_t>(m_target), MH_StatusToString(status))); throw std::runtime_error(fmt::format("Failed to create hook '{}' at 0x{:X} (error: {})", m_name, reinterpret_cast<std::uintptr_t>(m_target), MH_StatusToString(status)));
} }
} }
@ -31,14 +30,14 @@ namespace big
MH_RemoveHook(m_target); MH_RemoveHook(m_target);
} }
LOG_INFO("Removed hook '{}',", m_name); LOG(INFO) << "Removed hook '" << m_name << "'.";
} }
void detour_hook::enable() void detour_hook::enable()
{ {
if (auto status = MH_EnableHook(m_target); status == MH_OK) if (auto status = MH_EnableHook(m_target); status == MH_OK)
{ {
LOG_INFO("Enabled hook '{}'.", m_name); LOG(INFO_TO_FILE) << "Enabled hook '" << m_name << "'.";
} }
else else
{ {
@ -50,15 +49,15 @@ namespace big
{ {
if (auto status = MH_DisableHook(m_target); status == MH_OK) if (auto status = MH_DisableHook(m_target); status == MH_OK)
{ {
LOG_INFO("Disabled hook '{}'", m_name); LOG(INFO_TO_FILE) << "Disabled hook '" << m_name << "'.";
} }
else else
{ {
LOG_ERROR("Failed to disable hook '{}'.", m_name); LOG(WARNING) << "Failed to disable hook '" << m_name << "'.";
} }
} }
DWORD exp_handler(PEXCEPTION_POINTERS exp, std::string const &name) DWORD exp_handler(PEXCEPTION_POINTERS exp, std::string const& name)
{ {
return exp->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION return exp->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION
? EXCEPTION_EXECUTE_HANDLER ? EXCEPTION_EXECUTE_HANDLER

View File

@ -14,7 +14,11 @@ namespace big
{ {
while (true) while (true)
{ {
run_tick(); TRY_CLAUSE
{
run_tick();
}
EXCEPT_CLAUSE
script::get_current()->yield(); script::get_current()->yield();
} }
} }

View File

@ -78,6 +78,8 @@ using Any = std::uint32_t;
using Hash = std::uint32_t; using Hash = std::uint32_t;
using Entity = std::int32_t; using Entity = std::int32_t;
using Player = std::int32_t; using Player = std::int32_t;
using FireId = std::int32_t;
using Interior = std::int32_t;
using Ped = Entity; using Ped = Entity;
using Vehicle = Entity; using Vehicle = Entity;
using Cam = std::int32_t; using Cam = std::int32_t;

View File

@ -12,7 +12,8 @@
#include "script.hpp" #include "script.hpp"
#include <imgui.h> #include <imgui.h>
#include <StackWalker.h>
#include "gui/base_tab.h"
namespace big namespace big
{ {
@ -96,56 +97,17 @@ namespace big
void gui::dx_on_tick() void gui::dx_on_tick()
{ {
if (ImGui::Begin("BigBaseV2")) TRY_CLAUSE
{ {
static bool demo_bool = true; if (ImGui::Begin("BigBaseV2"))
static int demo_int = 1;
static float demo_float = 1.f;
static const char *demo_combo[]
{ {
"One", ImGui::BeginTabBar("tabbar");
"Two", base_tab::render_base_tab();
"Three" ImGui::EndTabBar();
};
static int demo_combo_pos = 0;
ImGui::Checkbox("Bool", &demo_bool);
ImGui::SliderInt("Int", &demo_int, 0, 10);
ImGui::SliderFloat("Float", &demo_float, 0.f, 10.f);
ImGui::Combo("Combo", &demo_combo_pos, demo_combo, sizeof(demo_combo) / sizeof(*demo_combo));
if (ImGui::Button("Spawn a vehicle"))
{
g_fiber_pool->queue_job([]
{
constexpr auto hash = RAGE_JOAAT("adder");
while (!STREAMING::HAS_MODEL_LOADED(hash))
{
STREAMING::REQUEST_MODEL(hash);
script::get_current()->yield();
}
auto pos = ENTITY::GET_ENTITY_COORDS(PLAYER::PLAYER_PED_ID(), true);
auto vehicle = VEHICLE::CREATE_VEHICLE(hash, pos.x, pos.y, pos.z, 0.f, true, true);
if (*g_pointers->m_is_session_started)
{
DECORATOR::DECOR_SET_INT(vehicle, "MPBitset", 0);
}
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);
});
}
ImGui::Separator();
if (ImGui::Button("Unload"))
{
g_running = false;
} }
ImGui::End();
} }
ImGui::End(); EXCEPT_CLAUSE
} }
void gui::script_init() void gui::script_init()
@ -154,10 +116,14 @@ namespace big
void gui::script_on_tick() void gui::script_on_tick()
{ {
if (g_gui.m_opened) TRY_CLAUSE
{ {
CONTROLS::DISABLE_ALL_CONTROL_ACTIONS(0); if (g_gui.m_opened)
{
PAD::DISABLE_ALL_CONTROL_ACTIONS(0);
}
} }
EXCEPT_CLAUSE
} }
void gui::script_func() void gui::script_func()

View File

@ -0,0 +1,99 @@
#include "common.hpp"
#include "base_tab.h"
#include "imgui.h"
#include "script.hpp"
#include "fiber_pool.hpp"
#include "natives.hpp"
#include "gta_util.hpp"
namespace big
{
void base_tab::render_base_tab()
{
if (ImGui::BeginTabItem("Test"))
{
static const char* demo_combo[]
{
"One",
"Two",
"Three"
};
static double min = 0., max = 10.;
//If you want to add a new option, you have to first declare it in settings.h's default_options, otherwise, this code will crash when trying to access an option that does not exist in memory.
if (ImGui::Checkbox("Bool", g_settings.options["demo bool"].get<bool*>()))
g_settings.save();
if (ImGui::SliderInt("Int", (PINT)g_settings.options["demo int"].get<int64_t*>(), 0, 10))
g_settings.save();
if (ImGui::SliderScalar("Double", ImGuiDataType_Double, g_settings.options["demo double"].get<double*>(), &min, &max)) //JSON does not describe rational numbers as integer/float/double/etc types, it is just "number". See: https://nlohmann.github.io/json/
g_settings.save();
ImGui::Combo("Combo", (PINT)g_settings.options["demo combo"].get<int64_t*>(), demo_combo, sizeof(demo_combo) / sizeof(*demo_combo));
if (ImGui::Button("Spawn an Adder"))
{
QUEUE_JOB_BEGIN_CLAUSE()
{
constexpr auto hash = RAGE_JOAAT("adder");
while (!STREAMING::HAS_MODEL_LOADED(hash))
{
STREAMING::REQUEST_MODEL(hash);
script::get_current()->yield();
}
auto pos = ENTITY::GET_ENTITY_COORDS(PLAYER::PLAYER_PED_ID(), true);
while (!STREAMING::HAS_MODEL_LOADED(hash))
{
STREAMING::REQUEST_MODEL(hash);
script::get_current()->yield();
}
*(unsigned short*)g_pointers->m_model_spawn_bypass = 0x9090;
Vehicle vehicle = VEHICLE::CREATE_VEHICLE(hash, pos.x, pos.y, pos.z, 0.f, TRUE, FALSE, FALSE);
*(unsigned short*)g_pointers->m_model_spawn_bypass = 0x0574; //By writing the "old" bypass to the function, running CREATE_VEHICLE, then restoring it, the anti-cheat does not have enough time to catch the function in a dirty state.
script::get_current()->yield();
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);
if (*g_pointers->m_is_session_started)
{
DECORATOR::DECOR_SET_INT(vehicle, "MPBitset", 0);
ENTITY::_SET_ENTITY_SOMETHING(vehicle, TRUE); //True means it can be deleted by the engine when switching lobbies/missions/etc, false means the script is expected to clean it up.
auto networkId = NETWORK::VEH_TO_NET(vehicle);
if (NETWORK::NETWORK_GET_ENTITY_IS_NETWORKED(vehicle))
NETWORK::SET_NETWORK_ID_EXISTS_ON_ALL_MACHINES(networkId, true);
VEHICLE::SET_VEHICLE_IS_STOLEN(vehicle, FALSE);
}
if (*g_pointers->m_is_session_started)
{
DECORATOR::DECOR_SET_INT(vehicle, "MPBitset", 0);
}
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);
}
QUEUE_JOB_END_CLAUSE
}
if (ImGui::Button("Test g3log crash within ImGui"))
{
*((PINT)nullptr) = 0xDEADBEEF;
}
ImGui::SameLine();
if (ImGui::Button("Test g3log crash within GTA V Script"))
{
QUEUE_JOB_BEGIN_CLAUSE()
{
//PED::_0xB782F8238512BAD5(PLAYER::PLAYER_PED_ID(), nullptr); //This causes a crash at GTA5.exe+5845356 and nothing of value was in the log in the stack dump because of the context switch to GTA 5's memory. If you encounter something similar, you will have to figure out where the crash occured in the GTA 5 exe, and trace back that native, and figure out which function is calling the native that is crashing.
*((PINT)nullptr) = 0xDEADBEEF;
}
QUEUE_JOB_END_CLAUSE
}
ImGui::Separator();
if (ImGui::Button("Unload"))
{
g_running = false;
}
}
ImGui::EndTabItem();
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "common.hpp"
#include "natives.hpp"
namespace big
{
class base_tab
{
public:
static void render_base_tab();
};
}

View File

@ -63,7 +63,6 @@ namespace big
m_run_script_threads_hook.enable(); m_run_script_threads_hook.enable();
m_convert_thread_to_fiber_hook.enable(); m_convert_thread_to_fiber_hook.enable();
ensure_dynamic_hooks();
m_enabled = true; m_enabled = true;
} }
@ -71,11 +70,6 @@ namespace big
{ {
m_enabled = false; m_enabled = false;
if (m_main_persistent_hook)
{
m_main_persistent_hook->disable();
}
m_convert_thread_to_fiber_hook.disable(); m_convert_thread_to_fiber_hook.disable();
m_run_script_threads_hook.disable(); m_run_script_threads_hook.disable();
@ -84,20 +78,6 @@ namespace big
m_swapchain_hook.disable(); m_swapchain_hook.disable();
} }
void hooking::ensure_dynamic_hooks()
{
if (!m_main_persistent_hook)
{
if (auto main_persistent = find_script_thread(RAGE_JOAAT("main_persistent")))
{
m_main_persistent_hook = std::make_unique<vmt_hook>(main_persistent->m_handler, hooks::main_persistent_num_funcs);
m_main_persistent_hook->hook(hooks::main_persistent_dtor_index, &hooks::main_persistent_dtor);
m_main_persistent_hook->hook(hooks::main_persistent_is_networked_index, &hooks::main_persistent_is_networked);
m_main_persistent_hook->enable();
}
}
}
minhook_keepalive::minhook_keepalive() minhook_keepalive::minhook_keepalive()
{ {
MH_Initialize(); MH_Initialize();
@ -110,85 +90,94 @@ namespace big
bool hooks::run_script_threads(std::uint32_t ops_to_execute) bool hooks::run_script_threads(std::uint32_t ops_to_execute)
{ {
if (g_running) TRY_CLAUSE
{ {
g_script_mgr.tick(); if (g_running)
} {
g_script_mgr.tick();
}
return g_hooking->m_run_script_threads_hook.get_original<functions::run_script_threads_t>()(ops_to_execute); return g_hooking->m_run_script_threads_hook.get_original<functions::run_script_threads_t>()(ops_to_execute);
} EXCEPT_CLAUSE
return false;
} }
void *hooks::convert_thread_to_fiber(void *param) void *hooks::convert_thread_to_fiber(void *param)
{ {
if (IsThreadAFiber()) TRY_CLAUSE
{ {
return GetCurrentFiber(); if (IsThreadAFiber())
} {
return GetCurrentFiber();
}
return g_hooking->m_convert_thread_to_fiber_hook.get_original<decltype(&convert_thread_to_fiber)>()(param); return g_hooking->m_convert_thread_to_fiber_hook.get_original<decltype(&convert_thread_to_fiber)>()(param);
} EXCEPT_CLAUSE
return nullptr;
} }
HRESULT hooks::swapchain_present(IDXGISwapChain *this_, UINT sync_interval, UINT flags) HRESULT hooks::swapchain_present(IDXGISwapChain *this_, UINT sync_interval, UINT flags)
{ {
if (g_running) TRY_CLAUSE
{ {
g_renderer->on_present(); if (g_running)
} {
g_renderer->on_present();
}
return g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_present)>(swapchain_present_index)(this_, sync_interval, flags); return g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_present)>(swapchain_present_index)(this_, sync_interval, flags);
} EXCEPT_CLAUSE
return NULL;
} }
HRESULT hooks::swapchain_resizebuffers(IDXGISwapChain * this_, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT new_format, UINT swapchain_flags) HRESULT hooks::swapchain_resizebuffers(IDXGISwapChain * this_, UINT buffer_count, UINT width, UINT height, DXGI_FORMAT new_format, UINT swapchain_flags)
{ {
if (g_running) TRY_CLAUSE
{ {
g_renderer->pre_reset(); if (g_running)
auto result = g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_resizebuffers)>(swapchain_resizebuffers_index)
(this_, buffer_count, width, height, new_format, swapchain_flags);
if (SUCCEEDED(result))
{ {
g_renderer->post_reset(); g_renderer->pre_reset();
auto result = g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_resizebuffers)>(swapchain_resizebuffers_index)
(this_, buffer_count, width, height, new_format, swapchain_flags);
if (SUCCEEDED(result))
{
g_renderer->post_reset();
}
return result;
} }
return result; return g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_resizebuffers)>(swapchain_resizebuffers_index)
} (this_, buffer_count, width, height, new_format, swapchain_flags);
} EXCEPT_CLAUSE
return g_hooking->m_swapchain_hook.get_original<decltype(&swapchain_resizebuffers)>(swapchain_resizebuffers_index) return NULL;
(this_, buffer_count, width, height, new_format, swapchain_flags);
} }
LRESULT hooks::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) LRESULT hooks::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{ {
if (g_running) TRY_CLAUSE
{ {
g_renderer->wndproc(hwnd, msg, wparam, lparam); if (g_running)
} {
g_renderer->wndproc(hwnd, msg, wparam, lparam);
}
return CallWindowProcW(g_hooking->m_og_wndproc, hwnd, msg, wparam, lparam); return CallWindowProcW(g_hooking->m_og_wndproc, hwnd, msg, wparam, lparam);
} EXCEPT_CLAUSE
return NULL;
} }
BOOL hooks::set_cursor_pos(int x, int y) BOOL hooks::set_cursor_pos(int x, int y)
{ {
if (g_gui.m_opened) TRY_CLAUSE
{ {
return true; if (g_gui.m_opened)
} return true;
return g_hooking->m_set_cursor_pos_hook.get_original<decltype(&set_cursor_pos)>()(x, y); return g_hooking->m_set_cursor_pos_hook.get_original<decltype(&set_cursor_pos)>()(x, y);
} } EXCEPT_CLAUSE
return FALSE;
void hooks::main_persistent_dtor(CGameScriptHandler *this_, bool free_memory)
{
auto og_func = g_hooking->m_main_persistent_hook->get_original<decltype(&main_persistent_dtor)>(main_persistent_dtor_index);
g_hooking->m_main_persistent_hook->disable();
g_hooking->m_main_persistent_hook.reset();
return og_func(this_, free_memory);
}
bool hooks::main_persistent_is_networked(CGameScriptHandler *this_)
{
return *g_pointers->m_is_session_started;
} }
} }

View File

@ -20,12 +20,6 @@ namespace big
static LRESULT wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); static LRESULT wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static BOOL set_cursor_pos(int x, int y); static BOOL set_cursor_pos(int x, int y);
static constexpr auto main_persistent_num_funcs = 16;
static constexpr auto main_persistent_dtor_index = 0;
static constexpr auto main_persistent_is_networked_index = 6;
static void main_persistent_dtor(CGameScriptHandler *this_, bool free_memory);
static bool main_persistent_is_networked(CGameScriptHandler *this_);
}; };
struct minhook_keepalive struct minhook_keepalive
@ -44,7 +38,6 @@ namespace big
void enable(); void enable();
void disable(); void disable();
void ensure_dynamic_hooks();
private: private:
bool m_enabled{}; bool m_enabled{};
minhook_keepalive m_minhook_keepalive; minhook_keepalive m_minhook_keepalive;
@ -55,7 +48,6 @@ namespace big
detour_hook m_run_script_threads_hook; detour_hook m_run_script_threads_hook;
detour_hook m_convert_thread_to_fiber_hook; detour_hook m_convert_thread_to_fiber_hook;
std::unique_ptr<vmt_hook> m_main_persistent_hook;
}; };
inline hooking *g_hooking{}; inline hooking *g_hooking{};

View File

@ -14,7 +14,7 @@ namespace big
void native_invoker::cache_handlers() void native_invoker::cache_handlers()
{ {
for (const rage::scrNativeMapping &mapping : g_crossmap) for (const rage::scrNativeMapping& mapping : g_crossmap)
{ {
rage::scrNativeHandler handler = g_pointers->m_get_native_handler( rage::scrNativeHandler handler = g_pointers->m_get_native_handler(
g_pointers->m_native_registration_table, mapping.second); g_pointers->m_native_registration_table, mapping.second);
@ -34,19 +34,12 @@ namespace big
{ {
rage::scrNativeHandler handler = it->second; rage::scrNativeHandler handler = it->second;
__try handler(&m_call_context);
{ g_pointers->m_fix_vectors(&m_call_context);
handler(&m_call_context);
g_pointers->m_fix_vectors(&m_call_context);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
LOG_ERROR("Exception caught while trying to call 0x{:X} native.", hash);
}
} }
else else
{ {
LOG_ERROR("Failed to find 0x{:X} native's handler.", hash); [hash]() { LOG(WARNING) << "Failed to find " << HEX_TO_UPPER(hash) << " native's handler."; }();
} }
} }
} }

View File

@ -1,188 +1,211 @@
#pragma once #pragma once
#include "common.hpp" #include "common.hpp"
#include <g3log/g3log.hpp>
namespace big #include <g3log/logworker.hpp>
{
enum class log_color : std::uint16_t namespace big
{ {
red = FOREGROUND_RED, template <typename TP>
green = FOREGROUND_GREEN, std::time_t to_time_t(TP tp)
blue = FOREGROUND_BLUE, {
intensify = FOREGROUND_INTENSITY using namespace std::chrono;
}; auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now()
+ system_clock::now());
inline log_color operator|(log_color a, log_color b) return system_clock::to_time_t(sctp);
{ }
return static_cast<log_color>(static_cast<std::underlying_type_t<log_color>>(a) | static_cast<std::underlying_type_t<log_color>>(b));
} enum class log_color : std::uint16_t
{
class logger; red = FOREGROUND_RED,
inline logger *g_logger{}; green = FOREGROUND_GREEN,
blue = FOREGROUND_BLUE,
class logger intensify = FOREGROUND_INTENSITY
{ };
public:
explicit logger() : enum LOG_FLAGS
m_file_path(std::getenv("appdata")) {
{ FLAG_NO_DISK = (1 << 0),
m_file_path /= "BigBaseV2"; FLAG_NO_CONSOLE = (1 << 1)
try };
{
if (!std::filesystem::exists(m_file_path)) static const int kEventValue = 400;
{ static const int kRawValue = 600;
std::filesystem::create_directory(m_file_path); inline constexpr auto max_padding_length = 26;
} inline constexpr auto level_padding_length = 8;
else if (!std::filesystem::is_directory(m_file_path))
{ const LEVELS INFO_TO_FILE{ INFO.value | FLAG_NO_CONSOLE, {"INFO"} },
std::filesystem::remove(m_file_path); HACKER{ INFO.value, {"HACKER"} },
std::filesystem::create_directory(m_file_path); EVENT{ kEventValue | FLAG_NO_CONSOLE, {"EVENT"} },
} RAW_GREEN_TO_CONSOLE{ kRawValue | FLAG_NO_DISK, {"RAW_GREEN_TO_CONSOLE"} },
RAW_RED{ kRawValue, {"RAW_RED"} };
m_file_path /= "BigBaseV2.log";
m_file_out.open(m_file_path, std::ios_base::out | std::ios_base::app); inline log_color operator|(log_color a, log_color b)
} {
catch (std::filesystem::filesystem_error const&) return static_cast<log_color>(static_cast<std::underlying_type_t<log_color>>(a) | static_cast<std::underlying_type_t<log_color>>(b));
{ }
}
class logger;
if ((m_did_console_exist = AttachConsole(GetCurrentProcessId())) == false) inline logger* g_logger{};
AllocConsole();
class logger
if ((m_console_handle = GetStdHandle(STD_OUTPUT_HANDLE)) != nullptr) {
{ public:
SetConsoleTitleA("BigBaseV2"); explicit logger() :
SetConsoleOutputCP(CP_UTF8); m_file_path(std::getenv("appdata")),
m_worker(g3::LogWorker::createLogWorker())
m_console_out.open("CONOUT$", std::ios_base::out | std::ios_base::app); {
} if ((m_did_console_exist = AttachConsole(GetCurrentProcessId())) == false)
AllocConsole();
g_logger = this;
} if ((m_console_handle = GetStdHandle(STD_OUTPUT_HANDLE)) != nullptr)
{
~logger() SetConsoleTitleA("BigBaseV2");
{ SetConsoleOutputCP(CP_UTF8);
if (!m_did_console_exist)
FreeConsole(); m_console_out.open("CONOUT$", std::ios_base::out | std::ios_base::app);
}
g_logger = nullptr;
} m_file_path /= "BigBaseV2";
std::filesystem::path m_backup_path = m_file_path;
template <typename ...Args> m_backup_path /= "Backup";
void raw(log_color color, Args const &...args) try
{ {
raw_to_console(color, args...); if (!std::filesystem::exists(m_file_path))
raw_to_file(args...); {
} std::filesystem::create_directory(m_file_path);
}
template <typename ...Args> else if (!std::filesystem::is_directory(m_file_path))
void log(log_color color, std::string_view prefix, std::string_view format, Args const &...args) {
{ std::filesystem::remove(m_file_path);
auto message = fmt::format(format, args...); std::filesystem::create_directory(m_file_path);
}
auto time_since_epoch = std::time(nullptr); if (!std::filesystem::exists(m_backup_path))
auto local_time = std::localtime(&time_since_epoch); {
std::filesystem::create_directory(m_backup_path);
auto console_timestamp = fmt::format("[{:0>2}:{:0>2}:{:0>2}]", local_time->tm_hour, local_time->tm_min, local_time->tm_sec); }
auto file_timestamp = fmt::format("[{}-{}-{} {:0>2}:{:0>2}:{:0>2}]", local_time->tm_year + 1900, local_time->tm_mon + 1, local_time->tm_mday, local_time->tm_hour, local_time->tm_min, local_time->tm_sec); else if (!std::filesystem::is_directory(m_backup_path))
{
raw_to_console(color, console_timestamp, " [", prefix, "] ", message, "\n"); std::filesystem::remove(m_backup_path);
raw_to_file(file_timestamp, " [", prefix, "] ", message, "\n"); std::filesystem::create_directory(m_backup_path);
} }
private:
template <typename ...Args> m_event_file_path = m_file_path;
void raw_to_console(log_color color, Args const &...args) m_file_path /= "BigBaseV2.log";
{ m_event_file_path /= "GTAEvents.log";
if (m_console_handle)
{ if (std::filesystem::exists(m_file_path))
SetConsoleTextAttribute(m_console_handle, static_cast<std::uint16_t>(color)); {
} auto file_time = std::filesystem::last_write_time(m_file_path);
auto timet = to_time_t(file_time);
if (m_console_out) auto local_time = std::localtime(&timet);
{
((m_console_out << args), ...); auto bigbase_timestamp = fmt::format("{:0>2}-{:0>2}-{}-{:0>2}-{:0>2}-{:0>2} BigBaseV2.log", local_time->tm_mon + 1, local_time->tm_mday, local_time->tm_year + 1900, local_time->tm_hour, local_time->tm_min, local_time->tm_sec);
m_console_out << std::flush; auto gta_events_timestamp = fmt::format("{:0>2}-{:0>2}-{}-{:0>2}-{:0>2}-{:0>2} GTAEvents.log", local_time->tm_mon + 1, local_time->tm_mday, local_time->tm_year + 1900, local_time->tm_hour, local_time->tm_min, local_time->tm_sec);
}
} std::filesystem::copy_file(m_file_path, m_backup_path / bigbase_timestamp);
if (std::filesystem::exists(m_event_file_path) && !std::filesystem::is_empty(m_event_file_path))
template <typename ...Args> std::filesystem::copy_file(m_event_file_path, m_backup_path / gta_events_timestamp);
void raw_to_file(Args const &...args) }
{
if (m_file_out) m_file_out.open(m_file_path, std::ios_base::out | std::ios_base::trunc);
{ m_gta_event_file_out.open(m_event_file_path, std::ios_base::out | std::ios_base::trunc);
((m_file_out << args), ...);
m_file_out << std::flush; m_worker->addSink(std::make_unique<log_sink>(), &log_sink::callback);
} g3::initializeLogging(m_worker.get());
} g3::installCrashHandler();
private: }
bool m_did_console_exist{}; catch (std::filesystem::filesystem_error const& error)
HANDLE m_console_handle{}; {
std::ofstream m_console_out; m_console_out << error.what();
}
std::filesystem::path m_file_path;
std::ofstream m_file_out; g_logger = this;
}; }
template <typename ...Args> ~logger()
inline void log_info(std::string_view format, Args const &...args) {
{ m_worker.reset();
if (g_logger) if (!m_did_console_exist)
{ FreeConsole();
g_logger->log(log_color::blue | log_color::intensify, "Info", format, args...);
} g_logger = nullptr;
else }
{
DebugBreak(); struct log_sink
} {
} std::map<std::string, log_color> log_colors = {
{INFO.text, log_color::blue | log_color::intensify},
template <typename ...Args> {WARNING.text, log_color::red},
inline void log_error(std::string_view format, Args const &...args) {HACKER.text, log_color::green | log_color::intensify},
{ {FATAL.text, log_color::red | log_color::intensify},
if (g_logger) {G3LOG_DEBUG.text, log_color::blue},
{ {RAW_RED.text, log_color::red},
g_logger->log(log_color::green | log_color::intensify, "Error", format, args...); {RAW_GREEN_TO_CONSOLE.text, log_color::green | log_color::intensify}
} };
else
{ void callback(g3::LogMessageMover log)
DebugBreak(); {
} g3::LogMessage log_message = log.get();
} int level_value = log_message._level.value;
template <typename ...Args> bool is_raw = level_value == RAW_RED.value || level_value == RAW_GREEN_TO_CONSOLE.value;
inline void log_trace(std::string_view format, Args const &...args)
{ if (!(level_value & FLAG_NO_CONSOLE))
if (g_logger) {
{ SetConsoleTextAttribute(g_logger->m_console_handle, static_cast<std::uint16_t>(log_colors[log_message._level.text]));
g_logger->log(log_color::green | log_color::intensify, "Trace", format, args...); g_logger->m_console_out << log_message.toString(is_raw ? format_raw : format_console) << std::flush;
} }
else
{ if (!(level_value & FLAG_NO_DISK))
DebugBreak(); {
} if (level_value == EVENT.value)
} g_logger->m_gta_event_file_out << log_message.toString(format_file) << std::flush;
else
template <typename ...Args> g_logger->m_file_out << log_message.toString(is_raw ? format_raw : format_file) << std::flush;
inline void log_raw(log_color color, Args const &...args) }
{ }
if (g_logger)
{ static std::string format_file(const g3::LogMessage& msg)
g_logger->raw(color, args...); {
} std::string file_name_with_line = "[" + msg.file() + ":" + msg.line() + "]";
else std::stringstream out;
{ out << "[" << msg.timestamp("%H:%M:%S") << "] [" << std::left << std::setw(level_padding_length) << msg.level().append("]") << std::setw(max_padding_length) << file_name_with_line;
DebugBreak(); return out.str();
} }
}
static std::string format_console(const g3::LogMessage& msg)
#define LOG_INFO_IMPL(format, ...) (::big::log_info(format, __VA_ARGS__)) {
#define LOG_INFO(format, ...) LOG_INFO_IMPL(format, __VA_ARGS__) std::stringstream out;
out << "[" << msg.timestamp("%H:%M:%S") << "] ";
#define LOG_ERROR_IMPL(format, ...) (::big::log_error(format, __VA_ARGS__)) return out.str();
#define LOG_ERROR(format, ...) LOG_ERROR_IMPL(format, __VA_ARGS__) }
#define LOG_TRACE_IMPL(format, ...) (::big::log_trace(format, __VA_ARGS__)) static std::string format_raw(const g3::LogMessage& msg)
#define LOG_TRACE(format, ...) LOG_TRACE_IMPL(format, __VA_ARGS__) {
return "";
#define LOG_RAW_IMPL(color, ...) (::big::log_raw(color, __VA_ARGS__)) }
#define LOG_RAW(color, ...) LOG_RAW_IMPL(color, __VA_ARGS__) };
}
template <typename ...Args>
inline void log_now(std::string_view format, Args const& ...args)
{
auto message = fmt::format(format, args...);
if (m_file_out)
m_file_out << message << std::endl << std::flush;
}
private:
bool m_did_console_exist{};
HANDLE m_console_handle{};
std::ofstream m_console_out;
std::filesystem::path m_file_path;
std::filesystem::path m_event_file_path;
std::ofstream m_file_out;
std::ofstream m_gta_event_file_out;
std::unique_ptr<g3::LogWorker> m_worker;
};
#define LOG_NOW(format, ...) g_logger->log_now(format, __VA_ARGS__)
#define HEX_TO_UPPER(value) "0x" << std::hex << std::uppercase << (DWORD64)value << std::dec << std::nouppercase
}

View File

@ -21,102 +21,83 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID)
auto logger_instance = std::make_unique<logger>(); auto logger_instance = std::make_unique<logger>();
try try
{ {
LOG(RAW_GREEN_TO_CONSOLE) << u8R"kek(
LOG_RAW(log_color::green | log_color::intensify, ______ _ ______ ______
u8R"kek( ... (____ \(_) (____ \ (_____ \
;::::; ____) )_ ____ ____) ) ____ ___ ____ _ _ ____) )
;::::; :; | __ (| |/ _ | __ ( / _ |/___)/ _ ) | | /_____/
;:::::' :; | |__) ) ( ( | | |__) | ( | |___ ( (/ / \ V /_______
;:::::; ;. |______/|_|\_|| |______/ \_||_(___/ \____) \_/(_______)
,:::::' ; OOO\ (_____|)kek";
::::::; ; OOOOO\
;:::::; ; OOOOOOOO
,;::::::; ;' / OOOOOOO
;:::::::::`. ,,,;. / / DOOOOOO
.';:::::::::::::::::;, / / DOOOO
,::::::;::::::;;;;::::;, / / DOOO
;`::::::`'::::::;;;::::: ,#/ / DOOO
:`:::::::`;::::::;;::: ;::# / DOOO
::`:::::::`;:::::::: ;::::# / DOO
`:`:::::::`;:::::: ;::::::#/ DOO
:::`:::::::`;; ;:::::::::## OO
::::`:::::::`;::::::::;:::# OO
`:::::`::::::::::::;'`:;::# O
`:::::`::::::::;' / / `:#
::::::`:::::;' / / `#
)kek");
auto pointers_instance = std::make_unique<pointers>(); auto pointers_instance = std::make_unique<pointers>();
LOG_INFO("Pointers initialized."); LOG(INFO) << "Pointers initialized.";
if (*g_pointers->m_game_state != eGameState::Playing) //if (*g_pointers->m_game_state != eGameState::Playing)
{ //{
LOG_INFO("Waiting for the game to load."); // LOG_INFO("Waiting for the game to load.");
do // do
{ // {
std::this_thread::sleep_for(100ms); // std::this_thread::sleep_for(100ms);
} while (*g_pointers->m_game_state != eGameState::Playing); // } while (*g_pointers->m_game_state != eGameState::Playing);
//
LOG_INFO("The game has loaded."); // LOG_INFO("The game has loaded.");
} //}
else //else
{ //{
LOG_INFO("The game is already loaded."); // LOG_INFO("The game is already loaded.");
} //}
auto renderer_instance = std::make_unique<renderer>(); auto renderer_instance = std::make_unique<renderer>();
LOG_INFO("Renderer initialized."); LOG(INFO) << "Renderer initialized.";
auto fiber_pool_instance = std::make_unique<fiber_pool>(10); auto fiber_pool_instance = std::make_unique<fiber_pool>(10);
LOG_INFO("Fiber pool initialized."); LOG(INFO) << "Fiber pool initialized.";
auto hooking_instance = std::make_unique<hooking>(); auto hooking_instance = std::make_unique<hooking>();
LOG_INFO("Hooking initialized."); LOG(INFO) << "Hooking initialized.";
g_settings.load();
LOG(INFO) << "Settings Loaded.";
g_script_mgr.add_script(std::make_unique<script>(&features::script_func)); g_script_mgr.add_script(std::make_unique<script>(&features::script_func));
g_script_mgr.add_script(std::make_unique<script>(&gui::script_func)); g_script_mgr.add_script(std::make_unique<script>(&gui::script_func));
LOG_INFO("Scripts registered."); LOG(INFO) << "Scripts registered.";
g_hooking->enable(); g_hooking->enable();
LOG_INFO("Hooking enabled."); LOG(INFO) << "Hooking enabled.";
while (g_running) while (g_running)
{ {
if (GetAsyncKeyState(VK_END) & 0x8000) std::this_thread::sleep_for(500ms);
g_running = false;
g_hooking->ensure_dynamic_hooks();
std::this_thread::sleep_for(10ms);
} }
g_hooking->disable(); g_hooking->disable();
LOG_INFO("Hooking disabled."); LOG(INFO) << "Hooking disabled.";
std::this_thread::sleep_for(1000ms); std::this_thread::sleep_for(1000ms);
g_script_mgr.remove_all_scripts(); g_script_mgr.remove_all_scripts();
LOG_INFO("Scripts unregistered."); LOG(INFO) << "Scripts unregistered.";
hooking_instance.reset(); hooking_instance.reset();
LOG_INFO("Hooking uninitialized."); LOG(INFO) << "Hooking uninitialized.";
fiber_pool_instance.reset(); fiber_pool_instance.reset();
LOG_INFO("Fiber pool uninitialized."); LOG(INFO) << "Fiber pool uninitialized.";
renderer_instance.reset(); renderer_instance.reset();
LOG_INFO("Renderer uninitialized."); LOG(INFO) << "Renderer uninitialized.";
pointers_instance.reset(); pointers_instance.reset();
LOG_INFO("Pointers uninitialized."); LOG(INFO) << "Pointers uninitialized.";
} }
catch (std::exception const &ex) catch (std::exception const &ex)
{ {
LOG_ERROR("{}", ex.what()); LOG(WARNING) << ex.what();
MessageBoxA(nullptr, ex.what(), nullptr, MB_OK | MB_ICONEXCLAMATION); MessageBoxA(nullptr, ex.what(), nullptr, MB_OK | MB_ICONEXCLAMATION);
} }
LOG_INFO("Farewell!"); LOG(INFO) << "Farewell!";
logger_instance.reset(); logger_instance.reset();
CloseHandle(g_main_thread); CloseHandle(g_main_thread);

View File

@ -13,21 +13,26 @@ namespace memory
void pattern_batch::run(range region) void pattern_batch::run(range region)
{ {
bool all_found = true; bool all_found = true;
for (auto &entry : m_entries) for (auto& entry : m_entries)
{ {
if (auto result = region.scan(entry.m_pattern)) if (auto result = region.scan(entry.m_pattern))
{ {
if (entry.m_callback) if (entry.m_callback)
{ {
std::invoke(std::move(entry.m_callback), result); std::invoke(std::move(entry.m_callback), result);
LOG_INFO("Found '{}'.", entry.m_name); LOG(big::INFO_TO_FILE) << "Found '" << entry.m_name << "' GTA5.exe+" << HEX_TO_UPPER(result.as<DWORD64>() - region.begin().as<DWORD64>());
} }
else else
{ {
all_found = false; all_found = false;
LOG_ERROR("Failed to find '{}'.", entry.m_name); LOG(WARNING) << "Failed to find '" << entry.m_name << "'.";
} }
} }
else
{
all_found = false;
LOG(WARNING) << "Failed to find '" << entry.m_name << "'.";
}
} }
m_entries.clear(); m_entries.clear();

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,11 @@ namespace big
m_swapchain = ptr.add(3).rip().as<IDXGISwapChain**>(); m_swapchain = ptr.add(3).rip().as<IDXGISwapChain**>();
}); });
main_batch.add("Model Spawn Bypass", "48 8B C8 FF 52 30 84 C0 74 05 48", [this](memory::handle ptr)
{
m_model_spawn_bypass = ptr.add(8).as<PVOID>();
});
main_batch.run(memory::module(nullptr)); main_batch.run(memory::module(nullptr));
m_hwnd = FindWindowW(L"grcWindow", nullptr); m_hwnd = FindWindowW(L"grcWindow", nullptr);

View File

@ -32,6 +32,8 @@ namespace big
CGameScriptHandlerMgr **m_script_handler_mgr{}; CGameScriptHandlerMgr **m_script_handler_mgr{};
IDXGISwapChain **m_swapchain{}; IDXGISwapChain **m_swapchain{};
PVOID m_model_spawn_bypass;
}; };
inline pointers *g_pointers{}; inline pointers *g_pointers{};

View File

@ -1,100 +1,132 @@
#include "common.hpp" #include "common.hpp"
#include "fonts.hpp" #include "fonts.hpp"
#include "logger.hpp" #include "logger.hpp"
#include "gui.hpp" #include "gui.hpp"
#include "pointers.hpp" #include "pointers.hpp"
#include "renderer.hpp" #include "renderer.hpp"
#include <imgui.h> #include <imgui.h>
#include <imgui_impl_dx11.h> #include <imgui_impl_dx11.h>
#include <imgui_impl_win32.h> #include <imgui_impl_win32.h>
#include <imgui_internal.h>
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
namespace big
{ namespace big
renderer::renderer() : {
m_dxgi_swapchain(*g_pointers->m_swapchain) renderer::renderer() :
{ m_dxgi_swapchain(*g_pointers->m_swapchain)
void *d3d_device{}; {
if (SUCCEEDED(m_dxgi_swapchain->GetDevice(__uuidof(ID3D11Device), &d3d_device))) void *d3d_device{};
{ if (SUCCEEDED(m_dxgi_swapchain->GetDevice(__uuidof(ID3D11Device), &d3d_device)))
m_d3d_device.Attach(static_cast<ID3D11Device*>(d3d_device)); {
} m_d3d_device.Attach(static_cast<ID3D11Device*>(d3d_device));
else }
{ else
throw std::runtime_error("Failed to get D3D device."); {
} throw std::runtime_error("Failed to get D3D device.");
}
m_d3d_device->GetImmediateContext(m_d3d_device_context.GetAddressOf());
m_d3d_device->GetImmediateContext(m_d3d_device_context.GetAddressOf());
ImGui::CreateContext();
ImGui_ImplDX11_Init(m_d3d_device.Get(), m_d3d_device_context.Get()); auto file_path = std::filesystem::path(std::getenv("appdata"));
ImGui_ImplWin32_Init(g_pointers->m_hwnd); file_path /= "BigBaseV2";
if (!std::filesystem::exists(file_path))
ImFontConfig font_cfg{}; {
font_cfg.FontDataOwnedByAtlas = false; std::filesystem::create_directory(file_path);
std::strcpy(font_cfg.Name, "Rubik"); }
else if (!std::filesystem::is_directory(file_path))
m_font = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(const_cast<std::uint8_t*>(font_rubik), sizeof(font_rubik), 20.f, &font_cfg); {
m_monospace_font = ImGui::GetIO().Fonts->AddFontDefault(); std::filesystem::remove(file_path);
std::filesystem::create_directory(file_path);
g_gui.dx_init(); }
g_renderer = this; file_path /= "imgui.ini";
}
ImGuiContext* ctx = ImGui::CreateContext();
renderer::~renderer()
{ static std::string path = file_path.make_preferred().string();
ImGui_ImplWin32_Shutdown(); ctx->IO.IniFilename = path.c_str();
ImGui_ImplDX11_Shutdown();
ImGui::DestroyContext(); ImGui_ImplDX11_Init(m_d3d_device.Get(), m_d3d_device_context.Get());
ImGui_ImplWin32_Init(g_pointers->m_hwnd);
g_renderer = nullptr;
} ImFontConfig font_cfg{};
font_cfg.FontDataOwnedByAtlas = false;
void renderer::on_present() std::strcpy(font_cfg.Name, "Rubik");
{
if (g_gui.m_opened) m_font = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(const_cast<std::uint8_t*>(font_rubik), sizeof(font_rubik), 20.f, &font_cfg);
{ m_monospace_font = ImGui::GetIO().Fonts->AddFontDefault();
ImGui::GetIO().MouseDrawCursor = true;
ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouse; g_gui.dx_init();
} g_renderer = this;
else }
{
ImGui::GetIO().MouseDrawCursor = false; renderer::~renderer()
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouse; {
} ImGui_ImplWin32_Shutdown();
ImGui_ImplDX11_Shutdown();
ImGui_ImplDX11_NewFrame(); ImGui::DestroyContext();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame(); g_renderer = nullptr;
}
if (g_gui.m_opened)
{ void renderer::on_present()
g_gui.dx_on_tick(); {
} if (g_gui.m_opened)
{
ImGui::Render(); ImGui::GetIO().MouseDrawCursor = true;
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
} }
else
void renderer::pre_reset() {
{ ImGui::GetIO().MouseDrawCursor = false;
ImGui_ImplDX11_InvalidateDeviceObjects(); ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouse;
} }
void renderer::post_reset() ImGui_ImplDX11_NewFrame();
{ ImGui_ImplWin32_NewFrame();
ImGui_ImplDX11_CreateDeviceObjects(); ImGui::NewFrame();
}
if (g_gui.m_opened)
void renderer::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
{ g_gui.dx_on_tick();
if (msg == WM_KEYUP && wparam == VK_INSERT) }
g_gui.m_opened ^= true;
ImGui::Render();
if (g_gui.m_opened) ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
{ }
ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam);
} void renderer::pre_reset()
} {
} ImGui_ImplDX11_InvalidateDeviceObjects();
}
void renderer::post_reset()
{
ImGui_ImplDX11_CreateDeviceObjects();
}
void renderer::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
if (msg == WM_KEYUP && wparam == VK_INSERT)
{
//Persist and restore the cursor position between menu instances.
static POINT cursor_coords{};
if (g_gui.m_opened)
{
GetCursorPos(&cursor_coords);
}
else if (cursor_coords.x + cursor_coords.y != 0)
{
SetCursorPos(cursor_coords.x, cursor_coords.y);
}
g_gui.m_opened ^= true;
}
if (g_gui.m_opened)
{
ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam);
}
}
}

View File

@ -5,10 +5,17 @@
namespace big namespace big
{ {
static void script_exception_handler(PEXCEPTION_POINTERS exp) void script::script_exception_handler(PEXCEPTION_POINTERS exp)
{ {
LOG_ERROR("Script threw an exception!"); HMODULE mod{};
g_stackwalker.ShowCallstack(GetCurrentThread(), exp->ContextRecord); DWORD64 offset{};
char buffer[MAX_PATH]{};
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)exp->ExceptionRecord->ExceptionAddress, &mod) == TRUE && mod != nullptr)
{
offset = ((DWORD64)exp->ExceptionRecord->ExceptionAddress - (DWORD64)mod);
GetModuleFileNameA(mod, buffer, MAX_PATH - 1);
}
LOG(FATAL) << "Exception Code: " << HEX_TO_UPPER(exp->ExceptionRecord->ExceptionCode) << " Exception Offset: " << HEX_TO_UPPER(offset) << " Fault Module Name: " << buffer;
} }
script::script(func_t func, std::optional<std::size_t> stack_size) : script::script(func_t func, std::optional<std::size_t> stack_size) :
@ -52,38 +59,23 @@ namespace big
SwitchToFiber(m_main_fiber); SwitchToFiber(m_main_fiber);
} }
script *script::get_current() script* script::get_current()
{ {
return static_cast<script*>(GetFiberData()); return static_cast<script*>(GetFiberData());
} }
void script::fiber_func() void script::fiber_func()
{ {
__try TRY_CLAUSE
{ {
[this]() m_func();
{
try
{
m_func();
}
catch (std::exception const &ex)
{
auto ex_class = typeid(ex).name() + 6;
LOG_INFO("Script threw an C++ expection! {}: {}", ex_class, ex.what());
}
catch (...)
{
LOG_INFO("Script threw a C++ exception!");
}
}();
}
__except (script_exception_handler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER)
{
LOG_INFO("Script threw an exception!");
} }
EXCEPT_CLAUSE
[]() {
LOG(INFO) << "Script finished!";
}();
LOG_INFO("Script finished!");
while (true) while (true)
{ {
yield(); yield();

View File

@ -13,13 +13,20 @@ namespace big
void tick(); void tick();
void yield(std::optional<std::chrono::high_resolution_clock::duration> time = std::nullopt); void yield(std::optional<std::chrono::high_resolution_clock::duration> time = std::nullopt);
static script *get_current(); static script* get_current();
static void script_exception_handler(PEXCEPTION_POINTERS exp);
private: private:
void fiber_func(); void fiber_func();
private: private:
void *m_script_fiber; void* m_script_fiber;
void *m_main_fiber; void* m_main_fiber;
func_t m_func; func_t m_func;
std::optional<std::chrono::high_resolution_clock::time_point> m_wake_time; std::optional<std::chrono::high_resolution_clock::time_point> m_wake_time;
}; };
#define TRY_CLAUSE __try
#define EXCEPT_CLAUSE __except (script::script_exception_handler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) { }
#define QUEUE_JOB_BEGIN_CLAUSE(...) g_fiber_pool->queue_job([__VA_ARGS__] { __try
#define QUEUE_JOB_END_CLAUSE __except (script::script_exception_handler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) {} });
} }

View File

@ -9,9 +9,9 @@ namespace big
{ {
inline std::unordered_map<rage::scrProgram*, script_hook*> script_hook::s_map; inline std::unordered_map<rage::scrProgram*, script_hook*> script_hook::s_map;
static bool map_native(rage::scrNativeHash *hash) static bool map_native(rage::scrNativeHash* hash)
{ {
for (auto const &mapping : g_crossmap) for (auto const& mapping : g_crossmap)
{ {
if (mapping.first == *hash) if (mapping.first == *hash)
{ {
@ -34,7 +34,7 @@ namespace big
{ {
if (m_program) if (m_program)
{ {
for (auto[hash, handler_ptr] : m_native_handler_ptrs) for (auto [hash, handler_ptr] : m_native_handler_ptrs)
{ {
auto og_handler = g_pointers->m_get_native_handler(g_pointers->m_native_registration_table, hash); auto og_handler = g_pointers->m_get_native_handler(g_pointers->m_native_registration_table, hash);
*handler_ptr = og_handler; *handler_ptr = og_handler;
@ -58,12 +58,12 @@ namespace big
if (program->is_valid()) if (program->is_valid())
{ {
hook_instance(program); hook_instance(program);
LOG_INFO("Hooked {} script ({})", program->m_name, static_cast<void*>(program)); LOG(INFO) << "Hooked " << program->m_name << " script (" << HEX_TO_UPPER(static_cast<void*>(program)) << ")";
} }
} }
} }
void script_hook::hook_instance(rage::scrProgram *program) void script_hook::hook_instance(rage::scrProgram* program)
{ {
m_program = program; m_program = program;
s_map.emplace(m_program, this); s_map.emplace(m_program, this);
@ -88,7 +88,7 @@ namespace big
} }
} }
void script_hook::scrprogram_dtor(rage::scrProgram *this_, bool free_memory) void script_hook::scrprogram_dtor(rage::scrProgram* this_, bool free_memory)
{ {
if (auto it = s_map.find(this_); it != s_map.end()) if (auto it = s_map.find(this_); it != s_map.end())
{ {

86
BigBaseV2/src/settings.h Normal file
View File

@ -0,0 +1,86 @@
#pragma once
#include "common.hpp"
#include "gta/player.hpp"
namespace big
{
class settings
{
public:
explicit settings() = default;
~settings() = default;
nlohmann::json options;
nlohmann::json default_options =
R"({
"demo bool": false,
"demo int": 1,
"demo double": 1.0,
"demo combo": 0
})"_json;
bool save()
{
std::string settings_file = std::getenv("appdata");
settings_file += "\\BigBaseV2\\settings.json";
std::ofstream file(settings_file, std::ios::out | std::ios::trunc);
file << options.dump(4);
file.close();
return true;
}
bool load()
{
std::string settings_file = std::getenv("appdata");
settings_file += "\\BigBaseV2\\settings.json";
std::ifstream file(settings_file);
if (!file.is_open())
{
write_default_config();
file.open(settings_file);
}
file >> options;
bool should_save = false;
for (auto& e : default_options.items())
{
if (options.count(e.key()) == 0)
{
should_save = true;
options[e.key()] = e.value();
}
}
if (should_save)
{
LOG(INFO) << "Updating settings.";
save();
}
return true;
}
private:
bool write_default_config()
{
std::string settings_file = std::getenv("appdata");
settings_file += "\\BigBaseV2\\settings.json";
std::ofstream file(settings_file, std::ios::out);
file << default_options.dump(4);
file.close();
options.clear();
options = default_options;
return true;
}
};
inline settings g_settings;
}

5
GenerateProjects.bat Normal file
View File

@ -0,0 +1,5 @@
@echo off
premake5 vs2019
IF %ERRORLEVEL% NEQ 0 (
PAUSE
)

View File

@ -20,6 +20,15 @@ To set up the build environment, run the following commands in a terminal:
```dos ```dos
git clone https://github.com/Pocakking/BigBaseV2.git --recurse-submodules git clone https://github.com/Pocakking/BigBaseV2.git --recurse-submodules
cd BigBaseV2 cd BigBaseV2
premake5 vs2019 GenerateProjects.bat
``` ```
Now, you will be able to open the solution, and simply build it in Visual Studio. Now, you will be able to open the solution, and simply build it in Visual Studio.
It is reccomended you generate the project each time you add a file instead of adding it directly to Visual Studio.
## Credits
Pocakking - Original creator.
gir489 - Implementer and wrote the g3log crash handler and added test cases.
datlimabean04 - Wrote the g3log and settings implementation.

View File

@ -17,7 +17,7 @@ workspace "BigBaseV2"
IncludeDir["MinHook"] = "vendor/MinHook/include" IncludeDir["MinHook"] = "vendor/MinHook/include"
IncludeDir["ImGui"] = "vendor/ImGui" IncludeDir["ImGui"] = "vendor/ImGui"
IncludeDir["ImGuiImpl"] = "vendor/ImGui/examples" IncludeDir["ImGuiImpl"] = "vendor/ImGui/examples"
IncludeDir["StackWalker"] = "vendor/StackWalker/Main/StackWalker/" IncludeDir["g3log"] = "vendor/g3log/src"
CppVersion = "C++17" CppVersion = "C++17"
MsvcToolset = "v142" MsvcToolset = "v142"
@ -26,6 +26,8 @@ workspace "BigBaseV2"
function DeclareMSVCOptions() function DeclareMSVCOptions()
filter "system:windows" filter "system:windows"
staticruntime "Off" staticruntime "Off"
floatingpoint "Fast"
vectorextensions "AVX2"
systemversion (WindowsSdkVersion) systemversion (WindowsSdkVersion)
toolset (MsvcToolset) toolset (MsvcToolset)
cppdialect (CppVersion) cppdialect (CppVersion)
@ -45,6 +47,11 @@ workspace "BigBaseV2"
"4307" -- C4307: integral constant overflow "4307" -- C4307: integral constant overflow
} }
end end
function file_exists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
function DeclareDebugOptions() function DeclareDebugOptions()
filter "configurations:Debug" filter "configurations:Debug"
@ -102,27 +109,6 @@ workspace "BigBaseV2"
DeclareMSVCOptions() DeclareMSVCOptions()
DeclareDebugOptions() DeclareDebugOptions()
project "StackWalker"
location "vendor/%{prj.name}"
kind "StaticLib"
language "C++"
targetdir ("bin/lib/" .. outputdir)
objdir ("bin/lib/int/" .. outputdir .. "/%{prj.name}")
files
{
"vendor/%{prj.name}/Main/StackWalker/StackWalker.cpp"
}
includedirs
{
"vendor/%{prj.name}/include"
}
DeclareMSVCOptions()
DeclareDebugOptions()
project "MinHook" project "MinHook"
location "vendor/%{prj.name}" location "vendor/%{prj.name}"
kind "StaticLib" kind "StaticLib"
@ -140,6 +126,38 @@ workspace "BigBaseV2"
DeclareMSVCOptions() DeclareMSVCOptions()
DeclareDebugOptions() DeclareDebugOptions()
project "g3log"
location "vendor/%{prj.name}"
kind "StaticLib"
language "C++"
targetdir ("bin/lib/" .. outputdir)
objdir ("bin/lib/int/" .. outputdir .. "/%{prj.name}")
includedirs
{
"vendor/%{prj.name}/src"
}
if(file_exists("vendor\\g3log\\src\\g3log\\generated_definitions.hpp") == false) then
file = io.open("vendor\\g3log\\src\\g3log\\generated_definitions.hpp", "w")
file:write("// AUTO GENERATED MACRO DEFINITIONS FOR G3LOG\n\n\n/* ==========================================================================\n*2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes\n* with no warranties. This code is yours to share, use and modify with no\n\n*strings attached and no restrictions or obligations.\n* \n* For more information see g3log/LICENSE or refer refer to http://unlicense.org\n\n*============================================================================*/\n#pragma once\n\n\n// CMake induced definitions below. See g3log/Options.cmake for details.");
end
files
{
"vendor/%{prj.name}/src/**.hpp",
"vendor/%{prj.name}/src/**.cpp"
}
removefiles
{
"vendor/%{prj.name}/src/crashhandler_unix.cpp"
}
DeclareMSVCOptions()
DeclareDebugOptions()
project "BigBaseV2" project "BigBaseV2"
location "BigBaseV2" location "BigBaseV2"
@ -155,6 +173,7 @@ workspace "BigBaseV2"
files files
{ {
"%{prj.name}/src/**.hpp", "%{prj.name}/src/**.hpp",
"%{prj.name}/src/**.h",
"%{prj.name}/src/**.cpp", "%{prj.name}/src/**.cpp",
"%{prj.name}/src/**.asm" "%{prj.name}/src/**.asm"
} }
@ -166,7 +185,7 @@ workspace "BigBaseV2"
"%{IncludeDir.MinHook}", "%{IncludeDir.MinHook}",
"%{IncludeDir.ImGui}", "%{IncludeDir.ImGui}",
"%{IncludeDir.ImGuiImpl}", "%{IncludeDir.ImGuiImpl}",
"%{IncludeDir.StackWalker}", "%{IncludeDir.g3log}",
"%{prj.name}/src" "%{prj.name}/src"
} }
@ -180,7 +199,7 @@ workspace "BigBaseV2"
"fmtlib", "fmtlib",
"MinHook", "MinHook",
"ImGui", "ImGui",
"StackWalker" "g3log"
} }
pchheader "%{PrecompiledHeaderInclude}" pchheader "%{PrecompiledHeaderInclude}"
@ -197,12 +216,14 @@ workspace "BigBaseV2"
flags { "NoImportLib", "Maps" } flags { "NoImportLib", "Maps" }
filter "configurations:Debug" filter "configurations:Debug"
flags { "LinkTimeOptimization", "MultiProcessorCompile" }
defines { "BIGBASEV2_DEBUG" } defines { "BIGBASEV2_DEBUG" }
filter "configurations:Release" filter "configurations:Release"
flags { "LinkTimeOptimization", "NoManifest", "MultiProcessorCompile" }
defines { "BIGBASEV2_RELEASE" } defines { "BIGBASEV2_RELEASE" }
optimize "speed" optimize "speed"
filter "configurations:Dist" filter "configurations:Dist"
flags { "LinkTimeOptimization", "FatalCompileWarnings" } flags { "LinkTimeOptimization", "FatalWarnings", "NoManifest", "MultiProcessorCompile" }
defines { "BIGBASEV2_DIST" } defines { "BIGBASEV2_DIST" }
optimize "speed" optimize "speed"

2
vendor/ImGui vendored

@ -1 +1 @@
Subproject commit 6a0d0dab5a9f0b9518a2bc9bb456a69895ae0962 Subproject commit 03453246464cdd414c2f76d4a2569d2d5511870b

2
vendor/MinHook vendored

@ -1 +1 @@
Subproject commit 9fbd087432700d73fc571118d6a9697a36443d88 Subproject commit 8fda4f5481fed5797dc2651cd91e238e9b3928c6

1
vendor/StackWalker vendored

@ -1 +0,0 @@
Subproject commit 42e7a6e056a9e7aca911a7e9e54e2e4f90bc2652

2
vendor/fmtlib vendored

@ -1 +1 @@
Subproject commit 9e554999ce02cf86fcdfe74fe740c4fe3f5a56d5 Subproject commit e00997b004713a8de4ea480d7dfb3abb11d07852

1
vendor/g3log vendored Submodule

@ -0,0 +1 @@
Subproject commit 3ffc36a3a2d07e2c1e51acfe5e04856f87639488

2
vendor/json vendored

@ -1 +1 @@
Subproject commit 53c3eefa2cf790a7130fed3e13a3be35c2f2ace2 Subproject commit 456478b3c50d60100dbb1fb9bc931f370a2c1c28