1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2024-11-29 11:24:19 +01:00
HLMetaModOfficial/loader/serverplugin.cpp

263 lines
6.2 KiB
C++

/**
* vim: set ts=4 sw=4 tw=99 noet :
* ======================================================
* Metamod:Source
* Copyright (C) 2004-2009 AlliedModders LLC and authors.
* All rights reserved.
* ======================================================
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
#include "loader.h"
#include <sh_memfuncinfo.h>
#include <sh_memory.h>
#include "serverplugin.h"
typedef enum
{
PLUGIN_CONTINUE = 0,
PLUGIN_OVERRIDE,
PLUGIN_STOP,
} PLUGIN_RESULT;
typedef enum
{
eQueryCvarValueStatus_ValueIntact=0,
eQueryCvarValueStatus_CvarNotFound=1,
eQueryCvarValueStatus_NotACvar=2,
eQueryCvarValueStatus_CvarProtected=3
} EQueryCvarValueStatus;
typedef int QueryCvarCookie_t;
class CCommand;
class IServerPluginCallbacks;
struct edict_t;
#if defined WIN32
#define LIBRARY_EXT ".dll"
#else
#define LIBRARY_EXT "_i486.so"
#endif
class IRandomThings
{
public:
virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity, const CCommand& args)
{
return PLUGIN_CONTINUE;
}
};
IVspBridge *vsp_bridge = NULL;
/**
* The vtable must match the general layout for ISPC. We modify the vtable
* based on what we get back.
*/
class ServerPlugin
{
const char *game_name;
unsigned int vsp_version;
bool load_allowed;
public:
ServerPlugin()
{
load_allowed = false;
}
virtual bool Load(QueryValveInterface engineFactory, QueryValveInterface gsFactory)
{
if (!load_allowed)
return false;
load_allowed = false;
if ((game_name = mm_GetGameName()) == NULL)
{
return false;
}
MetamodBackend backend = mm_DetermineBackend(engineFactory, game_name);
if (backend == MMBackend_UNKNOWN)
{
mm_LogFatal("Could not detect engine version");
return false;
}
else if (backend >= MMBackend_Episode2)
{
/* We need to insert the right type of call into this vtable */
void **vtable_src;
void **vtable_dest;
IRandomThings sample;
SourceHook::MemFuncInfo mfp_dest, mfp_src;
mfp_dest.isVirtual = false;
mfp_src.isVirtual = false;
SourceHook::GetFuncInfo(&ServerPlugin::ClientCommand, mfp_dest);
SourceHook::GetFuncInfo(&IRandomThings::ClientCommand, mfp_src);
assert(mfp_dest.isVirtual);
assert(mfp_dest.thisptroffs == 0);
assert(mfp_dest.vtbloffs == 0);
assert(mfp_src.isVirtual);
assert(mfp_src.thisptroffs == 0);
assert(mfp_src.vtbloffs == 0);
vtable_src = (void **)*(void **)&sample;
vtable_dest = (void **)*(void **)this;
SourceHook::SetMemAccess(&vtable_dest[mfp_dest.vtblindex],
sizeof(void*),
SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
vtable_dest[mfp_dest.vtblindex] = vtable_src[mfp_src.vtblindex];
}
char error[255];
if (!mm_LoadMetamodLibrary(backend, error, sizeof(error)))
{
mm_LogFatal("Detected engine %d but could not load: %s", backend, error);
return false;
}
typedef IVspBridge *(*GetVspBridge)();
GetVspBridge get_bridge = (GetVspBridge)mm_GetProcAddress("GetVspBridge");
if (get_bridge == NULL)
{
mm_UnloadMetamodLibrary();
mm_LogFatal("Detected engine %d but could not find GetVspBridge callback", backend);
return false;
}
vsp_bridge = get_bridge();
vsp_bridge_info info;
info.engineFactory = engineFactory;
info.gsFactory = gsFactory;
info.vsp_callbacks = (IServerPluginCallbacks*)this;
info.vsp_version = vsp_version;
strcpy(error, "Unknown error");
if (!vsp_bridge->Load(&info, error, sizeof(error)))
{
vsp_bridge = NULL;
mm_UnloadMetamodLibrary();
mm_LogFatal("Unknown error loading Metamod for engine %d: %s", backend, error);
return false;
}
return true;
}
virtual void Unload()
{
if (vsp_bridge == NULL)
return;
vsp_bridge->Unload();
mm_UnloadMetamodLibrary();
}
virtual void Pause()
{
}
virtual void UnPause()
{
}
virtual const char *GetPluginDescription()
{
if (vsp_bridge == NULL)
return "Metamod:Source Loader Shim";
return vsp_bridge->GetDescription();
}
virtual void LevelInit(char const *pMapName)
{
}
virtual void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
{
}
virtual void GameFrame(bool simulating)
{
}
virtual void LevelShutdown()
{
}
virtual void ClientActive(edict_t *pEntity)
{
}
virtual void ClientDisconnect(edict_t *pEntity)
{
}
virtual void ClientPutInServer(edict_t *pEntity, char const *playername)
{
}
virtual void SetCommandClient(int index)
{
}
virtual void ClientSettingsChanged(edict_t *pEdict)
{
}
virtual PLUGIN_RESULT ClientConnect(bool *bAllowConnect,
edict_t *pEntity,
const char *pszName,
const char *pszAddress,
char *reject,
int maxrejectlen)
{
return PLUGIN_CONTINUE;
}
virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity)
{
return PLUGIN_CONTINUE;
}
virtual PLUGIN_RESULT NetworkIDValidated(const char *pszUserName, const char *pszNetworkID)
{
return PLUGIN_CONTINUE;
}
virtual void OnQueryCvarValueFinished(QueryCvarCookie_t iCookie,
edict_t *pPlayerEntity,
EQueryCvarValueStatus eStatus,
const char *pCvarName,
const char *pCvarValue)
{
}
void PrepForLoad(unsigned int version)
{
vsp_version = version;
load_allowed = true;
}
};
ServerPlugin mm_vsp_callbacks;
void *mm_GetVspCallbacks(unsigned int version)
{
if (vsp_bridge != NULL)
return NULL;
/* Only support versions 1 or 2 right now */
if (version > 2)
return NULL;
mm_vsp_callbacks.PrepForLoad(version);
return &mm_vsp_callbacks;
}