2
0
mirror of https://github.com/rehlds/metamod-r.git synced 2024-12-28 15:45:37 +03:00
metamod-r/metamod/dllapi.cpp
2016-07-04 12:07:29 +06:00

514 lines
22 KiB
C++

// vi: set ts=4 sw=4 :
// vim: set tw=75 :
// dllapi.cpp - implementation of Half-Life DLL routines
/*
* Copyright (c) 2001-2006 Will Day <willday@hpgx.net>
*
* This file is part of Metamod.
*
* Metamod 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.
*
* Metamod 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 Metamod; 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.
*
*/
#include <stddef.h> // offsetof
#include <extdll.h> // always
#include "dllapi.h" // me
#include "metamod.h" // SETUP_API_CALLS, etc
#include "api_info.h" // dllapi_info, etc
#include "commands_meta.h" // client_meta, etc
#include "log_meta.h" // META_ERROR, etc
#include "api_hook.h"
// Original DLL routines, functions returning "void".
#define META_DLLAPI_HANDLE_void(FN_TYPE, pfnName, pack_args_type, pfn_args) \
API_START_TSC_TRACKING(); \
API_PACK_ARGS(pack_args_type, pfn_args); \
main_hook_function_void(offsetof(dllapi_info_t, pfnName), e_api_dllapi, offsetof(DLL_FUNCTIONS, pfnName), &packed_args); \
API_END_TSC_TRACKING()
// Original DLL routines, functions returning an actual value.
#define META_DLLAPI_HANDLE(ret_t, ret_init, FN_TYPE, pfnName, pack_args_type, pfn_args) \
API_START_TSC_TRACKING(); \
API_PACK_ARGS(pack_args_type, pfn_args); \
class_ret_t ret_val(main_hook_function(class_ret_t((ret_t)ret_init), offsetof(dllapi_info_t, pfnName), e_api_dllapi, offsetof(DLL_FUNCTIONS, pfnName), &packed_args)); \
API_END_TSC_TRACKING()
// The "new" api routines (just 3 right now), functions returning "void".
#define META_NEWAPI_HANDLE_void(FN_TYPE, pfnName, pack_args_type, pfn_args) \
API_START_TSC_TRACKING(); \
API_PACK_ARGS(pack_args_type, pfn_args); \
main_hook_function_void(offsetof(newapi_info_t, pfnName), e_api_newapi, offsetof(NEW_DLL_FUNCTIONS, pfnName), &packed_args); \
API_END_TSC_TRACKING()
// The "new" api routines (just 3 right now), functions returning an actual value.
#define META_NEWAPI_HANDLE(ret_t, ret_init, FN_TYPE, pfnName, pack_args_type, pfn_args) \
API_START_TSC_TRACKING(); \
API_PACK_ARGS(pack_args_type, pfn_args); \
class_ret_t ret_val(main_hook_function(class_ret_t((ret_t)ret_init), offsetof(newapi_info_t, pfnName), e_api_newapi, offsetof(NEW_DLL_FUNCTIONS, pfnName), &packed_args)); \
API_END_TSC_TRACKING()
// From SDK dlls/game.cpp:
static void mm_GameDLLInit(void) {
META_DLLAPI_HANDLE_void(FN_GAMEINIT, pfnGameInit, void, (VOID_ARG));
RETURN_API_void();
}
// From SDK dlls/cbase.cpp:
static int mm_DispatchSpawn(edict_t *pent) {
// 0==Success, -1==Failure ?
META_DLLAPI_HANDLE(int, 0, FN_DISPATCHSPAWN, pfnSpawn, p, (pent));
RETURN_API(int);
}
static void mm_DispatchThink(edict_t *pent) {
META_DLLAPI_HANDLE_void(FN_DISPATCHTHINK, pfnThink, p, (pent));
RETURN_API_void();
}
static void mm_DispatchUse(edict_t *pentUsed, edict_t *pentOther) {
META_DLLAPI_HANDLE_void(FN_DISPATCHUSE, pfnUse, 2p, (pentUsed, pentOther));
RETURN_API_void();
}
static void mm_DispatchTouch(edict_t *pentTouched, edict_t *pentOther) {
META_DLLAPI_HANDLE_void(FN_DISPATCHTOUCH, pfnTouch, 2p, (pentTouched, pentOther));
RETURN_API_void();
}
static void mm_DispatchBlocked(edict_t *pentBlocked, edict_t *pentOther) {
META_DLLAPI_HANDLE_void(FN_DISPATCHBLOCKED, pfnBlocked, 2p, (pentBlocked, pentOther));
RETURN_API_void();
}
static void mm_DispatchKeyValue(edict_t *pentKeyvalue, KeyValueData *pkvd) {
META_DLLAPI_HANDLE_void(FN_DISPATCHKEYVALUE, pfnKeyValue, 2p, (pentKeyvalue, pkvd));
RETURN_API_void();
}
static void mm_DispatchSave(edict_t *pent, SAVERESTOREDATA *pSaveData) {
META_DLLAPI_HANDLE_void(FN_DISPATCHSAVE, pfnSave, 2p, (pent, pSaveData));
RETURN_API_void();
}
static int mm_DispatchRestore(edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity) {
// 0==Success, -1==Failure ?
META_DLLAPI_HANDLE(int, 0, FN_DISPATCHRESTORE, pfnRestore, 2pi, (pent, pSaveData, globalEntity));
RETURN_API(int);
}
static void mm_DispatchObjectCollsionBox(edict_t *pent) {
META_DLLAPI_HANDLE_void(FN_DISPATCHOBJECTCOLLISIONBOX, pfnSetAbsBox, p, (pent));
RETURN_API_void();
}
static void mm_SaveWriteFields(SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount) {
META_DLLAPI_HANDLE_void(FN_SAVEWRITEFIELDS, pfnSaveWriteFields, 4pi, (pSaveData, pname, pBaseData, pFields, fieldCount));
RETURN_API_void();
}
static void mm_SaveReadFields(SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount) {
META_DLLAPI_HANDLE_void(FN_SAVEREADFIELDS, pfnSaveReadFields, 4pi, (pSaveData, pname, pBaseData, pFields, fieldCount));
RETURN_API_void();
}
// From SDK dlls/world.cpp:
static void mm_SaveGlobalState(SAVERESTOREDATA *pSaveData) {
META_DLLAPI_HANDLE_void(FN_SAVEGLOBALSTATE, pfnSaveGlobalState, p, (pSaveData));
RETURN_API_void();
}
static void mm_RestoreGlobalState(SAVERESTOREDATA *pSaveData) {
META_DLLAPI_HANDLE_void(FN_RESTOREGLOBALSTATE, pfnRestoreGlobalState, p, (pSaveData));
RETURN_API_void();
}
static void mm_ResetGlobalState(void) {
META_DLLAPI_HANDLE_void(FN_RESETGLOBALSTATE, pfnResetGlobalState, void, (VOID_ARG));
RETURN_API_void();
}
// From SDK dlls/client.cpp:
static qboolean mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) {
g_Players.clear_player_cvar_query(pEntity);
META_DLLAPI_HANDLE(qboolean, TRUE, FN_CLIENTCONNECT, pfnClientConnect, 4p, (pEntity, pszName, pszAddress, szRejectReason));
RETURN_API(qboolean);
}
static void mm_ClientDisconnect(edict_t *pEntity) {
g_Players.clear_player_cvar_query(pEntity);
META_DLLAPI_HANDLE_void(FN_CLIENTDISCONNECT, pfnClientDisconnect, p, (pEntity));
RETURN_API_void();
}
static void mm_ClientKill(edict_t *pEntity) {
META_DLLAPI_HANDLE_void(FN_CLIENTKILL, pfnClientKill, p, (pEntity));
RETURN_API_void();
}
static void mm_ClientPutInServer(edict_t *pEntity) {
META_DLLAPI_HANDLE_void(FN_CLIENTPUTINSERVER, pfnClientPutInServer, p, (pEntity));
RETURN_API_void();
}
static void mm_ClientCommand(edict_t *pEntity) {
if(Config->clientmeta && strmatch(CMD_ARGV(0), "meta")) {
client_meta(pEntity);
}
META_DLLAPI_HANDLE_void(FN_CLIENTCOMMAND, pfnClientCommand, p, (pEntity));
RETURN_API_void();
}
static void mm_ClientUserInfoChanged(edict_t *pEntity, char *infobuffer) {
META_DLLAPI_HANDLE_void(FN_CLIENTUSERINFOCHANGED, pfnClientUserInfoChanged, 2p, (pEntity, infobuffer));
RETURN_API_void();
}
static void mm_ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) {
META_DLLAPI_HANDLE_void(FN_SERVERACTIVATE, pfnServerActivate, p2i, (pEdictList, edictCount, clientMax));
RETURN_API_void();
}
static void mm_ServerDeactivate(void) {
META_DLLAPI_HANDLE_void(FN_SERVERDEACTIVATE, pfnServerDeactivate, void, (VOID_ARG));
// Update loaded plugins. Look for new plugins in inifile, as well as
// any plugins waiting for a changelevel to load.
//
// This is done in ServerDeactivate rather than Activate, as the latter
// isn't actually the first routine to be called on a new map. In
// particular DispatchKeyValue and DispatchSpawn are called before
// Activate, and we want any newly loaded plugins to be able to catch
// these.
//
// So, we do this from Deactivate, which is the _last_ routine called
// from the previous map. It's also called right before shutdown,
// which means whenever hlds quits, it'll reload the plugins just
// before it exits, which is rather silly, but oh well.
Plugins->refresh(PT_CHANGELEVEL);
Plugins->unpause_all();
// Plugins->retry_all(PT_CHANGELEVEL);
g_Players.clear_all_cvar_queries();
requestid_counter = 0;
RETURN_API_void();
}
static void mm_PlayerPreThink(edict_t *pEntity) {
META_DLLAPI_HANDLE_void(FN_PLAYERPRETHINK, pfnPlayerPreThink, p, (pEntity));
RETURN_API_void();
}
static void mm_PlayerPostThink(edict_t *pEntity) {
META_DLLAPI_HANDLE_void(FN_PLAYERPOSTTHINK, pfnPlayerPostThink, p, (pEntity));
RETURN_API_void();
}
static void mm_StartFrame(void) {
meta_debug_value = (int)meta_debug.value;
META_DLLAPI_HANDLE_void(FN_STARTFRAME, pfnStartFrame, void, (VOID_ARG));
RETURN_API_void();
}
static void mm_ParmsNewLevel(void) {
META_DLLAPI_HANDLE_void(FN_PARMSNEWLEVEL, pfnParmsNewLevel, void, (VOID_ARG));
RETURN_API_void();
}
static void mm_ParmsChangeLevel(void) {
META_DLLAPI_HANDLE_void(FN_PARMSCHANGELEVEL, pfnParmsChangeLevel, void, (VOID_ARG));
RETURN_API_void();
}
static const char *mm_GetGameDescription(void) {
META_DLLAPI_HANDLE(const char *, NULL, FN_GETGAMEDESCRIPTION, pfnGetGameDescription, void, (VOID_ARG));
RETURN_API(const char *);
}
static void mm_PlayerCustomization(edict_t *pEntity, customization_t *pCust) {
META_DLLAPI_HANDLE_void(FN_PLAYERCUSTOMIZATION, pfnPlayerCustomization, 2p, (pEntity, pCust));
RETURN_API_void();
}
static void mm_SpectatorConnect(edict_t *pEntity) {
META_DLLAPI_HANDLE_void(FN_SPECTATORCONNECT, pfnSpectatorConnect, p, (pEntity));
RETURN_API_void();
}
static void mm_SpectatorDisconnect(edict_t *pEntity) {
META_DLLAPI_HANDLE_void(FN_SPECTATORDISCONNECT, pfnSpectatorDisconnect, p, (pEntity));
RETURN_API_void();
}
static void mm_SpectatorThink(edict_t *pEntity) {
META_DLLAPI_HANDLE_void(FN_SPECTATORTHINK, pfnSpectatorThink, p, (pEntity));
RETURN_API_void();
}
static void mm_Sys_Error(const char *error_string) {
META_DLLAPI_HANDLE_void(FN_SYS_ERROR, pfnSys_Error, p, (error_string));
RETURN_API_void();
}
// From SDK pm_shared/pm_shared.c:
static void mm_PM_Move (struct playermove_s *ppmove, int server) {
META_DLLAPI_HANDLE_void(FN_PM_MOVE, pfnPM_Move, pi, (ppmove, server));
RETURN_API_void();
}
static void mm_PM_Init(struct playermove_s *ppmove) {
META_DLLAPI_HANDLE_void(FN_PM_INIT, pfnPM_Init, p, (ppmove));
RETURN_API_void();
}
static char mm_PM_FindTextureType(char *name) {
META_DLLAPI_HANDLE(char, '\0', FN_PM_FINDTEXTURETYPE, pfnPM_FindTextureType, p, (name));
RETURN_API(char);
}
// From SDK dlls/client.cpp:
static void mm_SetupVisibility(edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas) {
META_DLLAPI_HANDLE_void(FN_SETUPVISIBILITY, pfnSetupVisibility, 4p, (pViewEntity, pClient, pvs, pas));
RETURN_API_void();
}
static void mm_UpdateClientData (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd) {
META_DLLAPI_HANDLE_void(FN_UPDATECLIENTDATA, pfnUpdateClientData, pip, (ent, sendweapons, cd));
RETURN_API_void();
}
static int mm_AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet) {
META_DLLAPI_HANDLE(int, 0, FN_ADDTOFULLPACK, pfnAddToFullPack, pi2p2ip, (state, e, ent, host, hostflags, player, pSet));
RETURN_API(int);
}
static void mm_CreateBaseline(int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs) {
META_DLLAPI_HANDLE_void(FN_CREATEBASELINE, pfnCreateBaseline, 2i2pi2p, (player, eindex, baseline, entity, playermodelindex, (float*)player_mins, (float*)player_maxs));
RETURN_API_void();
}
static void mm_RegisterEncoders(void) {
META_DLLAPI_HANDLE_void(FN_REGISTERENCODERS, pfnRegisterEncoders, void, (VOID_ARG));
RETURN_API_void();
}
static int mm_GetWeaponData(struct edict_s *player, struct weapon_data_s *info) {
META_DLLAPI_HANDLE(int, 0, FN_GETWEAPONDATA, pfnGetWeaponData, 2p, (player, info));
RETURN_API(int);
}
static void mm_CmdStart(const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed) {
META_DLLAPI_HANDLE_void(FN_CMDSTART, pfnCmdStart, 2pui, (player, cmd, random_seed));
RETURN_API_void();
}
static void mm_CmdEnd (const edict_t *player) {
META_DLLAPI_HANDLE_void(FN_CMDEND, pfnCmdEnd, p, (player));
RETURN_API_void();
}
static int mm_ConnectionlessPacket(const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size) {
META_DLLAPI_HANDLE(int, 0, FN_CONNECTIONLESSPACKET, pfnConnectionlessPacket, 4p, (net_from, args, response_buffer, response_buffer_size));
RETURN_API(int);
}
static int mm_GetHullBounds(int hullnumber, float *mins, float *maxs) {
META_DLLAPI_HANDLE(int, 0, FN_GETHULLBOUNDS, pfnGetHullBounds, i2p, (hullnumber, mins, maxs));
RETURN_API(int);
}
static void mm_CreateInstancedBaselines (void) {
META_DLLAPI_HANDLE_void(FN_CREATEINSTANCEDBASELINES, pfnCreateInstancedBaselines, void, (VOID_ARG));
RETURN_API_void();
}
static int mm_InconsistentFile(const edict_t *player, const char *filename, char *disconnect_message) {
META_DLLAPI_HANDLE(int, 0, FN_INCONSISTENTFILE, pfnInconsistentFile, 3p, (player, filename, disconnect_message));
RETURN_API(int);
}
static int mm_AllowLagCompensation(void) {
META_DLLAPI_HANDLE(int, 0, FN_ALLOWLAGCOMPENSATION, pfnAllowLagCompensation, void, (VOID_ARG));
RETURN_API(int);
}
// New API functions
// From SDK ?
static void mm_OnFreeEntPrivateData(edict_t *pEnt) {
META_NEWAPI_HANDLE_void(FN_ONFREEENTPRIVATEDATA, pfnOnFreeEntPrivateData, p, (pEnt));
RETURN_API_void();
}
static void mm_GameShutdown(void) {
META_NEWAPI_HANDLE_void(FN_GAMESHUTDOWN, pfnGameShutdown, void, (VOID_ARG));
RETURN_API_void();
}
static int mm_ShouldCollide(edict_t *pentTouched, edict_t *pentOther) {
META_NEWAPI_HANDLE(int, 1, FN_SHOULDCOLLIDE, pfnShouldCollide, 2p, (pentTouched, pentOther));
RETURN_API(int);
}
// Added 2005/08/11 (no SDK update):
static void mm_CvarValue(const edict_t *pEnt, const char *value) {
g_Players.clear_player_cvar_query(pEnt);
META_NEWAPI_HANDLE_void(FN_CVARVALUE, pfnCvarValue, 2p, (pEnt, value));
RETURN_API_void();
}
// Added 2005/11/21 (no SDK update):
static void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, const char *value) {
META_NEWAPI_HANDLE_void(FN_CVARVALUE2, pfnCvarValue2, pi2p, (pEnt, requestID, cvarName, value));
RETURN_API_void();
}
// From SDK dlls/cbase.cpp:
// "(wd)" indicates my comments on the functions
static DLL_FUNCTIONS gFunctionTable =
{
mm_GameDLLInit, //! pfnGameInit() Initialize the game (one-time call after loading of game .dll)
mm_DispatchSpawn, //! pfnSpawn()
mm_DispatchThink, //! pfnThink()
mm_DispatchUse, //! pfnUse()
mm_DispatchTouch, //! pfnTouch()
mm_DispatchBlocked, //! pfnBlocked()
mm_DispatchKeyValue, //! pfnKeyValue()
mm_DispatchSave, //! pfnSave()
mm_DispatchRestore, //! pfnRestore()
mm_DispatchObjectCollsionBox, //! pfnSetAbsBox()
mm_SaveWriteFields, //! pfnSaveWriteFields()
mm_SaveReadFields, //! pfnSaveReadFields()
mm_SaveGlobalState, //! pfnSaveGlobalState()
mm_RestoreGlobalState, //! pfnRestoreGlobalState()
mm_ResetGlobalState, //! pfnResetGlobalState()
mm_ClientConnect, //! pfnClientConnect() (wd) Client has connected
mm_ClientDisconnect, //! pfnClientDisconnect() (wd) Player has left the game
mm_ClientKill, //! pfnClientKill() (wd) Player has typed "kill"
mm_ClientPutInServer, //! pfnClientPutInServer() (wd) Client is entering the game
mm_ClientCommand, //! pfnClientCommand() (wd) Player has sent a command (typed, or from a bind)
mm_ClientUserInfoChanged, //! pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure
mm_ServerActivate, //! pfnServerActivate() (wd) Server is starting a new map
mm_ServerDeactivate, //! pfnServerDeactivate() (wd) Server is leaving the map (shutdown, or changelevel); SDK2
mm_PlayerPreThink, //! pfnPlayerPreThink()
mm_PlayerPostThink, //! pfnPlayerPostThink()
mm_StartFrame, //! pfnStartFrame()
mm_ParmsNewLevel, //! pfnParmsNewLevel()
mm_ParmsChangeLevel, //! pfnParmsChangeLevel()
mm_GetGameDescription, //! pfnGetGameDescription() Returns string describing current .dll. E.g. "TeamFotrress 2", "Half-Life"
mm_PlayerCustomization, //! pfnPlayerCustomization() Notifies .dll of new customization for player.
mm_SpectatorConnect, //! pfnSpectatorConnect() Called when spectator joins server
mm_SpectatorDisconnect, //! pfnSpectatorDisconnect() Called when spectator leaves the server
mm_SpectatorThink, //! pfnSpectatorThink() Called when spectator sends a command packet (usercmd_t)
mm_Sys_Error, //! pfnSys_Error() Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. SDK2
mm_PM_Move, //! pfnPM_Move() (wd) SDK2
mm_PM_Init, //! pfnPM_Init() Server version of player movement initialization; (wd) SDK2
mm_PM_FindTextureType, //! pfnPM_FindTextureType() (wd) SDK2
mm_SetupVisibility, //! pfnSetupVisibility() Set up PVS and PAS for networking for this client; (wd) SDK2
mm_UpdateClientData, //! pfnUpdateClientData() Set up data sent only to specific client; (wd) SDK2
mm_AddToFullPack, //! pfnAddToFullPack() (wd) SDK2
mm_CreateBaseline, //! pfnCreateBaseline() Tweak entity baseline for network encoding, allows setup of player baselines, too.; (wd) SDK2
mm_RegisterEncoders, //! pfnRegisterEncoders() Callbacks for network encoding; (wd) SDK2
mm_GetWeaponData, //! pfnGetWeaponData() (wd) SDK2
mm_CmdStart, //! pfnCmdStart() (wd) SDK2
mm_CmdEnd, //! pfnCmdEnd() (wd) SDK2
mm_ConnectionlessPacket, //! pfnConnectionlessPacket() (wd) SDK2
mm_GetHullBounds, //! pfnGetHullBounds() (wd) SDK2
mm_CreateInstancedBaselines, //! pfnCreateInstancedBaselines() (wd) SDK2
mm_InconsistentFile, //! pfnInconsistentFile() (wd) SDK2
mm_AllowLagCompensation, //! pfnAllowLagCompensation() (wd) SDK2
};
DLL_FUNCTIONS *g_pHookedDllFunctions = &gFunctionTable;
// It's not clear what the difference is between GetAPI and GetAPI2; they
// both appear to return the exact same function table.
//
// Only one of them appears to be ever called, though. If the DLL provides
// GetAPI2, the engine/hlds will call that, and will not call GetAPI. If
// the engine couldn't find GetAPI2 in the DLL, it appears to fall back to
// GetAPI.
//
// So, GetAPI2 appears to replace GetAPI, and appears to have been added
// with SDK 2.0. My best guess is that, with the new SDK, interface
// version checking became important, and without the int ptr used in
// GetAPI2, the engine can't find out the version of the DLL via GetAPI.
//
// It's unclear whether a DLL coded under SDK2 needs to provide the older
// GetAPI or not..
C_DLLEXPORT int GetEntityAPI(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion)
{
META_DEBUG(3, ("called: GetEntityAPI; version=%d", interfaceVersion));
if(!pFunctionTable || metamod_not_loaded) {
META_WARNING("GetEntityAPI called with null pFunctionTable");
return(FALSE);
}
else if(interfaceVersion != INTERFACE_VERSION) {
META_WARNING("GetEntityAPI version mismatch; requested=%d ours=%d", interfaceVersion, INTERFACE_VERSION);
return(FALSE);
}
memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS));
return(TRUE);
}
C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion)
{
META_DEBUG(3, ("called: GetEntityAPI2; version=%d", *interfaceVersion));
if(!pFunctionTable || metamod_not_loaded) {
META_WARNING("GetEntityAPI2 called with null pFunctionTable");
return(FALSE);
}
else if(*interfaceVersion != INTERFACE_VERSION) {
META_WARNING("GetEntityAPI2 version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION);
//! Tell engine what version we had, so it can figure out who is out of date.
*interfaceVersion = INTERFACE_VERSION;
return(FALSE);
}
memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS));
return(TRUE);
}
// I could find _no_ documentation or examples for the intended use of
// NEW_DLL_FUNCTIONS. I wouldn't have even _known_ about the
// GetNewDLLFunctions() function except for the reference in Adminmod.. It
// appears to be new with SDK 2.0.
//
// Obviously, it seems to provide additional functions to the engine, but
// it's unclear why a new table and interface were added, rather than
// appending new functions to the GetAPI table/interface.
//
// Interestingly, it appears to be called by the engine _before_ GetAPI.
static meta_new_dll_functions_t sNewFunctionTable(
&mm_OnFreeEntPrivateData, //! pfnOnFreeEntPrivateData() Called right before the object's memory is freed. Calls its destructor.
&mm_GameShutdown, //! pfnGameShutdown()
&mm_ShouldCollide, //! pfnShouldCollide()
// Added 2005/08/11 (no SDK update):
&mm_CvarValue, //! pfnCvarValue()
// Added 2005/11/21 (no SDK update):
&mm_CvarValue2 //! pfnCvarValue2()
);
NEW_DLL_FUNCTIONS *g_pHookedNewDllFunctions = &sNewFunctionTable;
C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion)
{
META_DEBUG(6, ("called: GetNewDLLFunctions; version=%d", *interfaceVersion));
#if 0 // ~dvander - but then you can't use cvar querying on many mods...
// Don't provide these functions to engine if gamedll doesn't provide
// them. Otherwise, we're in the position of having to provide answers
// we can't necessarily provide (for instance, ShouldCollide())...
if(!GameDLL.funcs.newapi_table)
return(FALSE);
#endif
if(!pNewFunctionTable) {
META_ERROR("GetNewDLLFunctions called with null pNewFunctionTable");
return(FALSE);
}
else if(*interfaceVersion != NEW_DLL_FUNCTIONS_VERSION) {
META_ERROR("GetNewDLLFunctions version mismatch; requested=%d ours=%d", *interfaceVersion, NEW_DLL_FUNCTIONS_VERSION);
//! Tell engine what version we had, so it can figure out who is out of date.
*interfaceVersion = NEW_DLL_FUNCTIONS_VERSION;
return(FALSE);
}
sNewFunctionTable.copy_to(pNewFunctionTable);
return(TRUE);
}