Make menu unloadable

This commit is contained in:
Grinch_ 2021-02-26 04:45:41 +06:00
parent b9cc290603
commit 86431a9eac
20 changed files with 224 additions and 199 deletions

View File

@ -1,8 +1,9 @@
/* Slightly modified version of https://github.com/Rebzzel/kiero
/* Modified version of https://github.com/Rebzzel/kiero
MIT License
Copyright(c) 2014 - 2020 Rebzzel
Copyright(c) 2021 Grinch_
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal

3
deps/kiero/kiero.h vendored
View File

@ -1,8 +1,9 @@
/* Slightly modified version of https://github.com/Rebzzel/kiero
/* Modified version of https://github.com/Rebzzel/kiero
MIT License
Copyright(c) 2014 - 2020 Rebzzel
Copyright(c) 2021 Grinch_
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal

View File

@ -3,32 +3,13 @@
#include "MenuInfo.h"
#include "Ui.h"
unsortedMap CheatMenu::header{
CallbackTable CheatMenu::header{
{ "Teleport", &Teleport::Draw },{ "Player", &Player::Draw },{ "Ped", &Ped::Draw },
{ "Animation", &Animation::Draw },{ "Vehicle", &Vehicle::Draw },{ "Weapon", &Weapon::Draw },
{ "Game", &Game::Draw },{ "Visual", &Visual::Draw },{ "Menu", &Menu::Draw }
};
void CheatMenu::DrawMenu()
{
ImGui::SetNextWindowSize(Globals::menu_size);
if (ImGui::Begin(MENU_TITLE, &Globals::show_menu, ImGuiWindowFlags_NoCollapse))
{
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(250, 350));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(ImGui::GetWindowWidth() / 85, ImGui::GetWindowHeight() / 200));
Ui::DrawHeaders(header);
Globals::menu_size = ImGui::GetWindowSize();
config.SetValue("window.sizeX", Globals::menu_size.x);
config.SetValue("window.sizeY", Globals::menu_size.y);
ImGui::PopStyleVar(2);
ImGui::End();
}
}
void CheatMenu::ProcessWindow()
void CheatMenu::DrawWindow()
{
ImGuiIO& io = ImGui::GetIO();
@ -38,18 +19,61 @@ void CheatMenu::ProcessWindow()
if (Globals::show_menu || Menu::commands::show_menu)
{
if (Globals::show_menu)
DrawMenu();
{
ImGui::SetNextWindowSize(Globals::menu_size);
if (ImGui::Begin(MENU_TITLE, &Globals::show_menu, ImGuiWindowFlags_NoCollapse))
{
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(250, 350));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(ImGui::GetWindowWidth() / 85, ImGui::GetWindowHeight() / 200));
Ui::DrawHeaders(header);
Globals::menu_size = ImGui::GetWindowSize();
config.SetValue("window.sizeX", Globals::menu_size.x);
config.SetValue("window.sizeY", Globals::menu_size.y);
ImGui::PopStyleVar(2);
ImGui::End();
}
}
else
Menu::DrawShortcutsWindow();
}
Menu::ProcessOverlay();
Menu::DrawOverlay();
}
void CheatMenu::ProcessEvent()
{
if (Globals::init_done && !FrontEndMenuManager.m_bMenuActive)
{
if (Ui::HotKeyPressed(hotkeys::menu_open))
Globals::show_menu = !Globals::show_menu;
if (Ui::HotKeyPressed(hotkeys::command_window))
{
if (Menu::commands::show_menu)
{
Menu::ProcessCommands();
strcpy(commands::input_buffer, "");
}
Menu::commands::show_menu = !Menu::commands::show_menu;
}
if (Hook::show_mouse != Globals::show_menu)
{
if (Hook::show_mouse) // Only write when the menu closes
config.WriteToDisk();
Hook::show_mouse = Globals::show_menu;
}
}
}
CheatMenu::CheatMenu()
{
ApplyStyle();
Hook::window_callback = std::bind(&ProcessWindow);
Hook::window_callback = std::bind(&DrawWindow);
// Load menu settings
Globals::header_id = config.GetValue("window.id", std::string(""));
@ -57,32 +81,12 @@ CheatMenu::CheatMenu()
Globals::menu_size.y = config.GetValue("window.sizeY", screen::GetScreenHeight() / 1.2f);
srand(CTimer::m_snTimeInMilliseconds);
Events::processScriptsEvent += []
{
if (Globals::init_done && !FrontEndMenuManager.m_bMenuActive)
{
if (Ui::HotKeyPressed(hotkeys::menu_open))
Globals::show_menu = !Globals::show_menu;
Events::processScriptsEvent += ProcessEvent;
}
if (Ui::HotKeyPressed(hotkeys::command_window))
{
if (Menu::commands::show_menu)
{
Menu::ProcessCommands();
strcpy(commands::input_buffer, "");
}
Menu::commands::show_menu = !Menu::commands::show_menu;
}
if (Hook::show_mouse != Globals::show_menu)
{
if (Hook::show_mouse) // Only write when the menu closes
config.WriteToDisk();
Hook::show_mouse = Globals::show_menu;
}
}
};
CheatMenu::~CheatMenu()
{
Events::processScriptsEvent -= ProcessEvent;
}
void CheatMenu::ApplyStyle()
@ -159,16 +163,20 @@ void CheatMenu::ApplyStyle()
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
}
void HasGameInit()
{
Globals::game_init = true;
}
void MenuThread(void* param)
{
// Wait till the game is initiallized
Events::initGameEvent.after += []()
{
Globals::game_init = true;
};
// Wait till the game is initialized
Events::initGameEvent.after += HasGameInit;
while (!Globals::game_init)
Sleep(500);
Sleep(1000);
Events::initGameEvent.after -= HasGameInit;
if (GetModuleHandle("SAMP.dll"))
{
@ -185,10 +193,25 @@ void MenuThread(void* param)
flog << "Starting...\nVersion: " MENU_TITLE "\nAuthor: Grinch_\nDiscord: " DISCORD_INVITE "\nMore Info: " GITHUB_LINK "\n\n" << std::endl;
CFastman92limitAdjuster::Init();
CheatMenu cheatmenu;
CheatMenu *menu = new CheatMenu;
while (true)
Sleep(5000);
{
Sleep(50);
if (KeyPressed(VK_TAB))
break;
}
delete menu;
Sleep(100);
// reset mouse patches
patch::SetUChar(0x6194A0, 0xE9);
patch::SetUChar(0x746ED0, 0xA1);
patch::SetRaw(0x53F41F, (void*)"\x85\xC0\x0F\x8C", 4);
FreeLibraryAndExitThread(NULL,0);
}
BOOL WINAPI DllMain(HINSTANCE hDllHandle, DWORD nReason, LPVOID Reserved)

View File

@ -21,12 +21,14 @@
class CheatMenu : Hook, Animation, Game, Menu, Ped, Player, Teleport, Vehicle, Visual, Weapon
{
private:
static unsortedMap header;
static void DrawMenu();
static void ProcessWindow();
static CallbackTable header;
static void ApplyStyle();
static void DrawWindow();
static void ProcessEvent();
public:
CheatMenu();
~CheatMenu();
};

View File

@ -1,7 +1,6 @@
#include "Hook.h"
#include "kiero/kiero.h"
#include "kiero/minhook/MinHook.h"
// #include "vulkan/vulkan.h"
WNDPROC Hook::oWndProc = NULL;
f_Present11 Hook::oPresent11 = NULL;
@ -46,10 +45,13 @@ HRESULT Hook::Reset(IDirect3DDevice9* pDevice, D3DPRESENT_PARAMETERS* pPresentat
void Hook::Present(void* ptr)
{
if (!ImGui::GetCurrentContext())
return;
ImGuiIO& io = ImGui::GetIO();
if (Globals::init_done)
{
{
Hook::ShowMouse(show_mouse);
// handle window scaling here
@ -129,8 +131,6 @@ void Hook::Present(void* ptr)
reinterpret_cast<ID3D11Device*>(Globals::device)->GetImmediateContext(&context);
ImGui_ImplDX11_Init(reinterpret_cast<ID3D11Device*>(Globals::device), context);
//ImGui_ImplVulkan_Init()
}
ImGui_ImplWin32_EnableDpiAwareness();
@ -146,7 +146,7 @@ void Hook::Present(void* ptr)
HRESULT Hook::PresentDx9Handler(IDirect3DDevice9* pDevice, RECT* pSourceRect, RECT* pDestRect, HWND hDestWindowOverride, RGNDATA* pDirtyRegion)
{
Present(pDevice);
return oPresent9(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);;
return oPresent9(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}
HRESULT Hook::PresentDx11Handler(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)
@ -155,15 +155,6 @@ HRESULT Hook::PresentDx11Handler(IDXGISwapChain* pSwapChain, UINT SyncInterval,
return oPresent11(pSwapChain, SyncInterval, Flags);
}
// typedef void(*func_vkCmdDrawIndexed_t) (VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance);
// func_vkCmdDrawIndexed_t ovkCmdDrawIndexed;
// void hvkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance)
// {
// ovkCmdDrawIndexed(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
// }
// Thanks imring
void Hook::ShowMouse(bool state)
{
@ -173,7 +164,7 @@ void Hook::ShowMouse(bool state)
CPad::NewMouseControllerState.Y = 0;
patch::SetUChar(0x6194A0, 0xC3);
// Since Windowed mode by ThirteenAG hooks this too
// Don't nop this, WindowedMode uses it
// patch::Nop(0x53F417, 5); // don't call CPad__getMouseState
patch::SetUChar(0x746ED0, 0xC3);
@ -208,25 +199,26 @@ Hook::Hook()
{
ImGui::CreateContext();
if (kiero::init(kiero::RenderType::D3D9) == kiero::Status::Success)
// gtaRenderHook
if (kiero::init(kiero::RenderType::D3D11) == kiero::Status::Success)
{
Globals::renderer = Render_DirectX9;
kiero::bind(16, (void**)&oReset9, Reset);
kiero::bind(17, (void**)&oPresent9, PresentDx9Handler);
Globals::renderer = Render_DirectX11;
kiero::bind(8, (void**)&oPresent11, PresentDx11Handler);
}
else
{
// gtaRenderHook
if (kiero::init(kiero::RenderType::D3D11) == kiero::Status::Success)
if (kiero::init(kiero::RenderType::D3D9) == kiero::Status::Success)
{
Globals::renderer = Render_DirectX11;
kiero::bind(8, (void**)&oPresent11, PresentDx11Handler);
Globals::renderer = Render_DirectX9;
kiero::bind(16, (void**)&oReset9, Reset);
kiero::bind(17, (void**)&oPresent9, PresentDx9Handler);
}
}
}
Hook::~Hook()
{
SetWindowLongPtr(RsGlobal.ps->window, GWL_WNDPROC, (LRESULT)oWndProc);
ImGui_ImplDX9_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();

View File

@ -26,7 +26,6 @@ private:
protected:
static bool show_mouse;
static std::function<void()> window_callback;
Hook();
~Hook();
};

View File

@ -15,7 +15,7 @@ CJson::CJson(const char* name)
}
catch (...)
{
flog << "Error occured trying to read " << file_path << std::endl;
flog << "Error trying to read " << file_path << std::endl;
data = "{}"_json;
}
}
@ -37,9 +37,4 @@ void CJson::LoadData(std::vector<std::string>& vec, std::string& selected) // Te
{
for (auto element : data.items())
vec.push_back(element.key());
}
CJson::~CJson()
{
// Saving here won't work on crash
}
}

View File

@ -106,7 +106,6 @@ public:
*/
void WriteToDisk();
CJson(const char* text);
~CJson();
};

View File

@ -87,7 +87,7 @@ Menu::Menu()
hotkeys::veh_instant_stop.key2 = config.GetValue("hotkey.veh_instant_stop.key2", VK_NONE);
}
void Menu::ProcessOverlay()
void Menu::DrawOverlay()
{
CPlayerPed* player = FindPlayerPed();
bool show_menu = overlay::coord || overlay::fps || overlay::loc_name ||

View File

@ -41,9 +41,8 @@ public:
Menu();
static void Draw();
static void ProcessOverlay();
static void DrawOverlay();
static void DrawShortcutsWindow();
static void ProcessCommands();
};

View File

@ -5,48 +5,52 @@
VehicleExtendedData<Neon::NeonData> Neon::VehNeon;
RwTexture* Neon::neon_texture = nullptr;
void Neon::RenderEvent(CVehicle *pVeh)
{
NeonData* data = &VehNeon.Get(pVeh);
if (data->neon_installed && !pVeh->IsUpsideDown())
{
CVector Pos = CModelInfo::GetModelInfo(pVeh->m_nModelIndex)->m_pColModel->m_boundBox.m_vecMin;
CVector center = pVeh->TransformFromObjectSpace(CVector(0.0f, 0.0f, 0.0f));
CVector up = pVeh->TransformFromObjectSpace(CVector(0.0f, -Pos.y - data->val, 0.0f)) - center;
CVector right = pVeh->TransformFromObjectSpace(CVector(Pos.x + data->val, 0.0f, 0.0f)) - center;
CShadows::StoreShadowToBeRendered(5, neon_texture, &center, up.x, up.y, right.x, right.y, 180, data->color.r, data->color.g, data->color.b, 2.0f, false, 1.0f, 0, true);
if (CTimer::m_snTimeInMilliseconds - data->timer > 150)
{
data->timer = CTimer::m_snTimeInMilliseconds;
if (data->pulsing)
{
if (data->val < 0.0f)
data->increment = true;
if (data->val > 0.3f)
data->increment = false;
if (data->increment)
data->val += 0.1f;
else
data->val -= 0.1f;
}
}
}
}
Neon::Neon()
{
neon_texture = Util::LoadTextureFromPngFile(PLUGIN_PATH((char*)"CheatMenu\\vehicles\\neon_mask.png"));
if (!neon_texture)
flog << "WARN: Failed to load neon mask" << std::endl;
flog << "Failed to load neon mask" << std::endl;
Events::vehicleRenderEvent += [](CVehicle* pVeh)
{
NeonData* data = &VehNeon.Get(pVeh);
if (data->neon_installed && !pVeh->IsUpsideDown())
{
CVector Pos = CModelInfo::GetModelInfo(pVeh->m_nModelIndex)->m_pColModel->m_boundBox.m_vecMin;
CVector center = pVeh->TransformFromObjectSpace(CVector(0.0f, 0.0f, 0.0f));
CVector up = pVeh->TransformFromObjectSpace(CVector(0.0f, -Pos.y - data->val, 0.0f)) - center;
CVector right = pVeh->TransformFromObjectSpace(CVector(Pos.x + data->val, 0.0f, 0.0f)) - center;
CShadows::StoreShadowToBeRendered(5, neon_texture, &center, up.x, up.y, right.x, right.y, 180, data->color.r, data->color.g, data->color.b, 2.0f, false, 1.0f, 0, true);
if (CTimer::m_snTimeInMilliseconds - data->timer > 150)
{
data->timer = CTimer::m_snTimeInMilliseconds;
if (data->pulsing)
{
if (data->val < 0.0f)
data->increment = true;
if (data->val > 0.3f)
data->increment = false;
if (data->increment)
data->val += 0.1f;
else
data->val -= 0.1f;
}
}
}
};
Events::vehicleRenderEvent += RenderEvent;
}
Neon::~Neon()
{
delete neon_texture;
Events::vehicleRenderEvent -= RenderEvent;
RwTextureDestroy(neon_texture);
}
bool Neon::IsNeonInstalled(CVehicle* pVeh)

View File

@ -33,5 +33,6 @@ public:
static bool IsPulsingEnabled(CVehicle* veh);
static void SetPulsing(CVehicle* veh, bool state);
static void RemoveNeon(CVehicle* veh);
static void RenderEvent(CVehicle* veh);
};

View File

@ -34,6 +34,62 @@ VehicleExtendedData<Paint::VehData> Paint::vehdata;
std::map<std::string, std::shared_ptr<RwTexture>> Paint::textures;
void Paint::RenderEvent(CVehicle* pVeh)
{
VehData& data = vehdata.Get(pVeh);
// reset custom color if color id changed
if (pVeh->m_nPrimaryColor != data.primary_color
|| pVeh->m_nSecondaryColor != data.secondary_color)
{
for (auto& it : data.materialProperties)
data.resetMaterialColor(it.first);
data.primary_color = pVeh->m_nPrimaryColor;
data.secondary_color = pVeh->m_nSecondaryColor;
}
for (auto& it : data.materialProperties)
{
if (it.second._recolor)
{
it.second._originalColor = it.first->color;
it.first->color = it.second._color;
it.second._originalGeometryFlags = it.second._geometry->flags;
it.second._geometry->flags |= rpGEOMETRYMODULATEMATERIALCOLOR;
}
if (it.second._retexture)
{
auto tex = it.second._texture.lock();
if (tex)
{
it.second._originalTexture = it.first->texture;
it.first->texture = tex.get();
}
else
{
it.second._retexture = false;
}
}
}
}
void Paint::ResetAfterRenderEvent(CVehicle* pVeh)
{
for (auto& it : vehdata.Get(pVeh).materialProperties)
{
if (it.second._recolor)
{
it.first->color = it.second._originalColor;
it.second._geometry->flags = it.second._originalGeometryFlags;
}
if (it.second._retexture)
{
it.first->texture = it.second._originalTexture;
}
}
}
Paint::Paint()
{
for (auto& p : fs::recursive_directory_iterator(PLUGIN_PATH((char*)"\\CheatMenu\\vehicles\\paintjobs\\")))
@ -45,60 +101,14 @@ Paint::Paint()
}
}
Events::vehicleRenderEvent.before += [](CVehicle* veh)
{
VehData& data = vehdata.Get(veh);
Events::vehicleRenderEvent.before += RenderEvent;
Events::vehicleResetAfterRender += ResetAfterRenderEvent;
}
// reset custom color if color id changed
if (veh->m_nPrimaryColor != data.primary_color
|| veh->m_nSecondaryColor != data.secondary_color)
{
for (auto& it : data.materialProperties)
data.resetMaterialColor(it.first);
data.primary_color = veh->m_nPrimaryColor;
data.secondary_color = veh->m_nSecondaryColor;
}
for (auto& it : data.materialProperties)
{
if (it.second._recolor)
{
it.second._originalColor = it.first->color;
it.first->color = it.second._color;
it.second._originalGeometryFlags = it.second._geometry->flags;
it.second._geometry->flags |= rpGEOMETRYMODULATEMATERIALCOLOR;
}
if (it.second._retexture)
{
auto tex = it.second._texture.lock();
if (tex)
{
it.second._originalTexture = it.first->texture;
it.first->texture = tex.get();
}
else
{
it.second._retexture = false;
}
}
}
};
Events::vehicleResetAfterRender += [](CVehicle* veh) {
for (auto& it : vehdata.Get(veh).materialProperties)
{
if (it.second._recolor)
{
it.first->color = it.second._originalColor;
it.second._geometry->flags = it.second._originalGeometryFlags;
}
if (it.second._retexture)
{
it.first->texture = it.second._originalTexture;
}
}
};
Paint::~Paint()
{
Events::vehicleRenderEvent.before -= RenderEvent;
Events::vehicleResetAfterRender -= ResetAfterRenderEvent;
}
void Paint::VehData::setMaterialColor(RpMaterial* material, RpGeometry* geometry, RwRGBA color, bool filter_mat)

View File

@ -85,11 +85,14 @@ protected:
};
Paint();
~Paint();
static void UpdateNodeListRecursive(CVehicle* pVeh);
static void NodeWrapperRecursive(RwFrame* frame, CVehicle* pVeh, std::function<void(RwFrame*)> func);
static void SetNodeColor(CVehicle* pVeh, std::string node_name, CRGBA color, bool filter_mat = false);
static void SetNodeTexture(CVehicle* pVeh, std::string node_name, std::string texturename, bool filter_mat = false);
static void ResetNodeColor(CVehicle* veh, std::string node_name);
static void ResetNodeTexture(CVehicle* pVeh, std::string node_name);
static void RenderEvent(CVehicle* pVeh);
static void ResetAfterRenderEvent(CVehicle* pVeh);
};

View File

@ -52,7 +52,7 @@ Player::Player()
if (file_name.size() < 9)
custom_skins::store_vec.push_back(file_name);
else
flog << "WARN: Custom Skin longer than 8 characters " << file_name << std::endl;
flog << "Custom Skin longer than 8 characters " << file_name << std::endl;
}
}
}

View File

@ -76,7 +76,7 @@ void Ui::CenterdText(const std::string& text)
ImGui::Text(text.c_str());
}
void Ui::DrawHeaders(unsortedMap& data)
void Ui::DrawHeaders(CallbackTable& data)
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));

View File

@ -38,7 +38,7 @@ public:
static bool CheckboxAddressVarEx(const char* label, bool val, int addr, int enabled_val, int disabled_val, const char* hint = nullptr);
static bool CheckboxBitFlag(const char* label, uint flag, const char* hint = nullptr);
static bool CheckboxWithHint(const char* label, bool* state, const char* hint = nullptr, const bool is_disabled = false);
static void DrawHeaders(unsortedMap& data);
static void DrawHeaders(CallbackTable& data);
static void DrawJSON(CJson& json, std::vector<std::string>& combo_items, std::string& selected_item, ImGuiTextFilter& filter,
std::function<void(std::string&, std::string&, std::string&)> func_left_click, std::function<void(std::string&, std::string&, std::string&)> func_right_click);

View File

@ -48,7 +48,7 @@ void Util::LoadTexturesInDirRecursive(const char* path, const char* file_ext, st
}
else
{
flog << "WARN: Failed to load " << p.path().stem().string() << std::endl;
flog << "Failed to load " << p.path().stem().string() << std::endl;
store_vec.pop_back();
}
}

View File

@ -234,7 +234,7 @@ void Vehicle::AddComponent(const std::string& component, const bool display_mess
}
catch (...)
{
flog << "Failed to add " << component << " to vehicle." << std::endl;
flog << "Failed to component to vehicle " << component << std::endl;
}
}
@ -253,7 +253,7 @@ void Vehicle::RemoveComponent(const std::string& component, const bool display_m
}
catch (...)
{
flog << "Failed to remove " << component << " from vehicle." << std::endl;
flog << "Failed to remove component from vehicle " << component << std::endl;
}
}
@ -326,7 +326,7 @@ void Vehicle::ParseVehiclesIDE()
}
catch (...)
{
flog << "Error occured while parsing line, " << line << std::endl;
flog << "Error while parsing line, " << line << std::endl;
}
}
@ -397,7 +397,7 @@ void Vehicle::ParseCarcolsDAT()
}
catch (...)
{
flog << "Error occured while parsing car line, " << line << std::endl;
flog << "Error while parsing car line, " << line << std::endl;
}
}
@ -422,7 +422,7 @@ void Vehicle::ParseCarcolsDAT()
}
catch (...)
{
flog << "Error occured while parsing car line, " << line << std::endl;
flog << "Error while parsing car line, " << line << std::endl;
}
}
}
@ -430,7 +430,7 @@ void Vehicle::ParseCarcolsDAT()
file.close();
}
else flog << "Vehicle.ide file not found";
else flog << "Error locating Vehicle.ide";
}
void Vehicle::SpawnVehicle(std::string& smodel)

View File

@ -63,19 +63,15 @@
#include "VKeys.h"
// Globals
typedef std::vector<std::pair<std::string, void(*)(void)>> unsortedMap;
typedef std::vector<std::pair<std::string, void(*)()>> CallbackTable;
using namespace plugin;
namespace fs = std::filesystem;
enum Renderer
{
Render_DirectX9,
Render_DirectX10,
Render_DirectX11,
Render_DirectX12,
Render_OpenGL,
Render_Unknown,
Render_Vulkan,
Render_Unknown
};
struct Globals