mirror of
https://github.com/rehlds/metamod-r.git
synced 2025-01-26 05:28:19 +03:00
Implemented extension dll to avoid a list of entities e.g (linkgame.cpp).
Minor refactoring
This commit is contained in:
parent
d90f336a75
commit
a6ab7cea5d
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
**/.gradle
|
||||
.idea
|
||||
*.iml
|
||||
*.bat
|
||||
**/msvc/Debug*
|
||||
**/msvc/Release*
|
||||
**/msvc/*.sdf
|
||||
@ -14,7 +15,6 @@
|
||||
**/msvc/*.pch
|
||||
**/msvc/*.txt
|
||||
**/msvc/.vs
|
||||
**/msvc/start*.bat
|
||||
**/msvc/ipch
|
||||
**/PublishPath*.txt
|
||||
**/*.log
|
||||
|
@ -48,7 +48,7 @@ void setupToolchain(NativeBinarySpec b)
|
||||
pchSourceSet: 'rmod_pch'
|
||||
)
|
||||
|
||||
cfg.extraLibs 'psapi.lib'
|
||||
cfg.extraLibs 'psapi.lib', 'user32.lib'
|
||||
cfg.singleDefines('_CRT_SECURE_NO_WARNINGS')
|
||||
} else if (cfg instanceof GccToolchainConfig) {
|
||||
cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions(
|
||||
|
@ -36,7 +36,6 @@
|
||||
|
||||
#include "archtypes.h"
|
||||
#include "maintypes.h"
|
||||
#include "regamedll_common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#define _strlwr(p) for (int i = 0; p[i] != 0; i++) p[i] = tolower(p[i]);
|
||||
#endif
|
||||
|
||||
#define Q_isspace isspace
|
||||
#define Q_isalnum isalnum
|
||||
#define Q_isalpha isalpha
|
||||
|
||||
#define Q_malloc malloc
|
||||
#define Q_calloc calloc
|
||||
#define Q_alloca alloca
|
||||
#define Q_free free
|
||||
|
||||
#define Q_min min
|
||||
#define Q_max max
|
||||
#define Q_clamp clamp
|
||||
#define Q_access _access
|
||||
#define Q_close _close
|
||||
#define Q_write _write
|
||||
#define Q_memset memset
|
||||
#define Q_memcpy memcpy
|
||||
#define Q_strlen strlen
|
||||
#define Q_memcmp memcmp
|
||||
#define Q_strcpy strcpy
|
||||
#define Q_strncpy strncpy
|
||||
#define Q_strrchr strrchr
|
||||
#define Q_strcat strcat
|
||||
#define Q_strncat strncat
|
||||
#define Q_strcmp strcmp
|
||||
#define Q_strncmp strncmp
|
||||
#define Q_sscanf sscanf
|
||||
#define Q_strdup _strdup
|
||||
#define Q_stricmp _stricmp
|
||||
#define Q_strnicmp _strnicmp
|
||||
#define Q_strstr strstr
|
||||
#define Q_strchr strchr
|
||||
#define Q_strrchr strrchr
|
||||
#define Q_strlwr _strlwr
|
||||
#define Q_sprintf sprintf
|
||||
#define Q_snprintf _snprintf
|
||||
#define Q_atoi atoi
|
||||
#define Q_atof atof
|
||||
#define Q_toupper toupper
|
||||
#define Q_memmove memmove
|
||||
#define Q_vsnprintf _vsnprintf
|
||||
#define Q_vsnwprintf _vsnwprintf
|
||||
#define Q_abs abs
|
||||
#define Q_fabs fabs
|
||||
#define Q_tan tan
|
||||
#define Q_atan atan
|
||||
#define Q_atan2 atan2
|
||||
#define Q_acos acos
|
||||
#define Q_cos cos
|
||||
#define Q_sin sin
|
||||
#define Q_pow pow
|
||||
#define Q_fmod fmod
|
||||
#define Q_fopen fopen
|
||||
#define Q_fwrite fwrite
|
||||
#define Q_fprintf fprintf
|
||||
#define Q_fclose fclose
|
||||
|
||||
#ifdef REGAMEDLL_FIXES
|
||||
#define Q_sqrt M_sqrt
|
||||
#else
|
||||
#define Q_sqrt sqrt
|
||||
#endif
|
@ -36,7 +36,6 @@
|
||||
|
||||
#include "archtypes.h"
|
||||
#include "maintypes.h"
|
||||
#include "regamedll_common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#define _strlwr(p) for (int i = 0; p[i] != 0; i++) p[i] = tolower(p[i]);
|
||||
#endif
|
||||
|
||||
#define Q_isspace isspace
|
||||
#define Q_isalnum isalnum
|
||||
#define Q_isalpha isalpha
|
||||
|
||||
#define Q_malloc malloc
|
||||
#define Q_calloc calloc
|
||||
#define Q_alloca alloca
|
||||
#define Q_free free
|
||||
|
||||
#define Q_min min
|
||||
#define Q_max max
|
||||
#define Q_clamp clamp
|
||||
#define Q_access _access
|
||||
#define Q_close _close
|
||||
#define Q_write _write
|
||||
#define Q_memset memset
|
||||
#define Q_memcpy memcpy
|
||||
#define Q_strlen strlen
|
||||
#define Q_memcmp memcmp
|
||||
#define Q_strcpy strcpy
|
||||
#define Q_strncpy strncpy
|
||||
#define Q_strrchr strrchr
|
||||
#define Q_strcat strcat
|
||||
#define Q_strncat strncat
|
||||
#define Q_strcmp strcmp
|
||||
#define Q_strncmp strncmp
|
||||
#define Q_sscanf sscanf
|
||||
#define Q_strdup _strdup
|
||||
#define Q_stricmp _stricmp
|
||||
#define Q_strnicmp _strnicmp
|
||||
#define Q_strstr strstr
|
||||
#define Q_strchr strchr
|
||||
#define Q_strrchr strrchr
|
||||
#define Q_strlwr _strlwr
|
||||
#define Q_sprintf sprintf
|
||||
#define Q_snprintf _snprintf
|
||||
#define Q_atoi atoi
|
||||
#define Q_atof atof
|
||||
#define Q_toupper toupper
|
||||
#define Q_memmove memmove
|
||||
#define Q_vsnprintf _vsnprintf
|
||||
#define Q_vsnwprintf _vsnwprintf
|
||||
#define Q_abs abs
|
||||
#define Q_fabs fabs
|
||||
#define Q_tan tan
|
||||
#define Q_atan atan
|
||||
#define Q_atan2 atan2
|
||||
#define Q_acos acos
|
||||
#define Q_cos cos
|
||||
#define Q_sin sin
|
||||
#define Q_pow pow
|
||||
#define Q_fmod fmod
|
||||
#define Q_fopen fopen
|
||||
#define Q_fwrite fwrite
|
||||
#define Q_fprintf fprintf
|
||||
#define Q_fclose fclose
|
||||
|
||||
#ifdef REGAMEDLL_FIXES
|
||||
#define Q_sqrt M_sqrt
|
||||
#else
|
||||
#define Q_sqrt sqrt
|
||||
#endif
|
@ -10,6 +10,7 @@ set repodir=%~2
|
||||
set old_version=
|
||||
set version_major=0
|
||||
set version_minor=0
|
||||
set version_maintenance=0
|
||||
set version_modifed=
|
||||
|
||||
set commitSHA=
|
||||
@ -65,6 +66,7 @@ IF EXIST "%srcdir%\version.h" (
|
||||
IF %%i==#define (
|
||||
IF %%j==VERSION_MAJOR set version_major=%%k
|
||||
IF %%j==VERSION_MINOR set version_minor=%%k
|
||||
IF %%j==VERSION_MAINTENANCE set version_maintenance=%%k
|
||||
)
|
||||
)
|
||||
) ELSE (
|
||||
@ -72,6 +74,7 @@ IF EXIST "%srcdir%\version.h" (
|
||||
IF NOT [%%j] == [] (
|
||||
IF %%i==majorVersion set version_major=%%j
|
||||
IF %%i==minorVersion set version_minor=%%j
|
||||
IF %%i==maintenanceVersion set version_maintenance=%%j
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -165,7 +168,7 @@ IF [%localChanged%]==[1] (
|
||||
:: Now form full version string like 1.0.0.1
|
||||
::
|
||||
|
||||
set new_version=%version_major%.%version_minor%.%commitCount%%version_modifed%
|
||||
set new_version=%version_major%.%version_minor%.%version_maintenance%.%commitCount%%version_modifed%
|
||||
|
||||
::
|
||||
:: Update appversion.h if version has changed or modifications/mixed revisions detected
|
||||
@ -194,8 +197,8 @@ echo.>>"%srcdir%\appversion.h"
|
||||
echo // Version defines>>"%srcdir%\appversion.h"
|
||||
echo #define APP_VERSION "%new_version%">>"%srcdir%\appversion.h"
|
||||
|
||||
>>"%srcdir%\appversion.h" echo #define APP_VERSION_C %version_major%,%version_minor%,%commitCount%
|
||||
echo #define APP_VERSION_STRD "%version_major%.%version_minor%.%commitCount%">>"%srcdir%\appversion.h"
|
||||
>>"%srcdir%\appversion.h" echo #define APP_VERSION_C %version_major%,%version_minor%,%version_maintenance%,%commitCount%
|
||||
echo #define APP_VERSION_STRD "%version_major%.%version_minor%.%version_maintenance%.%commitCount%">>"%srcdir%\appversion.h"
|
||||
echo #define APP_VERSION_FLAGS 0x0L>>"%srcdir%\appversion.h"
|
||||
|
||||
echo.>>"%srcdir%\appversion.h"
|
||||
|
@ -206,14 +206,15 @@
|
||||
<ClCompile Include="..\src\linkgame.cpp" />
|
||||
<ClCompile Include="..\src\log_meta.cpp" />
|
||||
<ClCompile Include="..\src\mdebug.cpp" />
|
||||
<ClCompile Include="..\src\metamod_rehlds_api.cpp" />
|
||||
<ClCompile Include="..\src\mem_utils.cpp" />
|
||||
<ClCompile Include="..\src\meta_rehlds_api.cpp" />
|
||||
<ClCompile Include="..\src\metamod.cpp" />
|
||||
<ClCompile Include="..\src\mextdll.cpp" />
|
||||
<ClCompile Include="..\src\mlist.cpp" />
|
||||
<ClCompile Include="..\src\mplayer.cpp" />
|
||||
<ClCompile Include="..\src\mplugin.cpp" />
|
||||
<ClCompile Include="..\src\mreg.cpp" />
|
||||
<ClCompile Include="..\src\mutil.cpp" />
|
||||
<ClCompile Include="..\src\osdep.cpp" />
|
||||
<ClCompile Include="..\src\precompiled.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
@ -222,6 +223,7 @@
|
||||
<ClCompile Include="..\src\reg_support.cpp" />
|
||||
<ClCompile Include="..\src\sdk_util.cpp" />
|
||||
<ClCompile Include="..\src\studioapi.cpp" />
|
||||
<ClCompile Include="..\src\sys_module.cpp" />
|
||||
<ClCompile Include="..\src\utils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -239,9 +241,11 @@
|
||||
<ClInclude Include="..\src\linkent.h" />
|
||||
<ClInclude Include="..\src\log_meta.h" />
|
||||
<ClInclude Include="..\src\mdebug.h" />
|
||||
<ClInclude Include="..\src\metamod_rehlds_api.h" />
|
||||
<ClInclude Include="..\src\mem_utils.h" />
|
||||
<ClInclude Include="..\src\meta_rehlds_api.h" />
|
||||
<ClInclude Include="..\src\meta_api.h" />
|
||||
<ClInclude Include="..\src\metamod.h" />
|
||||
<ClInclude Include="..\src\mextdll.h" />
|
||||
<ClInclude Include="..\src\mlist.h" />
|
||||
<ClInclude Include="..\src\mplayer.h" />
|
||||
<ClInclude Include="..\src\mplugin.h" />
|
||||
@ -253,6 +257,7 @@
|
||||
<ClInclude Include="..\src\reg_support.h" />
|
||||
<ClInclude Include="..\src\sdk_util.h" />
|
||||
<ClInclude Include="..\src\studioapi.h" />
|
||||
<ClInclude Include="..\src\sys_module.h" />
|
||||
<ClInclude Include="..\src\utils.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -62,9 +62,6 @@
|
||||
<ClCompile Include="..\src\mutil.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\osdep.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\precompiled.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
@ -83,15 +80,24 @@
|
||||
<ClCompile Include="..\src\callback_jit.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\metamod_rehlds_api.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\public_amalgamation.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\mdebug.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\mem_utils.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\sys_module.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\mextdll.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\meta_rehlds_api.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\api_info.h">
|
||||
@ -175,10 +181,19 @@
|
||||
<ClInclude Include="..\src\jitasm.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\metamod_rehlds_api.h">
|
||||
<ClInclude Include="..\src\mdebug.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\mdebug.h">
|
||||
<ClInclude Include="..\src\mem_utils.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\sys_module.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\mextdll.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\meta_rehlds_api.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
@ -114,7 +114,7 @@ void cmd_meta_version()
|
||||
return;
|
||||
}
|
||||
|
||||
META_CONS("Metamod-r v%s, API (%s)", APP_VERSION_STRD, META_INTERFACE_VERSION);
|
||||
META_CONS("Metamod-r v%s, API (%s)", APP_VERSION, META_INTERFACE_VERSION);
|
||||
META_CONS("Metamod-r build: " __TIME__ " " __DATE__ "");
|
||||
META_CONS("Metamod-r from: " APP_COMMIT_URL APP_COMMIT_SHA "");
|
||||
}
|
||||
@ -127,7 +127,7 @@ void client_meta_version(edict_t *pEntity)
|
||||
return;
|
||||
}
|
||||
|
||||
META_CONS("Metamod-r v%s, API (%s)", APP_VERSION_STRD, META_INTERFACE_VERSION);
|
||||
META_CONS("Metamod-r v%s, API (%s)", APP_VERSION, META_INTERFACE_VERSION);
|
||||
META_CONS("Metamod-r build: " __TIME__ " " __DATE__ "");
|
||||
META_CONS("Metamod-r from: " APP_COMMIT_URL APP_COMMIT_SHA "");
|
||||
}
|
||||
@ -336,7 +336,7 @@ void cmd_doplug(PLUG_CMD pcmd)
|
||||
}
|
||||
|
||||
// Allow chance to read the message, before any window closes.
|
||||
do_exit(1);
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
if (findp && !unique) {
|
||||
|
@ -62,21 +62,22 @@ bool MConfig::set(option_t* setp, const char* setstr)
|
||||
*optval = FALSE;
|
||||
}
|
||||
else {
|
||||
META_ERROR("option '%s' invalid format '%s'", setp->name,
|
||||
setstr);
|
||||
META_ERROR("option '%s' invalid format '%s'", setp->name, setstr);
|
||||
return false;
|
||||
}
|
||||
META_DEBUG(3, "set config bool: %s = %s", setp->name, *optval ? "true" : "false");
|
||||
break;
|
||||
case CF_STR:
|
||||
if (*optstr)
|
||||
Q_free(*optstr);
|
||||
if (*optstr) {
|
||||
free(*optstr);
|
||||
}
|
||||
*optstr = Q_strdup(setstr);
|
||||
META_DEBUG(3, "set config string: %s = %s", setp->name, *optstr);
|
||||
break;
|
||||
case CF_PATH:
|
||||
if (*optstr)
|
||||
Q_free(*optstr);
|
||||
if (*optstr) {
|
||||
free(*optstr);
|
||||
}
|
||||
full_gamedir_path(setstr, pathbuf);
|
||||
*optstr = Q_strdup(pathbuf);
|
||||
META_DEBUG(3, "set config path: %s = %s", setp->name, *optstr);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#define CDATA_DLL_H(x, p, h) CDATA_ENTRY(DLL_FUNCTIONS, x, p, size_t(h))
|
||||
#define CDATA_DLL(x) CDATA_ENTRY(DLL_FUNCTIONS, x, P_PRE, 0u)
|
||||
#define CDATA_NEWDLL_H(x, p, h) CDATA_ENTRY(NEW_DLL_FUNCTIONS, x, p, uint8(h))
|
||||
#define CDATA_NEWDLL_H(x, p, h) CDATA_ENTRY(NEW_DLL_FUNCTIONS, x, p, size_t(h))
|
||||
#define CDATA_NEWDLL(x) CDATA_ENTRY(NEW_DLL_FUNCTIONS, x, P_PRE, 0u)
|
||||
|
||||
DLL_FUNCTIONS sFunctionTable;
|
||||
@ -12,6 +12,13 @@ NEW_DLL_FUNCTIONS sNewFunctionTable;
|
||||
NEW_DLL_FUNCTIONS sNewFunctionTable_jit;
|
||||
NEW_DLL_FUNCTIONS *pHookedNewDllFunctions = &sNewFunctionTable;
|
||||
|
||||
void MM_PRE_HOOK EXT_FUNC mm_GameShutdown()
|
||||
{
|
||||
g_meta_extdll.unload();
|
||||
g_GameDLL.sys_module.unload();
|
||||
g_engine.sys_module.unload();
|
||||
}
|
||||
|
||||
void MM_PRE_HOOK EXT_FUNC mm_ClientConnect(edict_t *pEntity, const char *, const char *, char[128])
|
||||
{
|
||||
g_players.clear_player_cvar_query(pEntity);
|
||||
@ -58,76 +65,76 @@ void EXT_FUNC mm_ServerDeactivate()
|
||||
|
||||
compile_data_t g_dllfunc_cdata[] =
|
||||
{
|
||||
CDATA_DLL(pfnGameInit), // pfnGameInit() Initialize the game (one-time call after loading of game .dll)
|
||||
CDATA_DLL(pfnSpawn), // pfnSpawn()
|
||||
CDATA_DLL(pfnThink), // pfnThink()
|
||||
CDATA_DLL(pfnUse), // pfnUse()
|
||||
CDATA_DLL(pfnTouch), // pfnTouch()
|
||||
CDATA_DLL(pfnBlocked), // pfnBlocked()
|
||||
CDATA_DLL(pfnKeyValue), // pfnKeyValue()
|
||||
CDATA_DLL(pfnSave), // pfnSave()
|
||||
CDATA_DLL(pfnRestore), // pfnRestore()
|
||||
CDATA_DLL(pfnSetAbsBox), // pfnSetAbsBox()
|
||||
CDATA_DLL(pfnGameInit), // pfnGameInit() Initialize the game (one-time call after loading of game .dll)
|
||||
CDATA_DLL(pfnSpawn), // pfnSpawn()
|
||||
CDATA_DLL(pfnThink), // pfnThink()
|
||||
CDATA_DLL(pfnUse), // pfnUse()
|
||||
CDATA_DLL(pfnTouch), // pfnTouch()
|
||||
CDATA_DLL(pfnBlocked), // pfnBlocked()
|
||||
CDATA_DLL(pfnKeyValue), // pfnKeyValue()
|
||||
CDATA_DLL(pfnSave), // pfnSave()
|
||||
CDATA_DLL(pfnRestore), // pfnRestore()
|
||||
CDATA_DLL(pfnSetAbsBox), // pfnSetAbsBox()
|
||||
|
||||
CDATA_DLL(pfnSaveWriteFields), // pfnSaveWriteFields()
|
||||
CDATA_DLL(pfnSaveReadFields), // pfnSaveReadFields()
|
||||
CDATA_DLL(pfnSaveWriteFields), // pfnSaveWriteFields()
|
||||
CDATA_DLL(pfnSaveReadFields), // pfnSaveReadFields()
|
||||
|
||||
CDATA_DLL(pfnSaveGlobalState), // pfnSaveGlobalState()
|
||||
CDATA_DLL(pfnRestoreGlobalState), // pfnRestoreGlobalState()
|
||||
CDATA_DLL(pfnResetGlobalState), // pfnResetGlobalState()
|
||||
CDATA_DLL(pfnSaveGlobalState), // pfnSaveGlobalState()
|
||||
CDATA_DLL(pfnRestoreGlobalState), // pfnRestoreGlobalState()
|
||||
CDATA_DLL(pfnResetGlobalState), // pfnResetGlobalState()
|
||||
|
||||
CDATA_DLL_H(pfnClientConnect, P_PRE, mm_ClientConnect), // pfnClientConnect() (wd) Client has connected
|
||||
CDATA_DLL_H(pfnClientDisconnect, P_PRE, mm_ClientDisconnect), // pfnClientDisconnect() (wd) Player has left the game
|
||||
CDATA_DLL(pfnClientKill), // pfnClientKill() (wd) Player has typed "kill"
|
||||
CDATA_DLL(pfnClientPutInServer), // pfnClientPutInServer() (wd) Client is entering the game
|
||||
CDATA_DLL_H(pfnClientConnect, P_PRE, mm_ClientConnect), // pfnClientConnect() (wd) Client has connected
|
||||
CDATA_DLL_H(pfnClientDisconnect, P_PRE, mm_ClientDisconnect), // pfnClientDisconnect() (wd) Player has left the game
|
||||
CDATA_DLL(pfnClientKill), // pfnClientKill() (wd) Player has typed "kill"
|
||||
CDATA_DLL(pfnClientPutInServer), // pfnClientPutInServer() (wd) Client is entering the game
|
||||
CDATA_DLL_H(pfnClientCommand, P_PRE, mm_ClientCommand),
|
||||
CDATA_DLL(pfnClientUserInfoChanged), // pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure
|
||||
CDATA_DLL(pfnServerActivate), // pfnServerActivate() (wd) Server is starting a new map
|
||||
CDATA_DLL(pfnServerDeactivate), // pfnServerDeactivate() (wd) Server is leaving the map (shutdown), or changelevel); SDK2
|
||||
CDATA_DLL(pfnClientUserInfoChanged), // pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure
|
||||
CDATA_DLL(pfnServerActivate), // pfnServerActivate() (wd) Server is starting a new map
|
||||
CDATA_DLL(pfnServerDeactivate), // pfnServerDeactivate() (wd) Server is leaving the map (shutdown), or changelevel); SDK2
|
||||
|
||||
CDATA_DLL(pfnPlayerPreThink), // pfnPlayerPreThink()
|
||||
CDATA_DLL(pfnPlayerPostThink), // pfnPlayerPostThink()
|
||||
CDATA_DLL(pfnPlayerPreThink), // pfnPlayerPreThink()
|
||||
CDATA_DLL(pfnPlayerPostThink), // pfnPlayerPostThink()
|
||||
|
||||
CDATA_DLL(pfnStartFrame), // pfnStartFrame()
|
||||
CDATA_DLL(pfnParmsNewLevel), // pfnParmsNewLevel()
|
||||
CDATA_DLL(pfnParmsChangeLevel), // pfnParmsChangeLevel()
|
||||
CDATA_DLL(pfnStartFrame), // pfnStartFrame()
|
||||
CDATA_DLL(pfnParmsNewLevel), // pfnParmsNewLevel()
|
||||
CDATA_DLL(pfnParmsChangeLevel), // pfnParmsChangeLevel()
|
||||
|
||||
CDATA_DLL(pfnGetGameDescription), // pfnGetGameDescription() Returns string describing current .dll. E.g. "TeamFotrress 2"), "Half-Life"
|
||||
CDATA_DLL(pfnPlayerCustomization), // pfnPlayerCustomization() Notifies .dll of new customization for player.
|
||||
CDATA_DLL(pfnGetGameDescription), // pfnGetGameDescription() Returns string describing current .dll. E.g. "TeamFotrress 2"), "Half-Life"
|
||||
CDATA_DLL(pfnPlayerCustomization), // pfnPlayerCustomization() Notifies .dll of new customization for player.
|
||||
|
||||
CDATA_DLL(pfnSpectatorConnect), // pfnSpectatorConnect() Called when spectator joins server
|
||||
CDATA_DLL(pfnSpectatorDisconnect), // pfnSpectatorDisconnect() Called when spectator leaves the server
|
||||
CDATA_DLL(pfnSpectatorThink), // pfnSpectatorThink() Called when spectator sends a command packet (usercmd_t)
|
||||
CDATA_DLL(pfnSpectatorConnect), // pfnSpectatorConnect() Called when spectator joins server
|
||||
CDATA_DLL(pfnSpectatorDisconnect), // pfnSpectatorDisconnect() Called when spectator leaves the server
|
||||
CDATA_DLL(pfnSpectatorThink), // pfnSpectatorThink() Called when spectator sends a command packet (usercmd_t)
|
||||
|
||||
CDATA_DLL(pfnSys_Error), // pfnSys_Error() Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. SDK2
|
||||
CDATA_DLL(pfnSys_Error), // pfnSys_Error() Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. SDK2
|
||||
|
||||
CDATA_DLL(pfnPM_Move), // pfnPM_Move() (wd) SDK2
|
||||
CDATA_DLL(pfnPM_Init), // pfnPM_Init() Server version of player movement initialization; (wd) SDK2
|
||||
CDATA_DLL(pfnPM_FindTextureType), // pfnPM_FindTextureType() (wd) SDK2
|
||||
CDATA_DLL(pfnPM_Move), // pfnPM_Move() (wd) SDK2
|
||||
CDATA_DLL(pfnPM_Init), // pfnPM_Init() Server version of player movement initialization; (wd) SDK2
|
||||
CDATA_DLL(pfnPM_FindTextureType), // pfnPM_FindTextureType() (wd) SDK2
|
||||
|
||||
CDATA_DLL(pfnSetupVisibility), // pfnSetupVisibility() Set up PVS and PAS for networking for this client; (wd) SDK2
|
||||
CDATA_DLL(pfnUpdateClientData), // pfnUpdateClientData() Set up data sent only to specific client; (wd) SDK2
|
||||
CDATA_DLL(pfnAddToFullPack), // pfnAddToFullPack() (wd) SDK2
|
||||
CDATA_DLL(pfnCreateBaseline), // pfnCreateBaseline() Tweak entity baseline for network encoding), allows setup of player baselines), too.; (wd) SDK2
|
||||
CDATA_DLL(pfnRegisterEncoders), // pfnRegisterEncoders() Callbacks for network encoding; (wd) SDK2
|
||||
CDATA_DLL(pfnGetWeaponData), // pfnGetWeaponData() (wd) SDK2
|
||||
CDATA_DLL(pfnCmdStart), // pfnCmdStart() (wd) SDK2
|
||||
CDATA_DLL(pfnCmdEnd), // pfnCmdEnd() (wd) SDK2
|
||||
CDATA_DLL(pfnConnectionlessPacket), // pfnConnectionlessPacket() (wd) SDK2
|
||||
CDATA_DLL(pfnGetHullBounds), // pfnGetHullBounds() (wd) SDK2
|
||||
CDATA_DLL(pfnCreateInstancedBaselines), // pfnCreateInstancedBaselines() (wd) SDK2
|
||||
CDATA_DLL(pfnInconsistentFile), // pfnInconsistentFile() (wd) SDK2
|
||||
CDATA_DLL(pfnAllowLagCompensation), // pfnAllowLagCompensation() (wd) SDK2
|
||||
CDATA_DLL(pfnSetupVisibility), // pfnSetupVisibility() Set up PVS and PAS for networking for this client; (wd) SDK2
|
||||
CDATA_DLL(pfnUpdateClientData), // pfnUpdateClientData() Set up data sent only to specific client; (wd) SDK2
|
||||
CDATA_DLL(pfnAddToFullPack), // pfnAddToFullPack() (wd) SDK2
|
||||
CDATA_DLL(pfnCreateBaseline), // pfnCreateBaseline() Tweak entity baseline for network encoding), allows setup of player baselines), too.; (wd) SDK2
|
||||
CDATA_DLL(pfnRegisterEncoders), // pfnRegisterEncoders() Callbacks for network encoding; (wd) SDK2
|
||||
CDATA_DLL(pfnGetWeaponData), // pfnGetWeaponData() (wd) SDK2
|
||||
CDATA_DLL(pfnCmdStart), // pfnCmdStart() (wd) SDK2
|
||||
CDATA_DLL(pfnCmdEnd), // pfnCmdEnd() (wd) SDK2
|
||||
CDATA_DLL(pfnConnectionlessPacket), // pfnConnectionlessPacket() (wd) SDK2
|
||||
CDATA_DLL(pfnGetHullBounds), // pfnGetHullBounds() (wd) SDK2
|
||||
CDATA_DLL(pfnCreateInstancedBaselines), // pfnCreateInstancedBaselines()(wd) SDK2
|
||||
CDATA_DLL(pfnInconsistentFile), // pfnInconsistentFile() (wd) SDK2
|
||||
CDATA_DLL(pfnAllowLagCompensation), // pfnAllowLagCompensation() (wd) SDK2
|
||||
};
|
||||
|
||||
compile_data_t g_newdllfunc_cdata[] =
|
||||
{
|
||||
CDATA_NEWDLL(pfnOnFreeEntPrivateData), // pfnOnFreeEntPrivateData() Called right before the object's memory is freed. Calls its destructor.
|
||||
CDATA_NEWDLL(pfnGameShutdown), // pfnGameShutdown()
|
||||
CDATA_NEWDLL(pfnShouldCollide), // pfnShouldCollide()
|
||||
CDATA_NEWDLL(pfnOnFreeEntPrivateData), // pfnOnFreeEntPrivateData() Called right before the object's memory is freed. Calls its destructor.
|
||||
CDATA_NEWDLL_H(pfnGameShutdown, P_PRE, mm_GameShutdown), // pfnGameShutdown()
|
||||
CDATA_NEWDLL(pfnShouldCollide), // pfnShouldCollide()
|
||||
|
||||
CDATA_NEWDLL(pfnCvarValue), // pfnCvarValue() (fz) Use mm_CvarValue2 instead
|
||||
CDATA_NEWDLL(pfnCvarValue2) // pfnCvarValue2() (fz) When pfnQueryClientCvarValue2() completes it will call
|
||||
CDATA_NEWDLL(pfnCvarValue), // pfnCvarValue() (fz) Use mm_CvarValue2 instead
|
||||
CDATA_NEWDLL(pfnCvarValue2) // pfnCvarValue2() (fz) When pfnQueryClientCvarValue2() completes it will call
|
||||
// pfnCvarValue2() with the request ID supplied earlier, the name of the cvar requested and the value of that cvar.
|
||||
};
|
||||
|
||||
@ -202,6 +209,8 @@ C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *in
|
||||
*interfaceVersion = NEW_DLL_FUNCTIONS_VERSION;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_meta_extdll.load();
|
||||
memcpy(pNewFunctionTable, &sNewFunctionTable, sizeof(NEW_DLL_FUNCTIONS));
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -8,10 +8,12 @@ struct engine_t
|
||||
memset(&pl_funcs, 0, sizeof pl_funcs);
|
||||
}
|
||||
|
||||
enginefuncs_t* funcs; // engine funcs
|
||||
globalvars_t* globals; // engine globals
|
||||
enginefuncs_t* funcs; // engine funcs
|
||||
globalvars_t* globals; // engine globals
|
||||
|
||||
// Our modified version of the engine funcs, to give to plugins.
|
||||
enginefuncs_t pl_funcs; // "modified" eng funcs we give to plugins
|
||||
enginefuncs_t pl_funcs; // "modified" eng funcs we give to plugins
|
||||
CSysModule sys_module;
|
||||
};
|
||||
|
||||
extern engine_t g_engine;
|
||||
|
@ -47,7 +47,7 @@ bool lookup_game_postfixes(gamedll_t *gamedll)
|
||||
char pathname[PATH_MAX];
|
||||
static char postfix_path[PATH_MAX] = "";
|
||||
|
||||
strlcpy(pathname, gamedll->pathname);
|
||||
Q_strlcpy(pathname, gamedll->pathname);
|
||||
|
||||
// find extensions and skip
|
||||
char *pos = strrchr(pathname, '.');
|
||||
@ -58,12 +58,12 @@ bool lookup_game_postfixes(gamedll_t *gamedll)
|
||||
for (size_t i = 0; i < arraysize(g_platform_postfixes); i++)
|
||||
{
|
||||
postfix_path[0] = '\0';
|
||||
strlcat(postfix_path, pathname);
|
||||
strlcat(postfix_path, g_platform_postfixes[i]);
|
||||
Q_strlcat(postfix_path, pathname);
|
||||
Q_strlcat(postfix_path, g_platform_postfixes[i]);
|
||||
|
||||
if (is_file_exists_in_gamedir(postfix_path)) {
|
||||
strlcpy(gamedll->pathname, postfix_path);
|
||||
strlcpy(gamedll->real_pathname, postfix_path);
|
||||
Q_strlcpy(gamedll->pathname, postfix_path);
|
||||
Q_strlcpy(gamedll->real_pathname, postfix_path);
|
||||
gamedll->file = postfix_path;
|
||||
|
||||
return true;
|
||||
@ -94,7 +94,7 @@ bool install_gamedll(char *from, const char *to)
|
||||
return false;
|
||||
}
|
||||
|
||||
int length_out = Q_write(fd, cachefile, length_in);
|
||||
int length_out = write(fd, cachefile, length_in);
|
||||
FREE_FILE(cachefile);
|
||||
close(fd);
|
||||
|
||||
@ -146,7 +146,7 @@ bool setup_gamedll(gamedll_t *gamedll)
|
||||
|
||||
// Use override-dll if specified.
|
||||
if (g_config->m_gamedll) {
|
||||
strlcpy(gamedll->pathname, g_config->m_gamedll);
|
||||
Q_strlcpy(gamedll->pathname, g_config->m_gamedll);
|
||||
|
||||
// If the path is relative, the gamedll file will be missing and
|
||||
// it might be found in the cache file.
|
||||
@ -157,7 +157,7 @@ bool setup_gamedll(gamedll_t *gamedll)
|
||||
// If we could successfully install the gamedll from the cache we
|
||||
// rectify the pathname to be a full pathname.
|
||||
if (install_gamedll(gamedll->pathname, szInstallPath)) {
|
||||
strlcpy(gamedll->pathname, szInstallPath);
|
||||
Q_strlcpy(gamedll->pathname, szInstallPath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ bool setup_gamedll(gamedll_t *gamedll)
|
||||
Q_snprintf(gamedll->real_pathname, sizeof(gamedll->real_pathname), "%s/dlls/%s", gamedll->gamedir, knownfn);
|
||||
}
|
||||
else {
|
||||
strlcpy(gamedll->real_pathname, gamedll->pathname);
|
||||
Q_strlcpy(gamedll->real_pathname, gamedll->pathname);
|
||||
}
|
||||
|
||||
if (override) {
|
||||
@ -198,7 +198,7 @@ bool setup_gamedll(gamedll_t *gamedll)
|
||||
META_LOG("Overriding game '%s' with dllfile '%s'", gamedll->name, gamedll->file);
|
||||
}
|
||||
else if (known) {
|
||||
strlcpy(gamedll->desc, known->desc);
|
||||
Q_strlcpy(gamedll->desc, known->desc);
|
||||
|
||||
#if !defined(_WIN32)
|
||||
if (!is_file_exists_in_gamedir(gamedll->pathname))
|
||||
|
@ -15,6 +15,8 @@ void WINAPI GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t* pG
|
||||
gpGlobals = pGlobals;
|
||||
g_engine.funcs = &g_engfuncs;
|
||||
g_engine.globals = pGlobals;
|
||||
g_engfuncs = *pengfuncsFromEngine;
|
||||
g_engine.sys_module.load(pengfuncsFromEngine);
|
||||
|
||||
g_engfuncs = *pengfuncsFromEngine;
|
||||
flush_ALERT_buffer();
|
||||
|
File diff suppressed because it is too large
Load Diff
118
metamod/src/mem_utils.cpp
Normal file
118
metamod/src/mem_utils.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
static_allocator::static_allocator(memory_protection protection) : m_protection(protection)
|
||||
{
|
||||
}
|
||||
|
||||
char *static_allocator::allocate(const size_t n)
|
||||
{
|
||||
if (!m_pages.size() || m_used + n > Pagesize)
|
||||
allocate_page();
|
||||
|
||||
auto ptr = reinterpret_cast<char *>(m_pages.back()) + m_used;
|
||||
m_used += n;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *static_allocator::strdup(const char *string)
|
||||
{
|
||||
size_t len = Q_strlen(string) + 1;
|
||||
return (char *)Q_memcpy(allocate(len), string, len);
|
||||
}
|
||||
|
||||
void static_allocator::deallocate_all()
|
||||
{
|
||||
for (auto page : m_pages)
|
||||
#ifdef WIN32
|
||||
VirtualFree(page, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap(page, Pagesize);
|
||||
#endif
|
||||
|
||||
m_pages.clear();
|
||||
}
|
||||
|
||||
size_t static_allocator::memory_used() const
|
||||
{
|
||||
return (m_pages.size() - 1) * Pagesize + m_used;
|
||||
}
|
||||
|
||||
bool static_allocator::contain(uint32 addr)
|
||||
{
|
||||
for (auto p : m_pages) {
|
||||
if (uint32(p) <= addr && addr < uint32(p) + Pagesize)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char *static_allocator::find_pattern(char *pattern, size_t len)
|
||||
{
|
||||
for (auto p : m_pages) {
|
||||
for (char *c = (char *)p, *e = c + Pagesize - len; c < e; c++) {
|
||||
if (mem_compare(c, pattern, len))
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void static_allocator::allocate_page()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto page = VirtualAlloc(nullptr, Pagesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#else
|
||||
auto page = mmap(nullptr, Pagesize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
#endif
|
||||
|
||||
m_used = 0;
|
||||
m_pages.push_back(page);
|
||||
}
|
||||
|
||||
bool mem_compare(const char *addr, const char *pattern, size_t len)
|
||||
{
|
||||
for (auto c = pattern, pattern_end = pattern + len; c < pattern_end; ++c, ++addr) {
|
||||
if (*c == *addr || *c == '\x2A')
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char *mem_find_pattern(char *pos, int range, const char *pattern, size_t len)
|
||||
{
|
||||
for (auto c = pos + range - len; pos < c; ++pos) {
|
||||
if (mem_compare(pos, pattern, len))
|
||||
return pos;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *mem_find_ref(char *pos, char *end, char opcode, uint32 ref, bool relative)
|
||||
{
|
||||
for (; pos < end; ++pos)
|
||||
{
|
||||
if (*pos == opcode)
|
||||
{
|
||||
if (relative)
|
||||
{
|
||||
if ((uint32)pos + 5 + *(uint32 *)(pos + 1) == ref)
|
||||
return pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*(uint32 *)(pos + 1) == ref)
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *mem_find_string_push(char *addr, const char *string, size_t len)
|
||||
{
|
||||
char *ptr = mem_find_pattern(addr, len, string, Q_strlen(string) + 1);
|
||||
return mem_find_ref(addr, addr + len - 5, '\x68', (uint32)ptr, false);
|
||||
}
|
49
metamod/src/mem_utils.h
Normal file
49
metamod/src/mem_utils.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
class static_allocator
|
||||
{
|
||||
public:
|
||||
enum memory_protection : uint8
|
||||
{
|
||||
#ifdef _WIN32
|
||||
mp_readwrite = PAGE_READWRITE,
|
||||
mp_rwx = PAGE_EXECUTE_READWRITE
|
||||
#else
|
||||
mp_readwrite = PROT_READ | PROT_WRITE,
|
||||
mp_rwx = PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
#endif
|
||||
};
|
||||
|
||||
static_allocator(memory_protection protection);
|
||||
char *allocate(const size_t n);
|
||||
char *strdup(const char *string);
|
||||
void deallocate_all();
|
||||
size_t memory_used() const;
|
||||
bool contain(uint32 addr);
|
||||
char *find_pattern(char *pattern, size_t len);
|
||||
|
||||
template<typename T>
|
||||
T *allocate()
|
||||
{
|
||||
return (T *)allocate(sizeof(T));
|
||||
}
|
||||
|
||||
private:
|
||||
void allocate_page();
|
||||
|
||||
enum
|
||||
{
|
||||
Pagesize = 4096
|
||||
};
|
||||
|
||||
size_t m_used = 0;
|
||||
std::vector<void *> m_pages;
|
||||
memory_protection m_protection;
|
||||
|
||||
friend class CJit;
|
||||
};
|
||||
|
||||
bool mem_compare(const char *addr, const char *pattern, size_t len);
|
||||
char *mem_find_pattern(char *pos, int range, const char *pattern, size_t len);
|
||||
char *mem_find_ref(char *pos, char *end, char opcode, uint32 ref, bool relative);
|
||||
char *mem_find_string_push(char *addr, const char *string, size_t len);
|
55
metamod/src/meta_rehlds_api.cpp
Normal file
55
metamod/src/meta_rehlds_api.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
IRehldsApi* g_RehldsApi;
|
||||
const RehldsFuncs_t* g_RehldsFuncs;
|
||||
IRehldsHookchains* g_RehldsHookchains;
|
||||
IRehldsServerStatic* g_RehldsSvs;
|
||||
|
||||
bool rehlds_api_init(CSysModule* engineModule)
|
||||
{
|
||||
if (!engineModule) {
|
||||
META_ERROR("Failed to locate engine module\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CreateInterfaceFn ifaceFactory = Sys_GetFactory(engineModule);
|
||||
if (!ifaceFactory) {
|
||||
META_ERROR("Failed to locate interface factory in engine module\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int retCode = 0;
|
||||
g_RehldsApi = (IRehldsApi*)ifaceFactory(VREHLDS_HLDS_API_VERSION, &retCode);
|
||||
if (!g_RehldsApi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int majorVersion = g_RehldsApi->GetMajorVersion();
|
||||
int minorVersion = g_RehldsApi->GetMinorVersion();
|
||||
|
||||
if (majorVersion != REHLDS_API_VERSION_MAJOR) {
|
||||
META_ERROR("REHLDS Api major version mismatch; expected %d, real %d\n", REHLDS_API_VERSION_MAJOR, majorVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (minorVersion < REHLDS_API_VERSION_MINOR) {
|
||||
META_ERROR("REHLDS Api minor version mismatch; expected at least %d, real %d\n", REHLDS_API_VERSION_MINOR, minorVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_RehldsFuncs = g_RehldsApi->GetFuncs();
|
||||
g_RehldsHookchains = g_RehldsApi->GetHookchains();
|
||||
g_RehldsSvs = g_RehldsApi->GetServerStatic();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool meta_init_rehlds_api()
|
||||
{
|
||||
CSysModule* engineModule = Sys_LoadModule(ENGINE_LIB);
|
||||
if (!rehlds_api_init(engineModule)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "engine_hlds_api.h"
|
||||
|
||||
extern IRehldsApi* g_RehldsApi;
|
||||
extern const RehldsFuncs_t* g_RehldsFuncs;
|
||||
extern IRehldsHookchains* g_RehldsHookchains;
|
@ -1,6 +1,6 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
cvar_t g_meta_version = { "metamod_version", APP_VERSION_STRD, FCVAR_SERVER, 0, nullptr };
|
||||
cvar_t g_meta_version = { "metamod_version", APP_VERSION, FCVAR_SERVER, 0, nullptr };
|
||||
|
||||
MConfig g_static_config;
|
||||
MConfig *g_config = &g_static_config;
|
||||
@ -44,21 +44,20 @@ void metamod_startup()
|
||||
Q_snprintf(execFile, sizeof execFile, "%s/%s", g_config->directory(), EXEC_CFG);
|
||||
|
||||
META_CONS(" ");
|
||||
META_CONS(" Metamod-r version %s Copyright (c) 2016-2017 ReHLDS Team (rebuild of original Metamod by Will Day and Jussi Kivilinna)", APP_VERSION_STRD);
|
||||
META_CONS(" Metamod-r version %s Copyright (c) 2016-2017 ReHLDS Team (rebuild of original Metamod by Will Day and Jussi Kivilinna)", APP_VERSION);
|
||||
META_CONS(" Metamod-r comes with ABSOLUTELY NO WARRANTY; for details type `meta gpl'.");
|
||||
META_CONS(" This is free software, and you are welcome to redistribute it");
|
||||
META_CONS(" under certain conditions; type `meta gpl' for details.");
|
||||
META_CONS(" ");
|
||||
|
||||
META_CONS("Metamod-r v%s, API (%s)", APP_VERSION_STRD, META_INTERFACE_VERSION);
|
||||
META_CONS("Metamod-r v%s, API (%s)", APP_VERSION, META_INTERFACE_VERSION);
|
||||
META_CONS("Metamod-r build: " __TIME__ " " __DATE__ "");
|
||||
META_CONS("Metamod-r from: " APP_COMMIT_URL APP_COMMIT_SHA "");
|
||||
|
||||
// Get gamedir, very early on, because it seems we need it all over the
|
||||
// place here at the start.
|
||||
if (!meta_init_gamedll()) {
|
||||
META_ERROR("Failure to init game DLL; exiting...");
|
||||
do_exit(1);
|
||||
Sys_Error("Failure to init game DLL; exiting...");
|
||||
}
|
||||
|
||||
// Register various console commands and cvars.
|
||||
@ -201,8 +200,7 @@ void metamod_startup()
|
||||
g_plugins = new MPluginList(pluginFile);
|
||||
|
||||
if (!meta_load_gamedll()) {
|
||||
META_ERROR("Failure to load game DLL; exiting...");
|
||||
do_exit(1);
|
||||
Sys_Error("Failure to load game DLL; exiting...");
|
||||
}
|
||||
|
||||
if (!g_plugins->load()) {
|
||||
@ -212,6 +210,10 @@ void metamod_startup()
|
||||
|
||||
meta_init_rehlds_api();
|
||||
|
||||
if (!g_meta_extdll.init(&g_engine.sys_module)) {
|
||||
Sys_Error("Failure to init extension DLL; exiting...");
|
||||
}
|
||||
|
||||
// Allow for commands to metamod plugins at startup. Autoexec.cfg is
|
||||
// read too early, and server.cfg is read too late.
|
||||
//
|
||||
@ -294,7 +296,7 @@ bool get_function_table(const char* ifname, int ifvers_mm, table_t*& table, size
|
||||
auto pfnGetFuncs = (getfunc_t)g_GameDLL.sys_module.getsym(ifname);
|
||||
|
||||
if (pfnGetFuncs) {
|
||||
table = (table_t *)Q_calloc(1, table_size);
|
||||
table = (table_t *)calloc(1, table_size);
|
||||
|
||||
int ifvers_gamedll = ifvers_mm;
|
||||
|
||||
@ -304,7 +306,7 @@ bool get_function_table(const char* ifname, int ifvers_mm, table_t*& table, size
|
||||
}
|
||||
|
||||
META_ERROR("dll: Failure calling %s in game '%s'", ifname, g_GameDLL.name);
|
||||
Q_free(table);
|
||||
free(table);
|
||||
table = nullptr;
|
||||
|
||||
if (ifvers_gamedll != ifvers_mm) {
|
||||
@ -336,7 +338,7 @@ bool get_function_table_old(const char* ifname, int ifvers_mm, table_t*& table,
|
||||
auto pfnGetFuncs = (getfunc_t)g_GameDLL.sys_module.getsym(ifname);
|
||||
|
||||
if (pfnGetFuncs) {
|
||||
table = (table_t *)Q_calloc(1, table_size);
|
||||
table = (table_t *)calloc(1, table_size);
|
||||
|
||||
if (pfnGetFuncs(table, ifvers_mm)) {
|
||||
META_DEBUG(3, "dll: Game '%s': Found %s", g_GameDLL.name, ifname);
|
||||
@ -344,7 +346,7 @@ bool get_function_table_old(const char* ifname, int ifvers_mm, table_t*& table,
|
||||
}
|
||||
|
||||
META_ERROR("dll: Failure calling %s in game '%s'", ifname, g_GameDLL.name);
|
||||
Q_free(table);
|
||||
free(table);
|
||||
table = nullptr;
|
||||
}
|
||||
else {
|
||||
@ -478,8 +480,7 @@ static void meta_apply_fix_data(std::vector<fixdata_t>& data)
|
||||
|
||||
char* ptr = g_jit.find_callback_pattern(pattern, sizeof pattern);
|
||||
if (!ptr) {
|
||||
META_ERROR("Failed to fix callback retaddr.\n Bye bye...\n");
|
||||
do_exit(666);
|
||||
Sys_Error("Failed to fix callback retaddr.\n Bye bye...\n");
|
||||
}
|
||||
|
||||
// FF D1 call ecx
|
||||
|
@ -1,70 +0,0 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
IRehldsApi* g_RehldsApi;
|
||||
const RehldsFuncs_t* g_RehldsFuncs;
|
||||
IRehldsHookchains* g_RehldsHookchains;
|
||||
IRehldsServerStatic* g_RehldsSvs;
|
||||
|
||||
bool rehlds_api_try_init(CSysModule* engineModule, char* failureReason)
|
||||
{
|
||||
if (!engineModule) {
|
||||
META_ERROR("Failed to locate engine module\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CreateInterfaceFn ifaceFactory = Sys_GetFactory(engineModule);
|
||||
if (!ifaceFactory) {
|
||||
sprintf(failureReason, "Failed to locate interface factory in engine module\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int retCode = 0;
|
||||
g_RehldsApi = (IRehldsApi*)ifaceFactory(VREHLDS_HLDS_API_VERSION, &retCode);
|
||||
if (!g_RehldsApi) {
|
||||
sprintf(failureReason, "Failed to locate retrieve rehlds api interface from engine module, return code is %d\n", retCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
int majorVersion = g_RehldsApi->GetMajorVersion();
|
||||
int minorVersion = g_RehldsApi->GetMinorVersion();
|
||||
|
||||
if (majorVersion != REHLDS_API_VERSION_MAJOR) {
|
||||
sprintf(failureReason, "REHLDS Api major version mismatch; expected %d, real %d\n", REHLDS_API_VERSION_MAJOR, majorVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (minorVersion < REHLDS_API_VERSION_MINOR) {
|
||||
sprintf(failureReason, "REHLDS Api minor version mismatch; expected at least %d, real %d\n", REHLDS_API_VERSION_MINOR, minorVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_RehldsFuncs = g_RehldsApi->GetFuncs();
|
||||
g_RehldsHookchains = g_RehldsApi->GetHookchains();
|
||||
g_RehldsSvs = g_RehldsApi->GetServerStatic();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool meta_init_rehlds_api()
|
||||
{
|
||||
char failReason[2048];
|
||||
|
||||
#ifdef WIN32
|
||||
CSysModule* engineModule = Sys_LoadModule("swds.dll");
|
||||
if (!rehlds_api_try_init(engineModule, failReason)) {
|
||||
engineModule = Sys_LoadModule("filesystem_stdio.dll");
|
||||
if (!rehlds_api_try_init(engineModule, failReason)) {
|
||||
META_ERROR("%s", failReason);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
CSysModule* engineModule = Sys_LoadModule("engine_i486.so");
|
||||
if (!rehlds_api_try_init(engineModule, failReason)) {
|
||||
META_ERROR("%s", failReason);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
96
metamod/src/mextdll.cpp
Normal file
96
metamod/src/mextdll.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
CExtDll g_meta_extdll;
|
||||
|
||||
CExtDll::CExtDll()
|
||||
: m_dlls(nullptr), m_count(nullptr), m_hGameDLL(CSysModule::INVALID_HANDLE)
|
||||
{
|
||||
}
|
||||
|
||||
void CExtDll::load()
|
||||
{
|
||||
if (g_RehldsFuncs)
|
||||
{
|
||||
if (!g_RehldsFuncs->AddExtDll(m_hGameDLL)) {
|
||||
Sys_Error("Failure to add extension DLL; exiting...\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto extdll = &m_dlls[(*m_count)++];
|
||||
Q_memset(extdll, 0, sizeof(*extdll));
|
||||
extdll->lDLLHandle = m_hGameDLL;
|
||||
}
|
||||
|
||||
void CExtDll::unload()
|
||||
{
|
||||
if (g_RehldsFuncs) {
|
||||
g_RehldsFuncs->RemoveExtDll(m_hGameDLL);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < *m_count; i++)
|
||||
{
|
||||
if (m_dlls[i].lDLLHandle == m_hGameDLL)
|
||||
{
|
||||
--(*m_count);
|
||||
if (*m_count != i)
|
||||
{
|
||||
Q_memmove(&m_dlls[i], &m_dlls[i + 1], (*m_count - i) * sizeof(m_dlls[0]));
|
||||
i = *m_count;
|
||||
}
|
||||
|
||||
Q_memset(&m_dlls[i], 0, sizeof(m_dlls[0]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CExtDll::init(CSysModule *module)
|
||||
{
|
||||
m_hGameDLL = g_GameDLL.sys_module.gethandle();
|
||||
|
||||
if (g_RehldsFuncs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
m_dlls = (extensiondll_t *)module->getsym("g_rgextdll");
|
||||
m_count = (size_t *)module->getsym("g_iextdllMac");
|
||||
|
||||
if (m_dlls && m_count) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// HACK HACK MORE HACK
|
||||
// HLDS SHIT
|
||||
auto pos = module->find_string_push("SV_SaveGameComment");
|
||||
if (!pos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char patterns[2][2][14] = {
|
||||
{ "\x56\x33\xF6\x39\x2A\x2A\x2A\x2A\x2A\x7E\x2A\x53\x8B", "\x5B\xC3\x90\x90\xA1\x2A\x2A\x2A\x2A\x53\x56\x57\x33" },
|
||||
{ "\x53\x8B\x2A\x2A\x2A\x2A\x2A\x57\xBF\x2A\x2A\x2A\x2A", "\x7E\x2A\x8B\x2A\x2A\x2A\x2A\x2A\xBE\x2A\x2A\x2A\x2A" },
|
||||
};
|
||||
|
||||
for (auto i = 0u; i < ARRAYSIZE(patterns); i++)
|
||||
{
|
||||
auto addr = mem_find_pattern(pos - 33, 20, patterns[0][i], sizeof(patterns[0][i]) - 1);
|
||||
if (!addr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_count = *(size_t **)(addr + 5);
|
||||
|
||||
addr = mem_find_pattern(addr, 30, patterns[1][i], sizeof(patterns[1][i]) - 1);
|
||||
if (!addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_dlls = *(extensiondll_t **)(addr + 9);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
19
metamod/src/mextdll.h
Normal file
19
metamod/src/mextdll.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "pr_dlls.h"
|
||||
|
||||
class CExtDll
|
||||
{
|
||||
public:
|
||||
CExtDll();
|
||||
bool init(CSysModule *module);
|
||||
void load();
|
||||
void unload();
|
||||
|
||||
private:
|
||||
module_handle_t m_hGameDLL;
|
||||
extensiondll_t *m_dlls;
|
||||
size_t *m_count;
|
||||
};
|
||||
|
||||
extern CExtDll g_meta_extdll;
|
@ -629,7 +629,7 @@ template<typename T>
|
||||
void free_table(T& table)
|
||||
{
|
||||
if (table) {
|
||||
Q_free(table);
|
||||
free(table);
|
||||
table = nullptr;
|
||||
}
|
||||
}
|
||||
@ -861,7 +861,7 @@ bool get_function_table_from_plugin(const char* pl_desc, int ifvers_mm, getter_t
|
||||
|
||||
if (getter) {
|
||||
if (!table)
|
||||
table = (table_t *)Q_calloc(1, table_size);
|
||||
table = (table_t *)calloc(1, table_size);
|
||||
if (getter(table, &ifvers_pl)) {
|
||||
META_DEBUG(3, "dll: Plugin '%s': Found %s", pl_desc, getter_name);
|
||||
return true;
|
||||
@ -874,7 +874,7 @@ bool get_function_table_from_plugin(const char* pl_desc, int ifvers_mm, getter_t
|
||||
else {
|
||||
META_DEBUG(5, "dll: Plugin '%s': No %s", pl_desc, getter_name);
|
||||
if (table)
|
||||
Q_free(table);
|
||||
free(table);
|
||||
table = nullptr;
|
||||
}
|
||||
|
||||
@ -886,7 +886,7 @@ bool get_function_table_from_plugin_old(const char* pl_desc, int ifvers_mm, gett
|
||||
{
|
||||
if (getter) {
|
||||
if (!table)
|
||||
table = (table_t *)Q_calloc(1, table_size);
|
||||
table = (table_t *)calloc(1, table_size);
|
||||
if (getter(table, ifvers_mm)) {
|
||||
META_DEBUG(3, "dll: Plugin '%s': Found %s", pl_desc, getter_name);
|
||||
return true;
|
||||
@ -897,7 +897,7 @@ bool get_function_table_from_plugin_old(const char* pl_desc, int ifvers_mm, gett
|
||||
else {
|
||||
META_DEBUG(5, "dll: Plugin '%s': No %s", pl_desc, getter_name);
|
||||
if (table)
|
||||
Q_free(table);
|
||||
free(table);
|
||||
table = nullptr;
|
||||
}
|
||||
|
||||
@ -924,7 +924,7 @@ bool MPlugin::attach(PLUG_LOADTIME now)
|
||||
// Make copy of gameDLL's function tables for each plugin, so we don't
|
||||
// risk the plugins screwing with the tables everyone uses.
|
||||
if (g_GameDLL.funcs.dllapi_table && !m_gamedll_funcs.dllapi_table) {
|
||||
m_gamedll_funcs.dllapi_table = (DLL_FUNCTIONS *)Q_malloc(sizeof(DLL_FUNCTIONS));
|
||||
m_gamedll_funcs.dllapi_table = (DLL_FUNCTIONS *)malloc(sizeof(DLL_FUNCTIONS));
|
||||
if (!m_gamedll_funcs.dllapi_table) {
|
||||
META_ERROR("dll: Failed attach plugin '%s': Failed malloc() for dllapi_table");
|
||||
return false;
|
||||
@ -932,7 +932,7 @@ bool MPlugin::attach(PLUG_LOADTIME now)
|
||||
Q_memcpy(m_gamedll_funcs.dllapi_table, g_GameDLL.funcs.dllapi_table, sizeof(DLL_FUNCTIONS));
|
||||
}
|
||||
if (g_GameDLL.funcs.newapi_table && !m_gamedll_funcs.newapi_table) {
|
||||
m_gamedll_funcs.newapi_table = (NEW_DLL_FUNCTIONS *)Q_malloc(sizeof(NEW_DLL_FUNCTIONS));
|
||||
m_gamedll_funcs.newapi_table = (NEW_DLL_FUNCTIONS *)malloc(sizeof(NEW_DLL_FUNCTIONS));
|
||||
if (!m_gamedll_funcs.newapi_table) {
|
||||
META_ERROR("dll: Failed attach plugin '%s': Failed malloc() for newapi_table");
|
||||
return false;
|
||||
|
@ -2,6 +2,12 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
constexpr char *PLATFORM_DLEXT = ".dll";
|
||||
#else
|
||||
constexpr char *PLATFORM_DLEXT = ".so";
|
||||
#endif
|
||||
|
||||
// Flags to indicate current "load" state of plugin.
|
||||
// NOTE: order is important, as greater/less comparisons are made.
|
||||
enum PLUG_STATUS : uint8
|
||||
|
@ -7,7 +7,7 @@ MRegCmd::MRegCmd(const char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plug
|
||||
|
||||
MRegCmd::~MRegCmd()
|
||||
{
|
||||
Q_free(m_name);
|
||||
free(m_name);
|
||||
}
|
||||
|
||||
bool MRegCmd::call() const
|
||||
@ -157,8 +157,8 @@ MRegCvar::MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin) : m_cvar(cv_ptr), m_plugi
|
||||
|
||||
MRegCvar::~MRegCvar()
|
||||
{
|
||||
Q_free((void *)m_cvar->name);
|
||||
Q_free(m_cvar->string);
|
||||
free((void *)m_cvar->name);
|
||||
free(m_cvar->string);
|
||||
delete m_cvar;
|
||||
}
|
||||
|
||||
|
@ -1,153 +0,0 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
CSysModule::CSysModule() : m_handle(0), m_base(0), m_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
module_handle_t CSysModule::load(const char* filepath)
|
||||
{
|
||||
if (!m_handle) {
|
||||
m_handle = LoadLibrary(filepath);
|
||||
|
||||
MODULEINFO module_info;
|
||||
if (GetModuleInformation(GetCurrentProcess(), m_handle, &module_info, sizeof module_info)) {
|
||||
m_base = (uintptr_t)module_info.lpBaseOfDll;
|
||||
m_size = module_info.SizeOfImage;
|
||||
}
|
||||
}
|
||||
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool CSysModule::unload()
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
if (m_handle) {
|
||||
ret = FreeLibrary(m_handle) != ERROR;
|
||||
m_handle = 0;
|
||||
m_base = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* CSysModule::getsym(const char* name) const
|
||||
{
|
||||
return m_handle ? GetProcAddress(m_handle, name) : nullptr;
|
||||
}
|
||||
#else
|
||||
static ElfW(Addr) dlsize(void* base)
|
||||
{
|
||||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Phdr) *phdr;
|
||||
ElfW(Addr) end;
|
||||
|
||||
ehdr = (ElfW(Ehdr) *)base;
|
||||
|
||||
/* Find the first program header */
|
||||
phdr = (ElfW(Phdr)*)((ElfW(Addr))ehdr + ehdr->e_phoff);
|
||||
|
||||
/* Find the final PT_LOAD segment's extent */
|
||||
for (int i = 0; i < ehdr->e_phnum; ++i)
|
||||
if (phdr[i].p_type == PT_LOAD)
|
||||
end = phdr[i].p_vaddr + phdr[i].p_memsz;
|
||||
|
||||
/* The start (virtual) address is always zero, so just return end.*/
|
||||
return end;
|
||||
}
|
||||
|
||||
module_handle_t CSysModule::load(const char* filepath)
|
||||
{
|
||||
if (!m_handle) {
|
||||
m_handle = dlopen(filepath, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
|
||||
|
||||
char buf[1024], dummy[1024], path[260];
|
||||
sprintf(buf, "/proc/%i/maps", getpid());
|
||||
|
||||
FILE* fp = fopen(buf, "r");
|
||||
|
||||
while (fgets(buf, sizeof buf, fp)) {
|
||||
uintptr_t start, end;
|
||||
|
||||
int args = sscanf(buf, "%x-%x %128s %128s %128s %128s %255s", &start, &end, dummy, dummy, dummy, dummy, path);
|
||||
if (args != 7) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Q_stricmp(path, filepath)) {
|
||||
m_base = start;
|
||||
m_size = end - start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool CSysModule::unload()
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
if (m_handle) {
|
||||
ret = dlclose(m_handle) != 0;
|
||||
m_handle = 0;
|
||||
m_base = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* CSysModule::getsym(const char* name) const
|
||||
{
|
||||
return m_handle ? dlsym(m_handle, name) : nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
module_handle_t CSysModule::gethandle() const
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool CSysModule::contain(void* addr) const
|
||||
{
|
||||
return addr && uintptr_t(addr) > m_base && uintptr_t(addr) < m_base + m_size;
|
||||
}
|
||||
|
||||
const char* CSysModule::getloaderror()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return str_GetLastError();
|
||||
#else
|
||||
return dlerror();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows doesn't provide a functon analagous to dlerr() that returns a
|
||||
// string describing the error, so we include one here, as exampled at:
|
||||
// http://msdn.microsoft.com/library/en-us/debug/errors_0sdh.asp
|
||||
// except without FORMAT_MESSAGE_ALLOCATE_BUFFER, since we use a local
|
||||
// static buffer.
|
||||
static const char* str_GetLastError()
|
||||
{
|
||||
static char buf[MAX_STRBUF_LEN];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, MAX_STRBUF_LEN - 1, nullptr);
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* str_os_error()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return str_GetLastError();
|
||||
#else
|
||||
return strerror(errno);
|
||||
#endif
|
||||
}
|
@ -1,52 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// String describing platform/DLL-type, for matching lines in plugins.ini.
|
||||
#ifdef _WIN32
|
||||
#define UNUSED /**/
|
||||
|
||||
#define PLATFORM "mswin"
|
||||
#define PLATFORM_SPC "win32"
|
||||
#define PLATFORM_DLEXT ".dll"
|
||||
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
#else
|
||||
#define UNUSED __attribute__((unused))
|
||||
|
||||
#define PLATFORM "linux"
|
||||
#define PLATFORM_SPC "lin32"
|
||||
#define PLATFORM_DLEXT ".so"
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef HINSTANCE module_handle_t;
|
||||
#else
|
||||
typedef void* module_handle_t;
|
||||
#endif
|
||||
|
||||
class CSysModule
|
||||
{
|
||||
public:
|
||||
CSysModule();
|
||||
module_handle_t load(const char* filename);
|
||||
bool unload();
|
||||
void* getsym(const char* name) const;
|
||||
module_handle_t gethandle() const;
|
||||
bool contain(void* addr) const;
|
||||
static const char* getloaderror();
|
||||
|
||||
private:
|
||||
module_handle_t m_handle;
|
||||
uintptr_t m_base;
|
||||
uintptr_t m_size;
|
||||
};
|
||||
|
||||
// Windows doesn't have an strtok_r() routine, so we write our own.
|
||||
#ifdef _WIN32
|
||||
#define strtok_r(s, delim, ptrptr) mm_strtok_r(s, delim, ptrptr)
|
||||
#define strtok_r strtok_s
|
||||
#endif // _WIN32
|
||||
|
||||
// Set filename and pathname maximum lengths. Note some windows compilers
|
||||
@ -110,8 +66,4 @@ private:
|
||||
#ifndef S_IWGRP
|
||||
#define S_IWGRP S_IWUSR
|
||||
#endif
|
||||
|
||||
const char *str_GetLastError();
|
||||
#endif // _WIN32
|
||||
|
||||
const char* str_os_error();
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "osconfig.h"
|
||||
#include "jitasm.h"
|
||||
#include "strtools.h"
|
||||
|
||||
#define CreateInterface mm_CreateInterface
|
||||
|
||||
@ -27,6 +28,7 @@
|
||||
#include <rehlds_api.h>
|
||||
|
||||
#include "osdep.h"
|
||||
#include "sys_module.h"
|
||||
#include "mdebug.h"
|
||||
#include "api_info.h"
|
||||
#include "commands_meta.h"
|
||||
@ -38,6 +40,7 @@
|
||||
#include "game_support.h"
|
||||
#include "mreg.h"
|
||||
#include "meta_api.h"
|
||||
#include "mextdll.h"
|
||||
#include "mutil.h"
|
||||
#include "reg_support.h"
|
||||
#include "mlist.h"
|
||||
@ -47,8 +50,9 @@
|
||||
#include "sdk_util.h"
|
||||
#include "enginecallbacks.h"
|
||||
#include "utils.h"
|
||||
#include "mem_utils.h"
|
||||
#include "callback_jit.h"
|
||||
#include "metamod_rehlds_api.h"
|
||||
#include "meta_rehlds_api.h"
|
||||
|
||||
#undef CreateInterface
|
||||
#include "linkent.h"
|
||||
|
207
metamod/src/sys_module.cpp
Normal file
207
metamod/src/sys_module.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
const module_handle_t CSysModule::INVALID_HANDLE = (module_handle_t)0;
|
||||
|
||||
CSysModule::CSysModule() : m_handle(INVALID_HANDLE), m_base(0), m_size(0), m_free(true)
|
||||
{
|
||||
}
|
||||
|
||||
bool CSysModule::is_opened() const
|
||||
{
|
||||
return m_handle != INVALID_HANDLE;
|
||||
}
|
||||
|
||||
char *CSysModule::find_string_push(const char *string)
|
||||
{
|
||||
return mem_find_string_push((char *)getbase(), string, getsize());
|
||||
}
|
||||
|
||||
char *CSysModule::find_pattern(char *pos, int range, const char *pattern, size_t len)
|
||||
{
|
||||
for (auto c = pos + range - len; pos < c; ++pos) {
|
||||
if (mem_compare(pos, pattern, len))
|
||||
return pos;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
module_handle_t CSysModule::load(void *addr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mem;
|
||||
VirtualQuery(addr, &mem, sizeof(mem));
|
||||
|
||||
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)mem.AllocationBase;
|
||||
IMAGE_NT_HEADERS *pe = (IMAGE_NT_HEADERS *)((uintptr_t)dos + (uintptr_t)dos->e_lfanew);
|
||||
|
||||
if (pe->Signature != IMAGE_NT_SIGNATURE)
|
||||
return INVALID_HANDLE;
|
||||
|
||||
m_free = false;
|
||||
m_base = (uintptr_t)mem.AllocationBase;
|
||||
m_size = (size_t)pe->OptionalHeader.SizeOfImage;
|
||||
|
||||
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCTSTR>(addr), &m_handle);
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
module_handle_t CSysModule::load(const char *filepath)
|
||||
{
|
||||
if (!m_handle) {
|
||||
m_handle = LoadLibrary(filepath);
|
||||
|
||||
MODULEINFO module_info;
|
||||
if (GetModuleInformation(GetCurrentProcess(), m_handle, &module_info, sizeof(module_info))) {
|
||||
m_base = (uintptr_t)module_info.lpBaseOfDll;
|
||||
m_size = module_info.SizeOfImage;
|
||||
}
|
||||
}
|
||||
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool CSysModule::unload()
|
||||
{
|
||||
if (m_handle == INVALID_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
if (m_free) {
|
||||
ret = FreeLibrary(m_handle) != ERROR;
|
||||
}
|
||||
|
||||
m_handle = INVALID_HANDLE;
|
||||
m_base = 0;
|
||||
m_size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *CSysModule::getsym(const char *name) const
|
||||
{
|
||||
return m_handle ? GetProcAddress(m_handle, name) : nullptr;
|
||||
}
|
||||
#else
|
||||
|
||||
static ElfW(Addr) dlsize(void *base)
|
||||
{
|
||||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Phdr) *phdr;
|
||||
ElfW(Addr) end;
|
||||
|
||||
ehdr = (ElfW(Ehdr) *)base;
|
||||
|
||||
// Find the first program header
|
||||
phdr = (ElfW(Phdr)*)((ElfW(Addr))ehdr + ehdr->e_phoff);
|
||||
|
||||
// Find the final PT_LOAD segment's extent
|
||||
for (int i = 0; i < ehdr->e_phnum; ++i)
|
||||
if (phdr[i].p_type == PT_LOAD)
|
||||
end = phdr[i].p_vaddr + phdr[i].p_memsz;
|
||||
|
||||
// The start (virtual) address is always zero, so just return end.
|
||||
return end;
|
||||
}
|
||||
|
||||
module_handle_t CSysModule::load(void *addr)
|
||||
{
|
||||
Dl_info dlinfo;
|
||||
if ((!dladdr(addr, &dlinfo) && !dlinfo.dli_fbase) || !dlinfo.dli_fname) {
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
|
||||
m_free = false;
|
||||
m_base = (uintptr_t)dlinfo.dli_fbase;
|
||||
m_size = (size_t)dlsize(dlinfo.dli_fbase);
|
||||
|
||||
m_handle = dlopen(dlinfo.dli_fname, RTLD_NOW | RTLD_NOLOAD);
|
||||
}
|
||||
|
||||
module_handle_t CSysModule::load(const char *filepath)
|
||||
{
|
||||
if (!m_handle) {
|
||||
m_handle = dlopen(filepath, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
|
||||
|
||||
char buf[1024], dummy[1024], path[260];
|
||||
sprintf(buf, "/proc/%i/maps", getpid());
|
||||
|
||||
FILE* fp = fopen(buf, "r");
|
||||
|
||||
while (fgets(buf, sizeof buf, fp)) {
|
||||
uintptr_t start, end;
|
||||
|
||||
int args = sscanf(buf, "%x-%x %128s %128s %128s %128s %255s", &start, &end, dummy, dummy, dummy, dummy, path);
|
||||
if (args != 7) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Q_stricmp(path, filepath)) {
|
||||
m_base = start;
|
||||
m_size = end - start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool CSysModule::unload()
|
||||
{
|
||||
if (m_handle == INVALID_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
if (m_free) {
|
||||
ret = dlclose(m_handle) != 0;
|
||||
}
|
||||
|
||||
m_handle = INVALID_HANDLE;
|
||||
m_base = 0;
|
||||
m_size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* CSysModule::getsym(const char *name) const
|
||||
{
|
||||
return m_handle ? dlsym(m_handle, name) : nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
module_handle_t CSysModule::gethandle() const
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
uintptr_t CSysModule::getbase() const
|
||||
{
|
||||
return m_base;
|
||||
}
|
||||
|
||||
size_t CSysModule::getsize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool CSysModule::contain(void *addr) const
|
||||
{
|
||||
return addr && uintptr_t(addr) > m_base && uintptr_t(addr) < m_base + m_size;
|
||||
}
|
||||
|
||||
const char *CSysModule::getloaderror()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static char buf[1024];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, sizeof(buf) - 1, nullptr);
|
||||
return buf;
|
||||
#else
|
||||
return dlerror();
|
||||
#endif
|
||||
}
|
35
metamod/src/sys_module.h
Normal file
35
metamod/src/sys_module.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef HINSTANCE module_handle_t;
|
||||
#else
|
||||
typedef void* module_handle_t;
|
||||
#endif
|
||||
|
||||
class CSysModule
|
||||
{
|
||||
public:
|
||||
CSysModule();
|
||||
|
||||
module_handle_t load(void *addr);
|
||||
module_handle_t load(const char *filename);
|
||||
bool unload();
|
||||
void *getsym(const char *name) const;
|
||||
module_handle_t gethandle() const;
|
||||
uintptr_t getbase() const;
|
||||
size_t getsize() const;
|
||||
bool contain(void *addr) const;
|
||||
bool is_opened() const;
|
||||
|
||||
char *find_string_push(const char *string);
|
||||
char *find_pattern(char *pos, int range, const char *pattern, size_t len);
|
||||
|
||||
static const char *getloaderror();
|
||||
static const module_handle_t INVALID_HANDLE;
|
||||
|
||||
private:
|
||||
module_handle_t m_handle;
|
||||
uintptr_t m_base;
|
||||
size_t m_size;
|
||||
bool m_free; // m_handle should be released
|
||||
};
|
@ -28,104 +28,6 @@ const char* LOCALINFO(char* key)
|
||||
return ENTITY_KEYVALUE(nullptr, key);
|
||||
}
|
||||
|
||||
static_allocator::static_allocator(memory_protection protection) : m_protection(protection)
|
||||
{
|
||||
}
|
||||
|
||||
char* static_allocator::allocate(const size_t n)
|
||||
{
|
||||
if (!m_pages.size() || m_used + n > Pagesize)
|
||||
allocate_page();
|
||||
|
||||
auto ptr = reinterpret_cast<char *>(m_pages.back()) + m_used;
|
||||
m_used += n;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char* static_allocator::strdup(const char* string)
|
||||
{
|
||||
size_t len = strlen(string) + 1;
|
||||
return (char *)memcpy(allocate(len), string, len);
|
||||
}
|
||||
|
||||
void static_allocator::deallocate_all()
|
||||
{
|
||||
for (auto page : m_pages)
|
||||
#ifdef WIN32
|
||||
VirtualFree(page, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap(page, Pagesize);
|
||||
#endif
|
||||
|
||||
m_pages.clear();
|
||||
}
|
||||
|
||||
size_t static_allocator::memory_used() const
|
||||
{
|
||||
return (m_pages.size() - 1) * Pagesize + m_used;
|
||||
}
|
||||
|
||||
bool static_allocator::contain(uint32 addr)
|
||||
{
|
||||
for (auto p : m_pages) {
|
||||
if (uint32(p) <= addr && addr < uint32(p) + Pagesize)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char* static_allocator::find_pattern(char* pattern, size_t len)
|
||||
{
|
||||
for (auto p : m_pages) {
|
||||
for (char* c = (char *)p, *e = c + Pagesize - len; c < e; c++) {
|
||||
if (mem_compare(c, pattern, len))
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void static_allocator::allocate_page()
|
||||
{
|
||||
#ifdef WIN32
|
||||
auto page = VirtualAlloc(nullptr, Pagesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#else
|
||||
auto page = mmap(nullptr, Pagesize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
#endif
|
||||
|
||||
m_used = 0;
|
||||
m_pages.push_back(page);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Since windows doesn't provide a verison of strtok_r(), we include one
|
||||
// here. This may or may not operate exactly like strtok_r(), but does
|
||||
// what we need it it do.
|
||||
char* mm_strtok_r(char* s, const char* delim, char** ptrptr)
|
||||
{
|
||||
char* begin = nullptr;
|
||||
char* end = nullptr;
|
||||
char* rest = nullptr;
|
||||
if (s)
|
||||
begin = s;
|
||||
else
|
||||
begin = *ptrptr;
|
||||
if (!begin)
|
||||
return nullptr;
|
||||
|
||||
end = strpbrk(begin, delim);
|
||||
if (end) {
|
||||
*end = '\0';
|
||||
rest = end + 1;
|
||||
*ptrptr = rest + strspn(rest, delim);
|
||||
}
|
||||
else
|
||||
*ptrptr = nullptr;
|
||||
|
||||
return begin;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
char* trimbuf(char* str)
|
||||
{
|
||||
char* ibuf;
|
||||
@ -212,12 +114,6 @@ char* realpath(const char* file_name, char* resolved_name)
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
void __declspec(noreturn) do_exit(int exitval)
|
||||
{
|
||||
//Allahu Akbar!!
|
||||
*((int *)nullptr) = 0;
|
||||
}
|
||||
|
||||
// Checks for a non-empty file, relative to the gamedir if necessary.
|
||||
// Formerly used LOAD_FILE_FOR_ME, which provided a simple way to check for
|
||||
// a file under the gamedir, but which would _also_ look in the sibling
|
||||
@ -286,7 +182,7 @@ char* full_gamedir_path(const char* path, char* fullpath)
|
||||
|
||||
// Remove relative path components, if possible.
|
||||
if (!realpath(buf, fullpath)) {
|
||||
META_DEBUG(4, "Unable to get realpath for '%s': %s", buf, str_os_error());
|
||||
META_DEBUG(4, "Unable to get realpath for '%s': %s", buf, strerror(errno));
|
||||
Q_strncpy(fullpath, path, sizeof fullpath - 1);
|
||||
fullpath[sizeof fullpath - 1] = '\0';
|
||||
}
|
||||
@ -296,16 +192,6 @@ char* full_gamedir_path(const char* path, char* fullpath)
|
||||
return fullpath;
|
||||
}
|
||||
|
||||
bool mem_compare(const char* addr, const char* pattern, size_t len)
|
||||
{
|
||||
for (auto c = pattern, pattern_end = pattern + len; c < pattern_end; ++c, ++addr) {
|
||||
if (*c == *addr || *c == '\x2A')
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NORETURN Sys_Error(const char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
@ -316,8 +202,16 @@ void NORETURN Sys_Error(const char *error, ...)
|
||||
va_end(argptr);
|
||||
|
||||
META_CONS("FATAL ERROR (shutting down): %s\n", text);
|
||||
META_ERROR(text);
|
||||
|
||||
int *null = 0;
|
||||
#ifdef _WIN32
|
||||
MessageBox(GetForegroundWindow(), text, "Fatal error - Metamod", MB_ICONERROR | MB_OK);
|
||||
#endif // _WIN32
|
||||
|
||||
// Allow chance to read the message, before any window closes.
|
||||
sleep(3);
|
||||
|
||||
int *null = nullptr;
|
||||
*null = 0;
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -16,88 +16,11 @@ template <typename T, size_t N>
|
||||
char(&ArraySizeHelper(T(&array)[N]))[N];
|
||||
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
||||
|
||||
class static_allocator
|
||||
{
|
||||
public:
|
||||
enum memory_protection : uint8
|
||||
{
|
||||
#ifdef _WIN32
|
||||
mp_readwrite = PAGE_READWRITE,
|
||||
mp_rwx = PAGE_EXECUTE_READWRITE
|
||||
#else
|
||||
mp_readwrite = PROT_READ | PROT_WRITE,
|
||||
mp_rwx = PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
#endif
|
||||
};
|
||||
|
||||
static_allocator(memory_protection protection);
|
||||
char* allocate(const size_t n);
|
||||
char* strdup(const char* string);
|
||||
void deallocate_all();
|
||||
size_t memory_used() const;
|
||||
bool contain(uint32 addr);
|
||||
char* find_pattern(char* pattern, size_t len);
|
||||
|
||||
template<typename T>
|
||||
T* allocate()
|
||||
{
|
||||
return (T *)allocate(sizeof(T));
|
||||
}
|
||||
|
||||
private:
|
||||
void allocate_page();
|
||||
|
||||
enum
|
||||
{
|
||||
Pagesize = 4096
|
||||
};
|
||||
|
||||
size_t m_used = 0;
|
||||
std::vector<void *> m_pages;
|
||||
memory_protection m_protection;
|
||||
|
||||
friend class CJit;
|
||||
};
|
||||
|
||||
bool is_yes(const char* str);
|
||||
bool is_no(const char* str);
|
||||
|
||||
const char* LOCALINFO(char* key);
|
||||
|
||||
template <size_t N>
|
||||
char *strlcpy(char (&dest)[N], const char *src) {
|
||||
Q_strncpy(dest, src, N - 1);
|
||||
dest[N - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
inline char *strnlcpy(char *dest, const char *src, size_t n) {
|
||||
Q_strncpy(dest, src, n - 1);
|
||||
dest[n - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
size_t strlcat(char (&dest)[N], const char *src)
|
||||
{
|
||||
size_t dstlen = Q_strlen(dest);
|
||||
size_t size = N - dstlen + 1;
|
||||
|
||||
if (!size) {
|
||||
return dstlen;
|
||||
}
|
||||
|
||||
size_t srclen = Q_strlen(src);
|
||||
if (srclen > size) {
|
||||
srclen = size;
|
||||
}
|
||||
|
||||
Q_memcpy(dest + dstlen, src, srclen);
|
||||
dest[dstlen + srclen] = '\0';
|
||||
|
||||
return dstlen + srclen;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
char *mm_strtok_r(char *s, const char *delim, char **ptrptr);
|
||||
char *realpath(const char *file_name, char *resolved_name);
|
||||
@ -108,9 +31,6 @@ void normalize_path(char *path);
|
||||
bool is_abs_path(const char *path);
|
||||
bool is_valid_path(const char *path);
|
||||
bool is_platform_postfix(const char *pf);
|
||||
|
||||
void __declspec(noreturn) do_exit(int exitval);
|
||||
|
||||
bool is_file_exists_in_gamedir(const char *path);
|
||||
char *full_gamedir_path(const char *path, char *fullpath);
|
||||
bool mem_compare(const char* addr, const char* pattern, size_t len);
|
||||
|
Loading…
x
Reference in New Issue
Block a user