XAD
01-20-2005, 11:46
vancelorgin asked me for my version so thought I posted it here (this is more C than C++ :wink: )...
This line will hook all calls to the engine->LogPrint function and call the local MetaLogPrint function instead.
SET_ENGINEFUNC(LogPrint,MetaLogPrint);
/X
------
These are my macros and a code example to hook "engine->LogPrint()" (taken from my code)...
#define VNAME MyPlugin
#define ENGINEFUNC(func) ( (int)( (void**)&g_pOrigEngine.func - (void**)&g_pOrigEngine ) )
#define ENGINEFUNCSIZE ( sizeof(ivengineserver_t) )
#define SET_ENGINEFUNC(func,myfunc) ( (*(void***)engine)[ENGINEFUNC(func)] = (void*)&myfunc )
static ivengineserver_t g_pOrigEngine;
static void MetaLogPrint( void *pVTable, const char *msg );
// Initialize engine hook support
static void InitHookEngine()
{
static bool g_bHookEngineInd = false;
Msg( "[%s] Initialized Engine hooks\n", VNAME );
// Bail out if alread initialized
if( g_bHookEngineInd )
return;
// Block another initialization call
g_bHookEngineInd = true;
// Unprotect the virtual table and copy it to the local struct
UTIL_VClassUnprotect( (void*)engine, ENGINEFUNCSIZE );
memcpy( (void*)&g_pOrigEngine, *(void**)engine, ENGINEFUNCSIZE );
// Test hook !! REPEAT FOR EACH HOOK !!
SET_ENGINEFUNC(LogPrint,MetaLogPrint);
// Protect the virtual table again
UTIL_VClassProtect( (void*)engine, ENGINEFUNCSIZE );
}
// Print the log data to the console
static void MetaLogPrint( void *pVTable, const char *msg )
{
Msg( "[%s] DEBUG: LogPrint (%08Xh): %s", VNAME, pVTable, msg );
g_pOrigEngine.LogPrint( pVTable, msg );
}
This is the struct needed, which is a minor modified version of the eiface IVEngineServer class...
#ifndef INTERFACE_HOOK_H
#define INTERFACE_HOOK_H
#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>
#include "enginecallback.h"
//-----------------------------------------------------------------------------
// Purpose: Support engine hook
//-----------------------------------------------------------------------------
typedef struct ivengineserver_s
{
// Tell engine to change level ( "changelevel s1\n" or "changelevel2 s1 s2\n" )
void (*ChangeLevel)( void *pVTable, const char *s1, const char *s2 );
// Ask engine whether the specified map is a valid map file (exists and has valid version number).
int (*IsMapValid)( void *pVTable, const char *filename );
// Is this a dedicated server?
bool (*IsDedicatedServer)( void *pVTable );
// Is in Hammer editing mode?
int (*IsInEditMode)( void *pVTable );
// Add to the server/client lookup/precache table, the specified string is given a unique index
// NOTE: The indices for PrecacheModel are 1 based
// a 0 returned from those methods indicates the model or sound was not correctly precached
// However, generic and decal are 0 based
// If preload is specified, the file is loaded into the server/client's cache memory before level startup, otherwise
// it'll only load when actually used (which can cause a disk i/o hitch if it occurs during play of a level).
int (*PrecacheModel)( void *pVTable, const char *s, bool preload /* = false */ );
int (*PrecacheSentenceFile)( void *pVTable, const char *s, bool preload /* = false */ );
int (*PrecacheDecal)( void *pVTable, const char *name, bool preload /* = false */ );
int (*PrecacheGeneric)( void *pVTable, const char *s, bool preload /* = false */ );
// Check's if the name is precached, but doesn't actually precache the name if not...
bool (*IsModelPrecached)( void *pVTable, char const *s ) /* const */;
bool (*IsDecalPrecached)( void *pVTable, char const *s ) /* const */;
bool (*IsGenericPrecached)( void *pVTable, char const *s ) /* const */;
// Note that sounds are precached using the IEngineSound interface
// Special purpose PVS checking
// Get the cluster # for the specified position
int (*GetClusterForOrigin)( void *pVTable, const Vector &org );
// Get the PVS bits for a specified cluster and copy the bits into outputpvs. Returns the number of bytes needed to pack the PVS
int (*GetPVSForCluster)( void *pVTable, int cluster, int outputpvslength, unsigned char *outputpvs );
// Check whether the specified origin is inside the specified PVS
bool (*CheckOriginInPVS)( void *pVTable, const Vector &org, const unsigned char *checkpvs, int checkpvssize );
// Check whether the specified worldspace bounding box is inside the specified PVS
bool (*CheckBoxInPVS)( void *pVTable, const Vector &mins, const Vector &maxs, const unsigned char *checkpvs, int checkpvssize );
// Returns the server assigned userid for this player. Useful for logging frags, etc.
// returns -1 if the edict couldn't be found in the list of players.
int (*GetPlayerUserId)( void *pVTable, const edict_t *e );
const char *(*GetPlayerNetworkIDString)( void *pVTable, const edict_t *e );
// Return the current number of used edict slots
int (*GetEntityCount)( void *pVTable );
// Given an edict, returns the entity index
int (*IndexOfEdict)( void *pVTable, const edict_t *pEdict );
// Given and entity index, returns the corresponding edict pointer
edict_t *(*PEntityOfEntIndex)( void *pVTable, int iEntIndex );
// Get stats info interface for a client netchannel
INetChannelInfo* (*GetPlayerNetInfo)( void *pVTable, int playerIndex );
// Allocate space for string and return index/offset of string in global string list
// If iForceEdictIndex is not -1, then it will return the edict with that index. If that edict index
// is already used, it'll return null.
edict_t *(*CreateEdict)( void *pVTable, int iForceEdictIndex /* = -1 */ );
// Remove the specified edict and place back into the free edict list
void (*RemoveEdict)( void *pVTable, edict_t *e );
// Memory allocation for entity class data
void *(*PvAllocEntPrivateData)( void *pVTable, long cb );
void (*FreeEntPrivateData)( void *pVTable, void *pEntity );
// Save/restore uses a special memory allocator (which zeroes newly allocated memory, etc.)
void *(*SaveAllocMemory)( void *pVTable, size_t num, size_t size );
void (*SaveFreeMemory)( void *pVTable, void *pSaveMem );
// Emit an ambient sound associated with the specified entity
void (*EmitAmbientSound)( void *pVTable, int entindex, const Vector &pos, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float delay /* = 0.0f */ );
// Fade out the client's volume level toward silence (or fadePercent)
void (*FadeClientVolume)( void *pVTable, const edict_t *pEdict, float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds );
// Sentences / sentence groups
int (*SentenceGroupPick)( void *pVTable, int groupIndex, char *name, int nameBufLen );
int (*SentenceGroupPickSequential)( void *pVTable, int groupIndex, char *name, int nameBufLen, int sentenceIndex, int reset );
int (*SentenceIndexFromName)( void *pVTable, const char *pSentenceName );
const char *(*SentenceNameFromIndex)( void *pVTable, int sentenceIndex );
int (*SentenceGroupIndexFromName)( void *pVTable, const char *pGroupName );
const char *(*SentenceGroupNameFromIndex)( void *pVTable, int groupIndex );
float (*SentenceLength)( void *pVTable, int sentenceIndex );
// Issue a command to the command parser as if it was typed at the server console.
void (*ServerCommand)( void *pVTable, const char *str );
// Execute any commands currently in the command parser immediately (instead of once per frame)
void (*ServerExecute)( void *pVTable );
// Issue the specified command to the specified client (mimics that client typing the command at the console).
void (*ClientCommand)( void *pVTable, edict_t *pEdict, const char *szFmt, ... );
// Set the lightstyle to the specified value and network the change to any connected clients. Note that val must not
// change place in memory (use MAKE_STRING) for anything that's not compiled into your mod.
void (*LightStyle)( void *pVTable, int style, const char *val );
// Project a static decal onto the specified entity / model (for level placed decals in the .bsp)
void (*StaticDecal)( void *pVTable, const Vector &originInEntitySpace, int decalIndex, int entityIndex, int modelIndex, bool lowpriority );
// Given the current PVS(or PAS) and origin, determine which players should hear/receive the message
void (*Message_DetermineMulticastRecipients)( void *pVTable, bool usepas, const Vector& origin, CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits );
// Begin a message from a server side entity to its client side counterpart (func_breakable glass, e.g.)
bf_write *(*EntityMessageBegin)( void *pVTable, int ent_index, ServerClass * ent_class, bool reliable );
// Begin a usermessage from the server to the client .dll
bf_write *(*UserMessageBegin)( void *pVTable, IRecipientFilter *filter, int msg_type );
// Finish the Entity or UserMessage and dispatch to network layer
void (*MessageEnd)( void *pVTable );
// Print szMsg to the client console.
void (*ClientPrintf)( void *pVTable, edict_t *pEdict, const char *szMsg );
// SINGLE PLAYER/LISTEN SERVER ONLY (just matching the client .dll api for this)
// Prints the formatted string to the notification area of the screen ( down the right hand edge
// numbered lines starting at position 0
void (*Con_NPrintf)( void *pVTable, int pos, const char *fmt, ... );
// SINGLE PLAYER/LISTEN SERVER ONLY(just matching the client .dll api for this)
// Similar to Con_NPrintf, but allows specifying custom text color and duration information
void (*Con_NXPrintf)( void *pVTable, const struct con_nprint_s *info, const char *fmt, ... );
// For ConCommand parsing or parsing client commands issued by players typing at their console
// Retrieves the raw command string (untokenized)
const char *(*Cmd_Args)( void *pVTable );
// Returns the number of tokens in the command string
int (*Cmd_Argc)( void *pVTable );
// Retrieves a specified token
char *(*Cmd_Argv)( void *pVTable, int argc );
// Change a specified player's "view entity" (i.e., use the view entity position/orientation for rendering the client view)
void (*SetView)( void *pVTable, const edict_t *pClient, const edict_t *pViewent );
// Get a high precision timer for doing profiling work
float (*Time)( void *pVTable );
// Set the player's crosshair angle
void (*CrosshairAngle)( void *pVTable, const edict_t *pClient, float pitch, float yaw );
// Get the current game directory (hl2, tf2, hl1, cstrike, etc.)
void (*GetGameDir)( void *pVTable, char *szGetGameDir, int maxlength );
// Used by AI node graph code to determine if .bsp and .ain files are out of date
int (*CompareFileTime)( void *pVTable, const char *filename1, const char *filename2, int *iCompare );
// Locks/unlocks the network string tables (.e.g, when adding bots to server, this needs to happen).
// Be sure to reset the lock after executing your code!!!
bool (*LockNetworkStringTables)( void *pVTable, bool lock );
// Create a bot with the given name. Returns NULL if fake client can't be created
edict_t *(*CreateFakeClient)( void *pVTable, const char *netname );
// Get a convar keyvalue for s specified client
const char *(*GetClientConVarValue)( void *pVTable, int clientIndex, const char *name );
// Parse a token from a file
const char *(*ParseFile)( void *pVTable, const char *data, char *token, int maxlen );
// Copies a file
bool (*CopyFile)( void *pVTable, const char *source, const char *destination );
// Reset the pvs, pvssize is the size in bytes of the buffer pointed to by pvs.
// This should be called right before any calls to AddOriginToPVS
void (*ResetPVS)( void *pVTable, byte *pvs, int pvssize );
// Merge the pvs bits into the current accumulated pvs based on the specified origin ( not that each pvs origin has an 8 world unit fudge factor )
void (*AddOriginToPVS)( void *pVTable, const Vector &origin );
// Mark a specified area portal as open/closes
void (*SetAreaPortalState)( void *pVTable, int portalNumber, int isOpen );
// Queue a temp entity for transmission
void (*PlaybackTempEntity)( void *pVTable, IRecipientFilter& filter, float delay, const void *pSender, const SendTable *pST, int classID );
// Given a node number and the specified PVS, return with the node is in the PVS
int (*CheckHeadnodeVisible)( void *pVTable, int nodenum, const byte *pvs, int vissize );
// Using area bits, cheeck whether area1 flows into area2 and vice versa (depends on area portal state)
int (*CheckAreasConnected)( void *pVTable, int area1, int area2 );
// Given an origin, determine which area index the origin is within
int (*GetArea)( void *pVTable, const Vector &origin );
// Get area portal bit set
void (*GetAreaBits)( void *pVTable, int area, unsigned char *bits, int buflen );
// Given a view origin (which tells us the area to start looking in) and a portal key,
// fill in the plane that leads out of this area (it points into whatever area it leads to).
bool (*GetAreaPortalPlane)( void *pVTable, Vector const &vViewOrigin, int portalKey, VPlane *pPlane );
// Apply a modification to the terrain.
void (*ApplyTerrainMod)( void *pVTable, TerrainModType type, CTerrainModParams const ¶ms );
// Save/restore wrapper - FIXME: At some point we should move this to it's own interface
bool (*LoadGameState)( void *pVTable, char const *pMapName, bool createPlayers );
void (*LoadAdjacentEnts)( void *pVTable, const char *pOldLevel, const char *pLandmarkName );
void (*ClearSaveDir)( void *pVTable );
// Get the pristine map entity lump string. (e.g., used by CS to reload the map entities when restarting a round.)
const char* (*GetMapEntitiesString)( void *pVTable );
// Text message system -- lookup the text message of the specified name
client_textmessage_t *(*TextMessageGet)( void *pVTable, const char *pName );
// Print a message to the server log file
void (*LogPrint)( void *pVTable, const char *msg );
// Builds PVS information for an entity
void (*BuildEntityClusterList)( void *pVTable, edict_t *pEdict, PVSInfo_t *pPVSInfo );
// A solid entity moved, update spatial partition
void (*SolidMoved)( void *pVTable, edict_t *pSolidEnt, ICollideable *pSolidCollide, const Vector* pPrevAbsOrigin );
// A trigger entity moved, update spatial partition
void (*TriggerMoved)( void *pVTable, edict_t *pTriggerEnt );
// Create/destroy a custom spatial partition
ISpatialPartition *(*CreateSpatialPartition)( void *pVTable, const Vector& worldmin, const Vector& worldmax );
void (*DestroySpatialPartition)( void *pVTable, ISpatialPartition * );
// Draw the brush geometry in the map into the scratch pad.
// Flags is currently unused.
void (*DrawMapToScratchPad)( void *pVTable, IScratchPad3D *pPad, unsigned long iFlags );
// This returns which entities, to the best of the server's knowledge, the client currently knows about.
// This is really which entities were in the snapshot that this client last acked.
// This returns a bit vector with one bit for each entity.
//
// USE WITH CARE. Whatever tick the client is really currently on is subject to timing and
// ordering differences, so you should account for about a quarter-second discrepancy in here.
// Also, this will return NULL if the client doesn't exist or if this client hasn't acked any frames yet.
//
// iClientIndex is the CLIENT index, so if you use pPlayer->entindex(), subtract 1.
const CBitVec<MAX_EDICTS>* (*GetEntityTransmitBitsForClient)( void *pVTable, int iClientIndex );
// Is the game paused?
bool (*IsPaused)( void *pVTable );
// Marks the filename for consistency checking. This should be called after precaching the file.
void (*ForceExactFile)( void *pVTable, const char *s );
void (*ForceModelBounds)( void *pVTable, const char *s, const Vector &mins, const Vector &maxs );
} ivengineserver_t;
#endif // INTERFACE_HOOK_H
The protect / unprotect functions...
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
inline void UTIL_VClassUnprotect( void *pObject, int iMLen )
{
char *p;
p = (char*)((int)(*(void**)pObject) & ~(PAGESIZE-1));
if( mprotect( p, (int)(*(char**)pObject - p) + iMLen, PROT_READ | PROT_WRITE | PROT_EXEC ) )
{
perror( "Virtual Class memory unprotect failed (using mprotect)" );
}
}
inline void UTIL_VClassProtect( void *pObject, int iMLen )
{
char *p;
p = (char*)((int)(*(void**)pObject) & ~(PAGESIZE-1));
if( mprotect( p, (int)(*(char**)pObject - p) + iMLen, PROT_READ | PROT_EXEC ) )
{
perror( "Virtual Class memory protect failed (using mprotect)" );
}
}
This line will hook all calls to the engine->LogPrint function and call the local MetaLogPrint function instead.
SET_ENGINEFUNC(LogPrint,MetaLogPrint);
/X
------
These are my macros and a code example to hook "engine->LogPrint()" (taken from my code)...
#define VNAME MyPlugin
#define ENGINEFUNC(func) ( (int)( (void**)&g_pOrigEngine.func - (void**)&g_pOrigEngine ) )
#define ENGINEFUNCSIZE ( sizeof(ivengineserver_t) )
#define SET_ENGINEFUNC(func,myfunc) ( (*(void***)engine)[ENGINEFUNC(func)] = (void*)&myfunc )
static ivengineserver_t g_pOrigEngine;
static void MetaLogPrint( void *pVTable, const char *msg );
// Initialize engine hook support
static void InitHookEngine()
{
static bool g_bHookEngineInd = false;
Msg( "[%s] Initialized Engine hooks\n", VNAME );
// Bail out if alread initialized
if( g_bHookEngineInd )
return;
// Block another initialization call
g_bHookEngineInd = true;
// Unprotect the virtual table and copy it to the local struct
UTIL_VClassUnprotect( (void*)engine, ENGINEFUNCSIZE );
memcpy( (void*)&g_pOrigEngine, *(void**)engine, ENGINEFUNCSIZE );
// Test hook !! REPEAT FOR EACH HOOK !!
SET_ENGINEFUNC(LogPrint,MetaLogPrint);
// Protect the virtual table again
UTIL_VClassProtect( (void*)engine, ENGINEFUNCSIZE );
}
// Print the log data to the console
static void MetaLogPrint( void *pVTable, const char *msg )
{
Msg( "[%s] DEBUG: LogPrint (%08Xh): %s", VNAME, pVTable, msg );
g_pOrigEngine.LogPrint( pVTable, msg );
}
This is the struct needed, which is a minor modified version of the eiface IVEngineServer class...
#ifndef INTERFACE_HOOK_H
#define INTERFACE_HOOK_H
#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>
#include "enginecallback.h"
//-----------------------------------------------------------------------------
// Purpose: Support engine hook
//-----------------------------------------------------------------------------
typedef struct ivengineserver_s
{
// Tell engine to change level ( "changelevel s1\n" or "changelevel2 s1 s2\n" )
void (*ChangeLevel)( void *pVTable, const char *s1, const char *s2 );
// Ask engine whether the specified map is a valid map file (exists and has valid version number).
int (*IsMapValid)( void *pVTable, const char *filename );
// Is this a dedicated server?
bool (*IsDedicatedServer)( void *pVTable );
// Is in Hammer editing mode?
int (*IsInEditMode)( void *pVTable );
// Add to the server/client lookup/precache table, the specified string is given a unique index
// NOTE: The indices for PrecacheModel are 1 based
// a 0 returned from those methods indicates the model or sound was not correctly precached
// However, generic and decal are 0 based
// If preload is specified, the file is loaded into the server/client's cache memory before level startup, otherwise
// it'll only load when actually used (which can cause a disk i/o hitch if it occurs during play of a level).
int (*PrecacheModel)( void *pVTable, const char *s, bool preload /* = false */ );
int (*PrecacheSentenceFile)( void *pVTable, const char *s, bool preload /* = false */ );
int (*PrecacheDecal)( void *pVTable, const char *name, bool preload /* = false */ );
int (*PrecacheGeneric)( void *pVTable, const char *s, bool preload /* = false */ );
// Check's if the name is precached, but doesn't actually precache the name if not...
bool (*IsModelPrecached)( void *pVTable, char const *s ) /* const */;
bool (*IsDecalPrecached)( void *pVTable, char const *s ) /* const */;
bool (*IsGenericPrecached)( void *pVTable, char const *s ) /* const */;
// Note that sounds are precached using the IEngineSound interface
// Special purpose PVS checking
// Get the cluster # for the specified position
int (*GetClusterForOrigin)( void *pVTable, const Vector &org );
// Get the PVS bits for a specified cluster and copy the bits into outputpvs. Returns the number of bytes needed to pack the PVS
int (*GetPVSForCluster)( void *pVTable, int cluster, int outputpvslength, unsigned char *outputpvs );
// Check whether the specified origin is inside the specified PVS
bool (*CheckOriginInPVS)( void *pVTable, const Vector &org, const unsigned char *checkpvs, int checkpvssize );
// Check whether the specified worldspace bounding box is inside the specified PVS
bool (*CheckBoxInPVS)( void *pVTable, const Vector &mins, const Vector &maxs, const unsigned char *checkpvs, int checkpvssize );
// Returns the server assigned userid for this player. Useful for logging frags, etc.
// returns -1 if the edict couldn't be found in the list of players.
int (*GetPlayerUserId)( void *pVTable, const edict_t *e );
const char *(*GetPlayerNetworkIDString)( void *pVTable, const edict_t *e );
// Return the current number of used edict slots
int (*GetEntityCount)( void *pVTable );
// Given an edict, returns the entity index
int (*IndexOfEdict)( void *pVTable, const edict_t *pEdict );
// Given and entity index, returns the corresponding edict pointer
edict_t *(*PEntityOfEntIndex)( void *pVTable, int iEntIndex );
// Get stats info interface for a client netchannel
INetChannelInfo* (*GetPlayerNetInfo)( void *pVTable, int playerIndex );
// Allocate space for string and return index/offset of string in global string list
// If iForceEdictIndex is not -1, then it will return the edict with that index. If that edict index
// is already used, it'll return null.
edict_t *(*CreateEdict)( void *pVTable, int iForceEdictIndex /* = -1 */ );
// Remove the specified edict and place back into the free edict list
void (*RemoveEdict)( void *pVTable, edict_t *e );
// Memory allocation for entity class data
void *(*PvAllocEntPrivateData)( void *pVTable, long cb );
void (*FreeEntPrivateData)( void *pVTable, void *pEntity );
// Save/restore uses a special memory allocator (which zeroes newly allocated memory, etc.)
void *(*SaveAllocMemory)( void *pVTable, size_t num, size_t size );
void (*SaveFreeMemory)( void *pVTable, void *pSaveMem );
// Emit an ambient sound associated with the specified entity
void (*EmitAmbientSound)( void *pVTable, int entindex, const Vector &pos, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float delay /* = 0.0f */ );
// Fade out the client's volume level toward silence (or fadePercent)
void (*FadeClientVolume)( void *pVTable, const edict_t *pEdict, float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds );
// Sentences / sentence groups
int (*SentenceGroupPick)( void *pVTable, int groupIndex, char *name, int nameBufLen );
int (*SentenceGroupPickSequential)( void *pVTable, int groupIndex, char *name, int nameBufLen, int sentenceIndex, int reset );
int (*SentenceIndexFromName)( void *pVTable, const char *pSentenceName );
const char *(*SentenceNameFromIndex)( void *pVTable, int sentenceIndex );
int (*SentenceGroupIndexFromName)( void *pVTable, const char *pGroupName );
const char *(*SentenceGroupNameFromIndex)( void *pVTable, int groupIndex );
float (*SentenceLength)( void *pVTable, int sentenceIndex );
// Issue a command to the command parser as if it was typed at the server console.
void (*ServerCommand)( void *pVTable, const char *str );
// Execute any commands currently in the command parser immediately (instead of once per frame)
void (*ServerExecute)( void *pVTable );
// Issue the specified command to the specified client (mimics that client typing the command at the console).
void (*ClientCommand)( void *pVTable, edict_t *pEdict, const char *szFmt, ... );
// Set the lightstyle to the specified value and network the change to any connected clients. Note that val must not
// change place in memory (use MAKE_STRING) for anything that's not compiled into your mod.
void (*LightStyle)( void *pVTable, int style, const char *val );
// Project a static decal onto the specified entity / model (for level placed decals in the .bsp)
void (*StaticDecal)( void *pVTable, const Vector &originInEntitySpace, int decalIndex, int entityIndex, int modelIndex, bool lowpriority );
// Given the current PVS(or PAS) and origin, determine which players should hear/receive the message
void (*Message_DetermineMulticastRecipients)( void *pVTable, bool usepas, const Vector& origin, CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits );
// Begin a message from a server side entity to its client side counterpart (func_breakable glass, e.g.)
bf_write *(*EntityMessageBegin)( void *pVTable, int ent_index, ServerClass * ent_class, bool reliable );
// Begin a usermessage from the server to the client .dll
bf_write *(*UserMessageBegin)( void *pVTable, IRecipientFilter *filter, int msg_type );
// Finish the Entity or UserMessage and dispatch to network layer
void (*MessageEnd)( void *pVTable );
// Print szMsg to the client console.
void (*ClientPrintf)( void *pVTable, edict_t *pEdict, const char *szMsg );
// SINGLE PLAYER/LISTEN SERVER ONLY (just matching the client .dll api for this)
// Prints the formatted string to the notification area of the screen ( down the right hand edge
// numbered lines starting at position 0
void (*Con_NPrintf)( void *pVTable, int pos, const char *fmt, ... );
// SINGLE PLAYER/LISTEN SERVER ONLY(just matching the client .dll api for this)
// Similar to Con_NPrintf, but allows specifying custom text color and duration information
void (*Con_NXPrintf)( void *pVTable, const struct con_nprint_s *info, const char *fmt, ... );
// For ConCommand parsing or parsing client commands issued by players typing at their console
// Retrieves the raw command string (untokenized)
const char *(*Cmd_Args)( void *pVTable );
// Returns the number of tokens in the command string
int (*Cmd_Argc)( void *pVTable );
// Retrieves a specified token
char *(*Cmd_Argv)( void *pVTable, int argc );
// Change a specified player's "view entity" (i.e., use the view entity position/orientation for rendering the client view)
void (*SetView)( void *pVTable, const edict_t *pClient, const edict_t *pViewent );
// Get a high precision timer for doing profiling work
float (*Time)( void *pVTable );
// Set the player's crosshair angle
void (*CrosshairAngle)( void *pVTable, const edict_t *pClient, float pitch, float yaw );
// Get the current game directory (hl2, tf2, hl1, cstrike, etc.)
void (*GetGameDir)( void *pVTable, char *szGetGameDir, int maxlength );
// Used by AI node graph code to determine if .bsp and .ain files are out of date
int (*CompareFileTime)( void *pVTable, const char *filename1, const char *filename2, int *iCompare );
// Locks/unlocks the network string tables (.e.g, when adding bots to server, this needs to happen).
// Be sure to reset the lock after executing your code!!!
bool (*LockNetworkStringTables)( void *pVTable, bool lock );
// Create a bot with the given name. Returns NULL if fake client can't be created
edict_t *(*CreateFakeClient)( void *pVTable, const char *netname );
// Get a convar keyvalue for s specified client
const char *(*GetClientConVarValue)( void *pVTable, int clientIndex, const char *name );
// Parse a token from a file
const char *(*ParseFile)( void *pVTable, const char *data, char *token, int maxlen );
// Copies a file
bool (*CopyFile)( void *pVTable, const char *source, const char *destination );
// Reset the pvs, pvssize is the size in bytes of the buffer pointed to by pvs.
// This should be called right before any calls to AddOriginToPVS
void (*ResetPVS)( void *pVTable, byte *pvs, int pvssize );
// Merge the pvs bits into the current accumulated pvs based on the specified origin ( not that each pvs origin has an 8 world unit fudge factor )
void (*AddOriginToPVS)( void *pVTable, const Vector &origin );
// Mark a specified area portal as open/closes
void (*SetAreaPortalState)( void *pVTable, int portalNumber, int isOpen );
// Queue a temp entity for transmission
void (*PlaybackTempEntity)( void *pVTable, IRecipientFilter& filter, float delay, const void *pSender, const SendTable *pST, int classID );
// Given a node number and the specified PVS, return with the node is in the PVS
int (*CheckHeadnodeVisible)( void *pVTable, int nodenum, const byte *pvs, int vissize );
// Using area bits, cheeck whether area1 flows into area2 and vice versa (depends on area portal state)
int (*CheckAreasConnected)( void *pVTable, int area1, int area2 );
// Given an origin, determine which area index the origin is within
int (*GetArea)( void *pVTable, const Vector &origin );
// Get area portal bit set
void (*GetAreaBits)( void *pVTable, int area, unsigned char *bits, int buflen );
// Given a view origin (which tells us the area to start looking in) and a portal key,
// fill in the plane that leads out of this area (it points into whatever area it leads to).
bool (*GetAreaPortalPlane)( void *pVTable, Vector const &vViewOrigin, int portalKey, VPlane *pPlane );
// Apply a modification to the terrain.
void (*ApplyTerrainMod)( void *pVTable, TerrainModType type, CTerrainModParams const ¶ms );
// Save/restore wrapper - FIXME: At some point we should move this to it's own interface
bool (*LoadGameState)( void *pVTable, char const *pMapName, bool createPlayers );
void (*LoadAdjacentEnts)( void *pVTable, const char *pOldLevel, const char *pLandmarkName );
void (*ClearSaveDir)( void *pVTable );
// Get the pristine map entity lump string. (e.g., used by CS to reload the map entities when restarting a round.)
const char* (*GetMapEntitiesString)( void *pVTable );
// Text message system -- lookup the text message of the specified name
client_textmessage_t *(*TextMessageGet)( void *pVTable, const char *pName );
// Print a message to the server log file
void (*LogPrint)( void *pVTable, const char *msg );
// Builds PVS information for an entity
void (*BuildEntityClusterList)( void *pVTable, edict_t *pEdict, PVSInfo_t *pPVSInfo );
// A solid entity moved, update spatial partition
void (*SolidMoved)( void *pVTable, edict_t *pSolidEnt, ICollideable *pSolidCollide, const Vector* pPrevAbsOrigin );
// A trigger entity moved, update spatial partition
void (*TriggerMoved)( void *pVTable, edict_t *pTriggerEnt );
// Create/destroy a custom spatial partition
ISpatialPartition *(*CreateSpatialPartition)( void *pVTable, const Vector& worldmin, const Vector& worldmax );
void (*DestroySpatialPartition)( void *pVTable, ISpatialPartition * );
// Draw the brush geometry in the map into the scratch pad.
// Flags is currently unused.
void (*DrawMapToScratchPad)( void *pVTable, IScratchPad3D *pPad, unsigned long iFlags );
// This returns which entities, to the best of the server's knowledge, the client currently knows about.
// This is really which entities were in the snapshot that this client last acked.
// This returns a bit vector with one bit for each entity.
//
// USE WITH CARE. Whatever tick the client is really currently on is subject to timing and
// ordering differences, so you should account for about a quarter-second discrepancy in here.
// Also, this will return NULL if the client doesn't exist or if this client hasn't acked any frames yet.
//
// iClientIndex is the CLIENT index, so if you use pPlayer->entindex(), subtract 1.
const CBitVec<MAX_EDICTS>* (*GetEntityTransmitBitsForClient)( void *pVTable, int iClientIndex );
// Is the game paused?
bool (*IsPaused)( void *pVTable );
// Marks the filename for consistency checking. This should be called after precaching the file.
void (*ForceExactFile)( void *pVTable, const char *s );
void (*ForceModelBounds)( void *pVTable, const char *s, const Vector &mins, const Vector &maxs );
} ivengineserver_t;
#endif // INTERFACE_HOOK_H
The protect / unprotect functions...
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
inline void UTIL_VClassUnprotect( void *pObject, int iMLen )
{
char *p;
p = (char*)((int)(*(void**)pObject) & ~(PAGESIZE-1));
if( mprotect( p, (int)(*(char**)pObject - p) + iMLen, PROT_READ | PROT_WRITE | PROT_EXEC ) )
{
perror( "Virtual Class memory unprotect failed (using mprotect)" );
}
}
inline void UTIL_VClassProtect( void *pObject, int iMLen )
{
char *p;
p = (char*)((int)(*(void**)pObject) & ~(PAGESIZE-1));
if( mprotect( p, (int)(*(char**)pObject - p) + iMLen, PROT_READ | PROT_EXEC ) )
{
perror( "Virtual Class memory protect failed (using mprotect)" );
}
}