Add basic ReHLDS and ReGameDLL support (#417)

* Add ReHLDS API files and its dependencies

Note: This has been stolen from ReAPI AMXX module and modified/adjusted to match AMXX existing includes and to provide as less dependencies as possible as well

* Add the necessary files to get ReHLDS interface

* Split SV_DropClient into pre/post code

* Init ReHLDS API and add SV_DropClient hook

* Add Cvar_DirectSet hook and adjust code with helpers

Note: we don't need to split code here. This is pretty much the naive and straight way, but fairly enough for our case. If it happens we got a lot more hooks, we may consider to use some class to manage better the things.

* Move platform and interface stuff in their own files in public directory

* Make sure to init cvar stuff after ReHLDS

* Add ReGameDLL API files and its dependencies in cstrike module

* Init ReHLDS in cstrike module and adjust code

Note: About cs_uset_set_model(). ReHLDS API doesn't offer a way to know directly the precached models, so instead of looping through all the ressources, the models list is saved one time at map change into a hashmap.

* Init ReGameDLL and adjust code

* Fix linux compilation

* Init ReGameDLL in fakemeta module and adjust code

* Rename /reapi directory to /resdk to avoid confusion

* Retrieve gamerules pointer through InstallGameRules in fakemeta module

* Retrieve gamerules pointer through InstallGameRules in cstrike module

Note: actually gamerules is not used if regamedll is enabled, but it could be used in future natives.

* Fix a typo when ReGameDLL is not enabled

* Fix missing interface check for ReHLDS.

I'm pretty sure I was checking at the very first since I worked first on vanilla version of engine, looks like change has been lost.
This commit is contained in:
Vincent Herbet
2017-03-09 19:59:38 +01:00
committed by GitHub
parent 1c3e8de57a
commit 115916d753
48 changed files with 5298 additions and 379 deletions

View File

@ -93,6 +93,7 @@ binary.sources = [
'../public/memtools/MemoryUtils.cpp',
'../public/memtools/CDetour/detours.cpp',
'../public/memtools/CDetour/asm/asm.c',
'../public/resdk/mod_rehlds_api.cpp',
'CLibrarySys.cpp',
'CGameConfigs.cpp',
'gameconfigs.cpp',

View File

@ -11,67 +11,9 @@
#define _INCLUDE_LIBRARY_SYS_H_
#include "amx.h" // cell
#include <interface.h> // Interface (HLSDK)
#include <amtl/am-utility.h> // AutoPtr
#include <platform_helpers.h>
#include <amtl/os/am-shared-library.h>
#define PLATFORM_WINDOWNS_NAME "windows"
#define PLATFORM_LINUX_NAME "linux"
#define PLATFORM_MAC_NAME "mac"
#if defined(WIN32)
# ifndef PLATFORM_WINDOWS
# define PLATFORM_WINDOWS 1
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
# include <direct.h>
# include <io.h>
# define PLATFORM_LIB_EXT "dll"
# define PLATFORM_NAME PLATFORM_WINDOWNS_NAME
# define PLATFORM_SEP_CHAR '\\'
# define PLATFORM_SEP_ALTCHAR '/'
# define PLATFORM_EXTERN_C extern "C" __declspec(dllexport)
#elif defined(__linux__) || defined(__APPLE__)
# if defined(__linux__)
# define PLATFORM_LINUX 1
# define PLATFORM_LIB_EXT "so"
# define PLATFORM_NAME PLATFORM_LINUX_NAME
# define PLATFORM_COMPAT_ALT PLATFORM_MAC_NAME
# elif defined(__APPLE__)
# define PLATFORM_APPLE 1
# define PLATFORM_LIB_EXT "dylib"
# define PLATFORM_NAME PLATFORM_MAC_NAME
# define PLATFORM_COMPAT_ALT PLATFORM_LINUX_NAME
# endif
# ifndef PLATFORM_POSIX
# define PLATFORM_POSIX 1
# endif
# include <stdio.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <errno.h>
# include <unistd.h>
# include <dirent.h>
# include <dlfcn.h>
# if defined(PLATFORM_APPLE)
# include <sys/syslimits.h>
# endif
# define PLATFORM_SEP_CHAR '/'
# define PLATFORM_SEP_ALTCHAR '\\'
# define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default")))
# define WINAPI
#endif
#define PLATFORM_MAX_PATH 260
#if defined PLATFORM_WINDOWS
typedef HANDLE DirHandle;
#elif defined PLATFORM_POSIX
typedef DIR* DirHandle;
#endif
enum FileTimeType
{
FileTime_LastAccess = 0, /* Last access (not available on FAT) */
@ -162,26 +104,4 @@ class LibrarySystem
extern LibrarySystem g_LibSys;
template <typename T>
bool GET_IFACE(const char* library, T*& var, const char* version)
{
const char* path = g_LibSys.PathFormat("%s.%s", library, PLATFORM_LIB_EXT);
ke::AutoPtr<CLibrary> lib(g_LibSys.OpenLibrary(path));
if (lib)
{
CreateInterfaceFn factory = reinterpret_cast<CreateInterfaceFn>(lib->GetSymbolAddress(CREATEINTERFACE_PROCNAME));
if (factory)
{
var = reinterpret_cast<T*>(factory(version, nullptr));
return true;
}
}
var = nullptr;
return false;
}
#endif // _INCLUDE_LIBRARY_SYS_H_

View File

@ -11,10 +11,13 @@
#include "amxmodx.h"
#include <CDetour/detours.h>
#include <auto-string.h>
#include <resdk/mod_rehlds_api.h>
CvarManager g_CvarManager;
DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, value)
void (*Cvar_DirectSet_Actual)(struct cvar_s* var, const char *value) = nullptr;
void Cvar_DirectSet_Custom(struct cvar_s *var, const char *value, IRehldsHook_Cvar_DirectSet *chain = nullptr)
{
CvarInfo* info = nullptr;
@ -22,7 +25,7 @@ DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, valu
|| strcmp(var->string, value) == 0 // Make sure old and new values are different to not trigger callbacks.
|| !g_CvarManager.CacheLookup(var->name, &info)) // No data in cache, nothing to do.
{
DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value);
chain ? chain->callNext(var, value) : Cvar_DirectSet_Actual(var, value);
return;
}
@ -56,7 +59,7 @@ DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, valu
oldValue = var->string;
}
DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value);
chain ? chain->callNext(var, value) : Cvar_DirectSet_Actual(var, value);
if (!info->binds.empty())
{
@ -100,7 +103,18 @@ DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, valu
}
}
CvarManager::CvarManager() : m_AmxmodxCvars(0), m_HookDetour(nullptr)
void Cvar_DirectSet(struct cvar_s *var, const char *value)
{
Cvar_DirectSet_Custom(var, value);
}
void Cvar_DirectSet_RH(IRehldsHook_Cvar_DirectSet *chain, cvar_t *var, const char *value)
{
Cvar_DirectSet_Custom(var, value, chain);
}
CvarManager::CvarManager() : m_AmxmodxCvars(0), m_HookDetour(nullptr), m_ReHookEnabled(false)
{
}
@ -116,16 +130,61 @@ void CvarManager::CreateCvarHook(void)
// Cvar_DirectSet(var, value); // <- We want to hook this.
// }
void *functionAddress = nullptr;
if (!RehldsHookchains)
{
void *functionAddress = nullptr;
if (CommonConfig && CommonConfig->GetMemSig("Cvar_DirectSet", &functionAddress) && functionAddress)
{
// Disabled by default.
m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, functionAddress);
if (CommonConfig && CommonConfig->GetMemSig("Cvar_DirectSet", &functionAddress) && functionAddress)
{
// Disabled by default.
m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, functionAddress);
}
else
{
AMXXLOG_Log("Binding/Hooking cvars have been disabled - %s.", RehldsApi ? "update ReHLDS" : "check your gamedata files");
}
}
else
}
void CvarManager::EnableHook()
{
if (RehldsHookchains)
{
AMXXLOG_Log("Binding/Hooking cvars have been disabled - check your gamedata files.");
if (!m_ReHookEnabled)
{
RehldsHookchains->Cvar_DirectSet()->registerHook(Cvar_DirectSet_RH);
m_ReHookEnabled = true;
}
}
else if (m_HookDetour)
{
m_HookDetour->EnableDetour();
}
}
void CvarManager::DisableHook()
{
if (RehldsHookchains)
{
if (m_ReHookEnabled)
{
RehldsHookchains->Cvar_DirectSet()->unregisterHook(Cvar_DirectSet_RH);
m_ReHookEnabled = false;
}
}
else if (m_HookDetour)
{
m_HookDetour->DisableDetour();
}
}
void CvarManager::DestroyHook()
{
DisableHook();
if (m_HookDetour)
{
m_HookDetour->Destroy();
}
}
@ -205,9 +264,9 @@ CvarInfo* CvarManager::CreateCvar(const char* name, const char* value, const cha
// Detour is disabled on map change.
// Don't enable it unless there are things to do.
if ((info->bound.hasMin || info->bound.hasMax) && m_HookDetour)
if ((info->bound.hasMin || info->bound.hasMax))
{
m_HookDetour->EnableDetour();
EnableHook();
}
return info;
@ -295,11 +354,8 @@ AutoForward* CvarManager::HookCvarChange(cvar_t* var, AMX* amx, cell param, cons
return nullptr;
}
// Detour is disabled on map change.
if (m_HookDetour)
{
m_HookDetour->EnableDetour();
}
// Hook is disabled on map change.
EnableHook();
AutoForward* forward = new AutoForward(forwardId, *callback);
info->hooks.append(new CvarHook(g_plugins.findPlugin(amx)->getId(), forward));
@ -351,11 +407,8 @@ bool CvarManager::BindCvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, ce
break;
}
// Detour is disabled on map change.
if (m_HookDetour)
{
m_HookDetour->EnableDetour();
}
// Hook is disabled on map change.
EnableHook();
return true;
}
@ -367,11 +420,8 @@ void CvarManager::SetCvarMin(CvarInfo* info, bool set, float value, int pluginId
if (set)
{
// Detour is disabled on map change.
if (m_HookDetour)
{
m_HookDetour->EnableDetour();
}
// Hook is disabled on map change.
EnableHook();
info->bound.minVal = value;
@ -393,11 +443,8 @@ void CvarManager::SetCvarMax(CvarInfo* info, bool set, float value, int pluginId
if (set)
{
// Detour is disabled on map change.
if (m_HookDetour)
{
m_HookDetour->EnableDetour();
}
// Hook is disabled on map change.
EnableHook();
info->bound.maxVal = value;
@ -584,12 +631,9 @@ void CvarManager::OnPluginUnloaded()
(*cvar)->hooks.clear();
}
// There is no point to enable detour if at next map change
// There is no point to enable hook if at next map change
// no plugins hook cvars.
if (m_HookDetour)
{
m_HookDetour->DisableDetour();
}
DisableHook();
}
void CvarManager::OnAmxxShutdown()
@ -619,8 +663,5 @@ void CvarManager::OnAmxxShutdown()
m_Cache.clear();
if (m_HookDetour)
{
m_HookDetour->Destroy();
}
DestroyHook();
}

View File

@ -142,6 +142,9 @@ class CvarManager
public:
void CreateCvarHook();
void EnableHook();
void DisableHook();
void DestroyHook();
CvarInfo* CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, int flags = 0, const char* helpText = "");
CvarInfo* FindCvar(const char* name);
@ -166,6 +169,7 @@ class CvarManager
CvarsList m_Cvars;
size_t m_AmxmodxCvars;
CDetour* m_HookDetour;
bool m_ReHookEnabled;
};
extern CvarManager g_CvarManager;

View File

@ -32,6 +32,8 @@
#include <engine_strucs.h>
#include <CDetour/detours.h>
#include "CoreConfig.h"
#include <resdk/mod_rehlds_api.h>
#include <amtl/am-utility.h>
plugin_info_t Plugin_info =
{
@ -902,6 +904,31 @@ void C_ClientDisconnect(edict_t *pEntity)
RETURN_META(MRES_IGNORED);
}
CPlayer* SV_DropClient_PreHook(edict_s *client, qboolean crash, const char *buffer, size_t buffer_size)
{
auto pPlayer = client ? GET_PLAYER_POINTER(client) : nullptr;
if (pPlayer)
{
if (pPlayer->initialized)
{
pPlayer->disconnecting = true;
executeForwards(FF_ClientDisconnected, pPlayer->index, TRUE, prepareCharArray(const_cast<char*>(buffer), buffer_size, true), buffer_size - 1);
}
}
return pPlayer;
}
void SV_DropClient_PostHook(CPlayer *pPlayer, qboolean crash, const char *buffer)
{
if (pPlayer)
{
pPlayer->Disconnect();
executeForwards(FF_ClientRemove, pPlayer->index, TRUE, buffer);
}
}
// void SV_DropClient(client_t *cl, qboolean crash, const char *fmt, ...);
DETOUR_DECL_STATIC3_VAR(SV_DropClient, void, client_t*, cl, qboolean, crash, const char*, format)
{
@ -912,24 +939,23 @@ DETOUR_DECL_STATIC3_VAR(SV_DropClient, void, client_t*, cl, qboolean, crash, con
ke::SafeVsprintf(buffer, sizeof(buffer) - 1, format, ap);
va_end(ap);
auto pPlayer = cl->edict ? GET_PLAYER_POINTER(cl->edict) : nullptr;
if (pPlayer)
{
if (pPlayer->initialized)
{
pPlayer->disconnecting = true;
executeForwards(FF_ClientDisconnected, pPlayer->index, TRUE, prepareCharArray(buffer, sizeof(buffer), true), sizeof(buffer) - 1);
}
}
auto pPlayer = SV_DropClient_PreHook(cl->edict, crash, buffer, ARRAY_LENGTH(buffer));
DETOUR_STATIC_CALL(SV_DropClient)(cl, crash, "%s", buffer);
if (pPlayer)
{
pPlayer->Disconnect();
executeForwards(FF_ClientRemove, pPlayer->index, TRUE, buffer);
}
SV_DropClient_PostHook(pPlayer, crash, buffer);
}
void SV_DropClient_RH(IRehldsHook_SV_DropClient *chain, IGameClient *cl, bool crash, const char *format)
{
char buffer[1024];
ke::SafeStrcpy(buffer, sizeof(buffer), format);
auto pPlayer = SV_DropClient_PreHook(cl->GetEdict(), crash, buffer, ARRAY_LENGTH(buffer));
chain->callNext(cl, crash, buffer);
SV_DropClient_PostHook(pPlayer, crash, buffer);
}
void C_ClientPutInServer_Post(edict_t *pEntity)
@ -1602,19 +1628,27 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m
ConfigManager.OnAmxxStartup();
g_CvarManager.CreateCvarHook();
void *address = nullptr;
if (CommonConfig && CommonConfig->GetMemSig("SV_DropClient", &address) && address)
if (RehldsApi_Init())
{
DropClientDetour = DETOUR_CREATE_STATIC_FIXED(SV_DropClient, address);
RehldsHookchains->SV_DropClient()->registerHook(SV_DropClient_RH);
}
else
{
AMXXLOG_Log("client_disconnected and client_remove forwards have been disabled - check your gamedata files.");
void *address = nullptr;
if (CommonConfig && CommonConfig->GetMemSig("SV_DropClient", &address) && address)
{
DropClientDetour = DETOUR_CREATE_STATIC_FIXED(SV_DropClient, address);
}
else
{
auto reason = RehldsApi ? "update ReHLDS" : "check your gamedata files";
AMXXLOG_Log("client_disconnected and client_remove forwards have been disabled - %s.", reason);
}
}
g_CvarManager.CreateCvarHook();
GET_IFACE<IFileSystem>("filesystem_stdio", g_FileSystem, FILESYSTEM_INTERFACE_VERSION);
return (TRUE);
@ -1664,6 +1698,10 @@ C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{
DropClientDetour->Destroy();
}
else if (RehldsApi)
{
RehldsHookchains->SV_DropClient()->unregisterHook(SV_DropClient_RH);
}
return (TRUE);
}

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "amxmodx_mm", "amxmodx_mm.vcxproj", "{2BF64D1A-AC89-41B0-9D02-FB8CB610F850}"
EndProject

View File

@ -151,6 +151,7 @@
<ClCompile Include="..\..\public\memtools\CDetour\asm\asm.c" />
<ClCompile Include="..\..\public\memtools\CDetour\detours.cpp" />
<ClCompile Include="..\..\public\memtools\MemoryUtils.cpp" />
<ClCompile Include="..\..\public\resdk\mod_rehlds_api.cpp" />
<ClCompile Include="..\..\third_party\hashing\hashers\crc32.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='JITDebug|Win32'">$(IntDir)hashing\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='JITRelease|Win32'">$(IntDir)hashing\</ObjectFileName>
@ -311,6 +312,10 @@
<ClInclude Include="..\..\public\memtools\CDetour\detourhelpers.h" />
<ClInclude Include="..\..\public\memtools\CDetour\detours.h" />
<ClInclude Include="..\..\public\memtools\MemoryUtils.h" />
<ClInclude Include="..\..\public\resdk\common\hookchains.h" />
<ClInclude Include="..\..\public\resdk\engine\rehlds_api.h" />
<ClInclude Include="..\..\public\resdk\engine\rehlds_interfaces.h" />
<ClInclude Include="..\..\public\resdk\mod_rehlds_api.h" />
<ClInclude Include="..\..\third_party\hashing\hashers\crc32.h" />
<ClInclude Include="..\..\third_party\hashing\hashers\keccak.h" />
<ClInclude Include="..\..\third_party\hashing\hashers\md5.h" />

View File

@ -46,6 +46,15 @@
<Filter Include="Third Party\Hashing\hashers">
<UniqueIdentifier>{fb5fd616-bb2e-42f1-a113-a61eb9ead739}</UniqueIdentifier>
</Filter>
<Filter Include="ReSDK">
<UniqueIdentifier>{5dd87e1c-9be5-43d3-8216-74d36f4f7610}</UniqueIdentifier>
</Filter>
<Filter Include="ReSDK\common">
<UniqueIdentifier>{26cdecf1-06de-459e-9ea0-0bbb4a2b3bf6}</UniqueIdentifier>
</Filter>
<Filter Include="ReSDK\engine">
<UniqueIdentifier>{04fab577-6f56-40d0-8f69-7ce1b8bf3bb9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\amx.cpp">
@ -291,6 +300,9 @@
<ClCompile Include="..\CoreConfig.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\public\resdk\mod_rehlds_api.cpp">
<Filter>ReSDK</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\amx.h">
@ -503,6 +515,18 @@
<ClInclude Include="..\CFrameAction.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\public\resdk\common\hookchains.h">
<Filter>ReSDK\common</Filter>
</ClInclude>
<ClInclude Include="..\..\public\resdk\engine\rehlds_api.h">
<Filter>ReSDK\engine</Filter>
</ClInclude>
<ClInclude Include="..\..\public\resdk\engine\rehlds_interfaces.h">
<Filter>ReSDK\engine</Filter>
</ClInclude>
<ClInclude Include="..\..\public\resdk\mod_rehlds_api.h">
<Filter>ReSDK</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\version.rc">