Merge branch 'develop_official' into feature/xinput
# Conflicts: # src/Components/Loader.cpp
This commit is contained in:
commit
570d2acdac
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
36
.github/labeler.yml
vendored
36
.github/labeler.yml
vendored
@ -1,36 +0,0 @@
|
||||
"part: game client":
|
||||
- src/Components/Modules/Stats*
|
||||
|
||||
"part: game server":
|
||||
- src/Components/Modules/Dedicated*
|
||||
|
||||
"part: zonebuilder":
|
||||
- src/Components/Modules/ZoneBuilder*
|
||||
|
||||
"area: menus":
|
||||
- src/Components/Modules/Menus*
|
||||
|
||||
"area: anticheat":
|
||||
- src/Components/Modules/AntiCheat*
|
||||
|
||||
"area: serverlist":
|
||||
- src/Components/Modules/ServerList*
|
||||
|
||||
"area: weapons":
|
||||
- src/Components/Modules/Weapon*
|
||||
|
||||
"area: networking":
|
||||
- src/Components/Modules/Auth*
|
||||
- src/Components/Modules/Network*
|
||||
- src/Components/Modules/Node*
|
||||
- src/Components/Modules/PlayerName*
|
||||
- src/Components/Modules/RCon*
|
||||
- src/Components/Modules/Session*
|
||||
|
||||
"area: continuous integration":
|
||||
- "*appveyor*"
|
||||
- ".github/workflows/**"
|
||||
- Jenkinsfile
|
||||
|
||||
"status: work in progress":
|
||||
- "**"
|
11
.github/workflows/labeler.yml
vendored
11
.github/workflows/labeler.yml
vendored
@ -1,11 +0,0 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v2
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
2
deps/json11
vendored
2
deps/json11
vendored
@ -1 +1 @@
|
||||
Subproject commit e2e3a11e99672b018e0e0657867e6a3439e180cf
|
||||
Subproject commit 2df9473fb3605980db55ecddf34392a2e832ad35
|
2
deps/libtomcrypt
vendored
2
deps/libtomcrypt
vendored
@ -1 +1 @@
|
||||
Subproject commit 1937f412605e1b04ddb41ef9c2f2f0aab7e61548
|
||||
Subproject commit 673f5ce29015a9bba3c96792920a10601b5b0718
|
2
deps/libtommath
vendored
2
deps/libtommath
vendored
@ -1 +1 @@
|
||||
Subproject commit 6ac0b0c1b69b9a88e1b3b3002c2e3a9062ae99b4
|
||||
Subproject commit eda0bd6ae5705ab90b866dfb52c5f15c23687f81
|
2
deps/pdcurses
vendored
2
deps/pdcurses
vendored
@ -1 +1 @@
|
||||
Subproject commit 618e0aaa31b4728eb4df78ec4de6c2b873908eda
|
||||
Subproject commit 4bc97e287be5d8927405614c193fd0a039df027a
|
2
deps/protobuf
vendored
2
deps/protobuf
vendored
@ -1 +1 @@
|
||||
Subproject commit 63cfdafacba6141717a2df97fc123dc0c14ba7c4
|
||||
Subproject commit df2bce345d4bc8cdc3eba2a866e11e79e1fff4df
|
2
deps/zlib
vendored
2
deps/zlib
vendored
@ -1 +1 @@
|
||||
Subproject commit d71dc66fa8a153fb6e7c626847095d9697a6cf42
|
||||
Subproject commit c3f3043f7aa80750245f8166a338c4877020b589
|
@ -1,4 +1,4 @@
|
||||
@echo off
|
||||
echo Updating submodules...
|
||||
call git submodule update --init --recursive
|
||||
call tools\premake5 %* vs2019
|
||||
call tools\premake5 %* vs2019 --ac-disable
|
||||
|
@ -101,6 +101,7 @@ namespace Components
|
||||
Loader::Register(new StructuredData());
|
||||
Loader::Register(new ConnectProtocol());
|
||||
Loader::Register(new StartupMessages());
|
||||
Loader::Register(new SoundMutexFix());
|
||||
Loader::Register(new Gamepad());
|
||||
|
||||
Loader::Register(new Client());
|
||||
|
@ -130,6 +130,7 @@ namespace Components
|
||||
#include "Modules/ConnectProtocol.hpp"
|
||||
#include "Modules/StartupMessages.hpp"
|
||||
#include "Modules/Stats.hpp"
|
||||
#include "Modules/SoundMutexFix.hpp"
|
||||
|
||||
#include "Modules/Gamepad.hpp"
|
||||
#include "Modules/Client.hpp"
|
||||
|
@ -889,12 +889,8 @@ namespace Components
|
||||
time(nullptr);
|
||||
AntiCheat::Flags = NO_FLAG;
|
||||
|
||||
#ifdef DISABLE_ANTICHEAT
|
||||
Command::Add("penis", [](Command::Params*)
|
||||
{
|
||||
AntiCheat::CrashClient();
|
||||
});
|
||||
#else
|
||||
#ifndef DISABLE_ANTICHEAT
|
||||
|
||||
Utils::Hook(0x507BD5, AntiCheat::PatchWinAPI, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x5082FD, AntiCheat::LostD3DStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x51C76C, AntiCheat::CinematicStub, HOOK_CALL).install()->quick();
|
||||
|
@ -76,6 +76,29 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
void Dedicated::StripMaterialTextIcons(char* text)
|
||||
{
|
||||
char* currentChar = text;
|
||||
bool isEscaped = false;
|
||||
while (*currentChar)
|
||||
{
|
||||
if (*currentChar == '^')
|
||||
{
|
||||
isEscaped = true;
|
||||
}
|
||||
else if(isEscaped == true && (*currentChar == '\x01' || *currentChar == '\x02'))
|
||||
{
|
||||
*currentChar = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
isEscaped = false;
|
||||
}
|
||||
|
||||
currentChar++;
|
||||
}
|
||||
}
|
||||
|
||||
const char* Dedicated::EvaluateSay(char* text, Game::gentity_t* player)
|
||||
{
|
||||
Dedicated::SendChat = true;
|
||||
@ -87,6 +110,8 @@ namespace Components
|
||||
++text;
|
||||
}
|
||||
|
||||
StripMaterialTextIcons(text);
|
||||
|
||||
Game::Scr_AddEntity(player);
|
||||
Game::Scr_AddString(text + 1);
|
||||
Game::Scr_NotifyLevel(Game::SL_GetString("say", 0), 2);
|
||||
@ -103,7 +128,7 @@ namespace Components
|
||||
push eax
|
||||
pushad
|
||||
|
||||
push[esp + 100h + 28h]
|
||||
push [esp + 100h + 28h]
|
||||
push eax
|
||||
call Dedicated::EvaluateSay
|
||||
add esp, 8h
|
||||
|
@ -14,6 +14,8 @@ namespace Components
|
||||
|
||||
static void Heartbeat();
|
||||
|
||||
static void StripMaterialTextIcons(char* text);
|
||||
|
||||
private:
|
||||
static bool SendChat;
|
||||
|
||||
|
@ -186,6 +186,7 @@ namespace Components
|
||||
"Deity",
|
||||
"Dizzy",
|
||||
"Dss0",
|
||||
"FutureRave",
|
||||
"H3X1C",
|
||||
"HardNougat",
|
||||
"Homura",
|
||||
@ -193,7 +194,6 @@ namespace Components
|
||||
"Killera",
|
||||
"Lithium",
|
||||
"Louvenarde",
|
||||
"FutureRave",
|
||||
"OneFourOne",
|
||||
"quaK",
|
||||
"RaidMax",
|
||||
|
@ -771,6 +771,7 @@ namespace Components
|
||||
Maps::AddDlc({ 6, "Freighter", {"mp_cargoship_sh"} });
|
||||
Maps::AddDlc({ 7, "Resurrection Pack", {"mp_shipment_long", "mp_rust_long", "mp_firingrange"} });
|
||||
Maps::AddDlc({ 8, "Recycled Pack", {"mp_bloc_sh", "mp_crash_tropical", "mp_estate_tropical", "mp_fav_tropical", "mp_storm_spring"} });
|
||||
Maps::AddDlc({ 9, "Classics Pack #3", {"mp_farm", "mp_backlot", "mp_pipeline", "mp_countdown", "mp_crash_snow"} });
|
||||
|
||||
Maps::UpdateDlcStatus();
|
||||
|
||||
|
@ -161,7 +161,12 @@ namespace Components
|
||||
Materials::ImageNameLength = 4 + length;
|
||||
std::string image(imagePtr, length);
|
||||
|
||||
return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, image.data()).material;
|
||||
auto* material = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, image.data()).material;
|
||||
|
||||
if(material == nullptr || material->techniqueSet == nullptr || material->techniqueSet->name == nullptr || strcmp(material->techniqueSet->name, "2d") != 0)
|
||||
return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material;
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
Materials::ImageNameLength = 4;
|
||||
|
@ -421,8 +421,8 @@ namespace Components
|
||||
{
|
||||
int data = false;
|
||||
const Utils::Library ntdll("ntdll.dll");
|
||||
ntdll.InvokePascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.InvokePascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
ntdll.invokePascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.invokePascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
});
|
||||
|
||||
// Filtering any mapents that is intended for Spec:Ops gamemode (CODO) and prevent them from spawning
|
||||
|
@ -127,7 +127,7 @@ namespace Components
|
||||
|
||||
// show error
|
||||
pushad;
|
||||
push[esp + 24h + 20h];
|
||||
push [esp + 24h + 20h];
|
||||
push eax;
|
||||
call R_TextureFromCodeError;
|
||||
add esp, 8;
|
||||
|
@ -469,9 +469,19 @@ namespace Components
|
||||
server.ping = (Game::Sys_Milliseconds() - i->sendTime);
|
||||
server.addr = address;
|
||||
|
||||
Dedicated::StripMaterialTextIcons(server.hostname.data());
|
||||
Dedicated::StripMaterialTextIcons(server.mapname.data());
|
||||
Dedicated::StripMaterialTextIcons(server.gametype.data());
|
||||
Dedicated::StripMaterialTextIcons(server.mod.data());
|
||||
|
||||
// Remove server from queue
|
||||
i = ServerList::RefreshContainer.servers.erase(i);
|
||||
|
||||
// Servers with more than 18 players or less than 0 players are faking for sure
|
||||
// So lets ignore those
|
||||
if (server.clients > 18 || server.maxClients > 18 || server.clients < 0 || server.maxClients < 0)
|
||||
return;
|
||||
|
||||
// Check if already inserted and remove
|
||||
auto list = ServerList::GetList();
|
||||
if (!list) return;
|
||||
|
@ -21,11 +21,11 @@ namespace Components
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
push [esp + 20h]
|
||||
|
||||
push [esp + 24h]
|
||||
call SlowMotion::ApplySlowMotion
|
||||
add esp, 4h
|
||||
|
||||
pop ecx
|
||||
popad
|
||||
|
||||
retn
|
||||
@ -76,10 +76,10 @@ namespace Components
|
||||
|
||||
void SlowMotion::DrawConnectionInterruptedStub(int /*a1*/)
|
||||
{
|
||||
// if (!*reinterpret_cast<bool*>(0x1AD8ED0) && !*reinterpret_cast<bool*>(0x1AD8EEC) && !*reinterpret_cast<int*>(0x1AD78F8))
|
||||
// {
|
||||
// Utils::Hook::Call<void(int)>(0x454A70)(a1);
|
||||
// }
|
||||
// if (!*reinterpret_cast<bool*>(0x1AD8ED0) && !*reinterpret_cast<bool*>(0x1AD8EEC) && !*reinterpret_cast<int*>(0x1AD78F8))
|
||||
// {
|
||||
// Utils::Hook::Call<void(int)>(0x454A70)(a1);
|
||||
// }
|
||||
}
|
||||
|
||||
SlowMotion::SlowMotion()
|
||||
@ -91,4 +91,4 @@ namespace Components
|
||||
Utils::Hook(0x4A54ED, SlowMotion::DrawConnectionInterruptedStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4A54FB, SlowMotion::DrawConnectionInterruptedStub, HOOK_CALL).install()->quick();
|
||||
}
|
||||
}
|
||||
}
|
39
src/Components/Modules/SoundMutexFix.cpp
Normal file
39
src/Components/Modules/SoundMutexFix.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
namespace Components
|
||||
{
|
||||
// This component is a workaround for issue https://github.com/XLabsProject/iw4x-client/issues/80
|
||||
// In case the link goes down, this is a "game hangs randomly" issue:
|
||||
//
|
||||
// Investigations on the issue pointed out it comes from a situation on Intel processors where
|
||||
// WaitForSingleObjectA is ignored by a thread, for some (?) reason.
|
||||
//
|
||||
// This locks up the game randomly, mostly at the end of rounds or when too many things happen at
|
||||
// once, due to trying to stop sounds (AIL_Stop_sounds) and playing streams at the same time,
|
||||
// rushing for the same resource via AIL_lock_mutex.
|
||||
//
|
||||
// This bug has been reproduced on mp_terminal, mp_overgrown, mp_rust, with and without bots,
|
||||
// and so far this has been the only way to circumvent it afaik. This component wraps
|
||||
// miles' mutex into another mutex, created below, and for some reason (?) that mutex is
|
||||
// respected when miles' is not.
|
||||
//
|
||||
// As soon as a real fix is found, please discard this fix. In the meantime, it should not
|
||||
// have side effects too bad - worst case it might cause a slight performance drop during
|
||||
// team switch and intermission.
|
||||
//
|
||||
|
||||
std::mutex SoundMutexFix::SNDMutex;
|
||||
|
||||
void __stdcall SoundMutexFix::LockSoundMutex(int unk)
|
||||
{
|
||||
std::lock_guard lock(SoundMutexFix::SNDMutex);
|
||||
|
||||
DWORD funcPtr = *reinterpret_cast<DWORD*>(0x6D7554); // AIL_close_stream
|
||||
Utils::Hook::Call<void __stdcall(int)>(funcPtr)(unk);
|
||||
}
|
||||
|
||||
SoundMutexFix::SoundMutexFix()
|
||||
{
|
||||
Utils::Hook(0x689EFE, &SoundMutexFix::LockSoundMutex, HOOK_JUMP).install()->quick();
|
||||
}
|
||||
}
|
15
src/Components/Modules/SoundMutexFix.hpp
Normal file
15
src/Components/Modules/SoundMutexFix.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class SoundMutexFix : public Component
|
||||
{
|
||||
public:
|
||||
SoundMutexFix();
|
||||
|
||||
private:
|
||||
static std::mutex SNDMutex;
|
||||
static void _stdcall LockSoundMutex(int unk);
|
||||
};
|
||||
}
|
@ -384,25 +384,25 @@ namespace Steam
|
||||
Proxy::LaunchWatchGuard();
|
||||
|
||||
Proxy::Overlay = ::Utils::Library(GAMEOVERLAY_LIB, false);
|
||||
if (!Proxy::Overlay.IsValid()) return false;
|
||||
if (!Proxy::Overlay.isValid()) return false;
|
||||
}
|
||||
|
||||
Proxy::Client = ::Utils::Library(STEAMCLIENT_LIB, false);
|
||||
if (!Proxy::Client.IsValid()) return false;
|
||||
if (!Proxy::Client.isValid()) return false;
|
||||
|
||||
Proxy::SteamClient = Proxy::Client.Get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
|
||||
Proxy::SteamClient = Proxy::Client.get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
|
||||
if(!Proxy::SteamClient) return false;
|
||||
|
||||
Proxy::SteamBGetCallback = Proxy::Client.Get<Proxy::SteamBGetCallbackFn>("Steam_BGetCallback");
|
||||
Proxy::SteamBGetCallback = Proxy::Client.get<Proxy::SteamBGetCallbackFn>("Steam_BGetCallback");
|
||||
if (!Proxy::SteamBGetCallback) return false;
|
||||
|
||||
Proxy::SteamFreeLastCallback = Proxy::Client.Get<Proxy::SteamFreeLastCallbackFn>("Steam_FreeLastCallback");
|
||||
Proxy::SteamFreeLastCallback = Proxy::Client.get<Proxy::SteamFreeLastCallbackFn>("Steam_FreeLastCallback");
|
||||
if (!Proxy::SteamFreeLastCallback) return false;
|
||||
|
||||
Proxy::SteamGetAPICallResult = Proxy::Client.Get<Proxy::SteamGetAPICallResultFn>("Steam_GetAPICallResult");
|
||||
Proxy::SteamGetAPICallResult = Proxy::Client.get<Proxy::SteamGetAPICallResultFn>("Steam_GetAPICallResult");
|
||||
if (!Proxy::SteamGetAPICallResult) return false;
|
||||
|
||||
Proxy::SteamClient = Proxy::Client.Get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
|
||||
Proxy::SteamClient = Proxy::Client.get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
|
||||
if (!Proxy::SteamClient) return false;
|
||||
|
||||
Proxy::SteamPipe = Proxy::SteamClient->CreateSteamPipe();
|
||||
@ -411,7 +411,7 @@ namespace Steam
|
||||
Proxy::SteamUser = Proxy::SteamClient->ConnectToGlobalUser(Proxy::SteamPipe);
|
||||
if (!Proxy::SteamUser) return false;
|
||||
|
||||
Proxy::ClientEngine = Proxy::Client.Get<IClientEngine*(const char*, int*)>("CreateInterface")("CLIENTENGINE_INTERFACE_VERSION005", nullptr);
|
||||
Proxy::ClientEngine = Proxy::Client.get<IClientEngine*(const char*, int*)>("CreateInterface")("CLIENTENGINE_INTERFACE_VERSION005", nullptr);
|
||||
if (!Proxy::ClientEngine) return false;
|
||||
|
||||
Proxy::ClientUser = Proxy::ClientEngine->GetIClientUser(Proxy::SteamUser, Proxy::SteamPipe);
|
||||
@ -526,17 +526,17 @@ namespace Steam
|
||||
|
||||
void Proxy::SetOverlayNotificationPosition(uint32_t eNotificationPosition)
|
||||
{
|
||||
if (Proxy::Overlay.IsValid())
|
||||
if (Proxy::Overlay.isValid())
|
||||
{
|
||||
Proxy::Overlay.Get<void(uint32_t)>("SetNotificationPosition")(eNotificationPosition);
|
||||
Proxy::Overlay.get<void(uint32_t)>("SetNotificationPosition")(eNotificationPosition);
|
||||
}
|
||||
}
|
||||
|
||||
bool Proxy::IsOverlayEnabled()
|
||||
{
|
||||
if (Proxy::Overlay.IsValid())
|
||||
if (Proxy::Overlay.isValid())
|
||||
{
|
||||
return Proxy::Overlay.Get<bool()>("IsOverlayEnabled")();
|
||||
return Proxy::Overlay.get<bool()>("IsOverlayEnabled")();
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -544,9 +544,9 @@ namespace Steam
|
||||
|
||||
bool Proxy::BOverlayNeedsPresent()
|
||||
{
|
||||
if (Proxy::Overlay.IsValid())
|
||||
if (Proxy::Overlay.isValid())
|
||||
{
|
||||
return Proxy::Overlay.Get<bool()>("BOverlayNeedsPresent")();
|
||||
return Proxy::Overlay.get<bool()>("BOverlayNeedsPresent")();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -40,23 +40,23 @@ namespace Utils
|
||||
{
|
||||
if (this->freeOnDestroy)
|
||||
{
|
||||
this->Free();
|
||||
this->free();
|
||||
}
|
||||
}
|
||||
|
||||
bool Library::IsValid() const
|
||||
bool Library::isValid() const
|
||||
{
|
||||
return this->_module != nullptr;
|
||||
}
|
||||
|
||||
HMODULE Library::GetModule()
|
||||
HMODULE Library::getModule()
|
||||
{
|
||||
return this->_module;
|
||||
}
|
||||
|
||||
void Library::Free()
|
||||
void Library::free()
|
||||
{
|
||||
if (this->IsValid())
|
||||
if (this->isValid())
|
||||
{
|
||||
FreeLibrary(this->_module);
|
||||
}
|
||||
|
@ -15,48 +15,48 @@ namespace Utils
|
||||
explicit Library(HMODULE handle);
|
||||
~Library();
|
||||
|
||||
bool IsValid() const;
|
||||
HMODULE GetModule();
|
||||
bool isValid() const;
|
||||
HMODULE getModule();
|
||||
|
||||
template <typename T>
|
||||
T GetProc(const std::string& process) const
|
||||
T getProc(const std::string& process) const
|
||||
{
|
||||
if (!this->IsValid()) T{};
|
||||
if (!this->isValid()) T{};
|
||||
return reinterpret_cast<T>(GetProcAddress(this->_module, process.data()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::function<T> Get(const std::string& process) const
|
||||
std::function<T> get(const std::string& process) const
|
||||
{
|
||||
if (!this->IsValid()) return std::function<T>();
|
||||
return static_cast<T*>(this->GetProc<void*>(process));
|
||||
if (!this->isValid()) return std::function<T>();
|
||||
return static_cast<T*>(this->getProc<void*>(process));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T Invoke(const std::string& process, Args ... args) const
|
||||
T invoke(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->Get<T(__cdecl)(Args ...)>(process);
|
||||
auto method = this->get<T(__cdecl)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T InvokePascal(const std::string& process, Args ... args) const
|
||||
T invokePascal(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->Get<T(__stdcall)(Args ...)>(process);
|
||||
auto method = this->get<T(__stdcall)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T InvokeThis(const std::string& process, void* this_ptr, Args ... args) const
|
||||
T invokeThis(const std::string& process, void* this_ptr, Args ... args) const
|
||||
{
|
||||
auto method = this->Get<T(__thiscall)(void*, Args ...)>(this_ptr, process);
|
||||
auto method = this->get<T(__thiscall)(void*, Args ...)>(this_ptr, process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
void Free();
|
||||
void free();
|
||||
|
||||
private:
|
||||
HMODULE _module;
|
||||
|
Loading…
Reference in New Issue
Block a user