mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2024-11-28 10:24:20 +01:00
Sample plugin can now do anything server plugins can (except NetworkIDValidated callback)
--HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%4023
This commit is contained in:
parent
1789ad8324
commit
0d5424c5b4
@ -5,46 +5,168 @@ SamplePlugin g_SamplePlugin;
|
||||
|
||||
PLUGIN_EXPOSE(SamplePlugin, g_SamplePlugin);
|
||||
|
||||
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool);
|
||||
//This has all of the necessary hook declarations. Read it!
|
||||
#include "meta_hooks.h"
|
||||
|
||||
bool LevelInit_handler( char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background );
|
||||
bool SamplePlugin::LevelInit(const char *pMapName, const char *pMapEntities, const char *pOldLevel, const char *pLandmarkName, bool loadGame, bool background)
|
||||
{
|
||||
META_LOG(g_PLAPI, "LevelInit() called: pMapName=%s", pMapName);
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
void SamplePlugin::ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ServerActivate() called: edictCount=%d, clientMax=%d", edictCount, clientMax);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::GameFrame(bool simulating)
|
||||
{
|
||||
META_LOG(g_PLAPI, "GameFrame() called: simulating=%d", simulating);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::LevelShutdown( void )
|
||||
{
|
||||
META_LOG(g_PLAPI, "LevelShutdown() called");
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientActive(edict_t *pEntity, bool bLoadGame)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientActive called: pEntity=%d", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientDisconnect(edict_t *pEntity)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientDisconnect called: pEntity=%d", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientPutInServer(edict_t *pEntity, char const *playername)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientActivate called: pEntity=%d, playername=%s", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0, playername);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::SetCommandClient(int index)
|
||||
{
|
||||
META_LOG(g_PLAPI, "SetCommandClient() called: index=%d", index);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientSettingsChanged(edict_t *pEdict)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientSettingsChanged called: pEdict=%d", pEdict ? m_Engine->IndexOfEdict(pEdict) : 0);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool SamplePlugin::ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientConnect called: pEntity=%d, pszName=%s, pszAddress=%s", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0, pszName, pszAddress);
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
void SamplePlugin::ClientCommand(edict_t *pEntity)
|
||||
{
|
||||
META_LOG(g_PLAPI, "ClientCommand called: pEntity=%d (commandString=%s)", pEntity ? m_Engine->IndexOfEdict(pEntity) : 0, m_Engine->Cmd_Args() ? m_Engine->Cmd_Args() : "");
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool SamplePlugin::Load(PluginId id, ISmmAPI *ismm, factories *list, char *error, size_t maxlen)
|
||||
{
|
||||
PLUGIN_SAVEVARS();
|
||||
|
||||
IServerGameDLL *isgd = (IServerGameDLL *)((ismm->serverFactory())(INTERFACEVERSION_SERVERGAMEDLL, NULL));
|
||||
m_ServerDll = (IServerGameDLL *)((ismm->serverFactory())(INTERFACEVERSION_SERVERGAMEDLL, NULL));
|
||||
m_Engine = (IVEngineServer *)((ismm->engineFactory())(INTERFACEVERSION_VENGINESERVER, NULL));
|
||||
m_ServerClients = (IServerGameClients *)((ismm->serverFactory())(INTERFACEVERSION_SERVERGAMECLIENTS, NULL));
|
||||
|
||||
if (!isgd)
|
||||
if (!m_ServerDll)
|
||||
{
|
||||
snprintf(error, maxlen, "Could not find interface %s", INTERFACEVERSION_SERVERGAMEDLL);
|
||||
return false;
|
||||
}
|
||||
if (!m_Engine)
|
||||
{
|
||||
snprintf(error, maxlen, "Could not find interface %s", INTERFACEVERSION_VENGINESERVER);
|
||||
return false;
|
||||
}
|
||||
if (!m_ServerClients)
|
||||
{
|
||||
snprintf(error, maxlen, "Could not find interface %s", INTERFACEVERSION_SERVERGAMECLIENTS);
|
||||
return false;
|
||||
}
|
||||
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, isgd, LevelInit_handler, false);
|
||||
//We're hooking the following things as POST, in order to seem like Server Plugins.
|
||||
//However, I don't actually know if Valve has done server plugins as POST or not.
|
||||
//Change the last parameter to 'false' in order to change this to PRE.
|
||||
//SH_ADD_HOOK_MEMFUNC means "SourceHook, Add Hook, Member Function".
|
||||
|
||||
//Hook LevelInit to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, m_ServerDll, &g_SamplePlugin, LevelInit, true);
|
||||
//Hook ServerActivate to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, m_ServerDll, &g_SamplePlugin, ServerActivate, true);
|
||||
//Hook GameFrame to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, m_ServerDll, &g_SamplePlugin, GameFrame, true);
|
||||
//Hook LevelShutdown to our function -- this makes more sense as pre I guess
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, m_ServerDll, &g_SamplePlugin, LevelShutdown, false);
|
||||
//Hook ClientActivate to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientActive, m_ServerClients, &g_SamplePlugin, ClientActive, true);
|
||||
//Hook ClientDisconnect to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, m_ServerClients, &g_SamplePlugin, ClientDisconnect, true);
|
||||
//Hook ClientPutInServer to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, m_ServerClients, &g_SamplePlugin, ClientPutInServer, true);
|
||||
//Hook SetCommandClient to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, m_ServerClients, &g_SamplePlugin, SetCommandClient, true);
|
||||
//Hook ClientSettingsChanged to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, m_ServerClients, &g_SamplePlugin, ClientSettingsChanged, true);
|
||||
|
||||
//The following functions are pre handled, because that's how they are in IServerPluginCallbacks
|
||||
|
||||
//Hook ClientConnect to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, m_ServerClients, &g_SamplePlugin, ClientConnect, false);
|
||||
//Hook ClientCommand to our function
|
||||
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, m_ServerClients, &g_SamplePlugin, ClientCommand, false);
|
||||
|
||||
//Now, importantly, SourceHook has modified the layout of the above classes.
|
||||
//If we want to call them in their original state (i.e., without invoking hooks)
|
||||
// we must request a "Call Class" from SourceHook.
|
||||
m_ServerClients_CC = SH_GET_CALLCLASS(IServerGameClients, m_ServerClients);
|
||||
m_ServerDll = SH_GET_CALLCLASS(IServerGameDLL, m_ServerDll);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SamplePlugin::Unload(char *error, size_t maxlen)
|
||||
{
|
||||
//Make sure we remove any hooks we did... this may not be necessary since
|
||||
// SourceHook is capable of unloading plugins' hooks itself, but just to be safe.
|
||||
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, m_ServerDll, &g_SamplePlugin, LevelInit, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, m_ServerDll, &g_SamplePlugin, ServerActivate, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, m_ServerDll, &g_SamplePlugin, GameFrame, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, m_ServerDll, &g_SamplePlugin, LevelShutdown, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientActive, m_ServerClients, &g_SamplePlugin, ClientActive, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, m_ServerClients, &g_SamplePlugin, ClientDisconnect, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, m_ServerClients, &g_SamplePlugin, ClientPutInServer, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, m_ServerClients, &g_SamplePlugin, SetCommandClient, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, m_ServerClients, &g_SamplePlugin, ClientSettingsChanged, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, m_ServerClients, &g_SamplePlugin, ClientConnect, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, m_ServerClients, &g_SamplePlugin, ClientCommand, false);
|
||||
|
||||
//Lastly, release the call classes we requested
|
||||
SH_RELEASE_CALLCLASS(m_ServerDll_CC);
|
||||
SH_RELEASE_CALLCLASS(m_ServerClients_CC);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SamplePlugin::AllPluginsLoaded()
|
||||
{
|
||||
//we don't really care
|
||||
}
|
||||
|
||||
bool LevelInit_handler( char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background )
|
||||
{
|
||||
FILE *fp = fopen("c:\\dump.txt", "at");
|
||||
if (!fp)
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
|
||||
fprintf(fp, "Map name: %s (old level: %s)\n", pMapName?pMapName:"", pOldLevel?pOldLevel:"");
|
||||
|
||||
fclose(fp);
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
//we don't really need this for anything other than interplugin communication
|
||||
//and that's not used in this plugin.
|
||||
//If we really wanted, we could override the factories so other plugins can request
|
||||
// interfaces we make. In this callback, the plugin could be assured that either
|
||||
// the interfaces it requires were either loaded in another plugin or not.
|
||||
}
|
||||
|
@ -52,6 +52,53 @@ public:
|
||||
{
|
||||
return "SAMPLE";
|
||||
}
|
||||
public:
|
||||
//These functions are from IServerPluginCallbacks
|
||||
//Note, the parameters might be a little different to match the actual calls!
|
||||
|
||||
//Called on LevelInit. Server plugins only have pMapName
|
||||
bool LevelInit(const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
||||
|
||||
//Called on ServerActivate. Same definition as server plugins
|
||||
void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
|
||||
//Called on a game tick. Same definition as server plugins
|
||||
void GameFrame(bool simulating);
|
||||
|
||||
//Called on level shutdown. Same definition as server plugins
|
||||
void LevelShutdown(void);
|
||||
|
||||
//Client is activate (whatever that means). We get an extra parameter...
|
||||
// "If bLoadGame is true, don't spawn the player because its state is already setup."
|
||||
void ClientActive(edict_t *pEntity, bool bLoadGame);
|
||||
|
||||
//Client disconnects - same as server plugins
|
||||
void ClientDisconnect(edict_t *pEntity);
|
||||
|
||||
//Client is put in server - same as server plugins
|
||||
void ClientPutInServer(edict_t *pEntity, char const *playername);
|
||||
|
||||
//Sets the client index - same as server plugins
|
||||
void SetCommandClient(int index);
|
||||
|
||||
//Called on client settings changed (duh) - same as server plugins
|
||||
void ClientSettingsChanged(edict_t *pEdict);
|
||||
|
||||
//Called on client connect. Unlike server plugins, we return whether the
|
||||
// connection is allowed rather than set it through a pointer in the first parameter.
|
||||
// You can still supercede the GameDLL through RETURN_META_VALUE(MRES_SUPERCEDE, true/false)
|
||||
bool ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
|
||||
|
||||
//Called when a client uses a command. Unlike server plugins, it's void.
|
||||
// You can still supercede the gamedll through RETURN_META(MRES_SUPERCEDE).
|
||||
void ClientCommand(edict_t *pEntity);
|
||||
|
||||
private:
|
||||
IVEngineServer *m_Engine;
|
||||
IServerGameDLL *m_ServerDll;
|
||||
IServerGameClients *m_ServerClients;
|
||||
IServerGameDLL *m_ServerDll_CC;
|
||||
IServerGameClients *m_ServerClients_CC;
|
||||
};
|
||||
|
||||
extern SamplePlugin g_SamplePlugin;
|
||||
|
20
sourcemm/sample_mm/meta_hooks.h
Normal file
20
sourcemm/sample_mm/meta_hooks.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef _INCLUDE_META_HOOKS_H
|
||||
#define _INCLUDE_META_HOOKS_H
|
||||
|
||||
//Declare the hooks we will be using. Hooking will not compile without these.
|
||||
//The macro naming scheme is SH_DECL_HOOKn[_void].
|
||||
//If you have 5 parameters, it would be HOOK5. If the function is void, add _void.
|
||||
//It stands for "SourceHook, Declare Hook".
|
||||
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool);
|
||||
SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
|
||||
SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, 0, bool);
|
||||
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, 0);
|
||||
SH_DECL_HOOK2_void(IServerGameClients, ClientActive, SH_NOATTRIB, 0, edict_t *, bool);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
|
||||
SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, char const *);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, 0, int);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
|
||||
SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char*, const char *, char *, int);
|
||||
SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
|
||||
|
||||
#endif //_INCLUDE_META_HOOKS_H
|
@ -124,6 +124,9 @@
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath=".\meta_hooks.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\SamplePlugin.h">
|
||||
</File>
|
||||
|
Loading…
Reference in New Issue
Block a user