mirror of
https://github.com/rehlds/metamod-r.git
synced 2024-12-27 07:05:34 +03:00
Rewritten regcmd code
This commit is contained in:
parent
d206ad4a13
commit
7e6878b3a1
5
metamod/include/engine/public_amalgamation.cpp
Normal file
5
metamod/include/engine/public_amalgamation.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "sys_shared.cpp"
|
||||
#include "interface.cpp"
|
||||
#include "crc32c.cpp"
|
@ -34,8 +34,8 @@
|
||||
#include "interface.h"
|
||||
#include "model.h"
|
||||
|
||||
#define REHLDS_API_VERSION_MAJOR 2
|
||||
#define REHLDS_API_VERSION_MINOR 13
|
||||
#define REHLDS_API_VERSION_MAJOR 3
|
||||
#define REHLDS_API_VERSION_MINOR 1
|
||||
|
||||
//Steam_NotifyClientConnect hook
|
||||
typedef IHookChain<qboolean, IGameClient*, const void*, unsigned int> IRehldsHook_Steam_NotifyClientConnect;
|
||||
@ -122,8 +122,8 @@ typedef IVoidHookChain<IGameClient *, struct packet_entities_s *, sizebuf_t *> I
|
||||
typedef IVoidHookChainRegistry<IGameClient *, struct packet_entities_s *, sizebuf_t *> IRehldsHookRegistry_SV_EmitEvents;
|
||||
|
||||
//EV_PlayReliableEvent hook
|
||||
typedef IVoidHookChain<IGameClient *, int, short unsigned int, float, struct event_args_s *> IRehldsHook_EV_PlayReliableEvent;
|
||||
typedef IVoidHookChainRegistry<IGameClient *, int, short unsigned int, float, struct event_args_s *> IRehldsHookRegistry_EV_PlayReliableEvent;
|
||||
typedef IVoidHookChain<IGameClient *, int, unsigned short, float, struct event_args_s *> IRehldsHook_EV_PlayReliableEvent;
|
||||
typedef IVoidHookChainRegistry<IGameClient *, int, unsigned short, float, struct event_args_s *> IRehldsHookRegistry_EV_PlayReliableEvent;
|
||||
|
||||
//SV_StartSound hook
|
||||
typedef IVoidHookChain<int , edict_t *, int, const char *, int, float, int, int> IRehldsHook_SV_StartSound;
|
||||
@ -257,7 +257,7 @@ struct RehldsFuncs_t {
|
||||
cmd_source_t*(*GetCmdSource)();
|
||||
void(*Log)(const char* prefix, const char* msg);
|
||||
DLL_FUNCTIONS *(*GetEntityInterface)();
|
||||
void(*EV_PlayReliableEvent)(IGameClient *cl, int entindex, short unsigned int eventindex, float delay, struct event_args_s *pargs);
|
||||
void(*EV_PlayReliableEvent)(IGameClient *cl, int entindex, unsigned short eventindex, float delay, struct event_args_s *pargs);
|
||||
int(*SV_LookupSoundIndex)(const char *sample);
|
||||
void(*MSG_StartBitWriting)(sizebuf_t *buf);
|
||||
void(*MSG_WriteBits)(uint32 data, int numbits);
|
||||
@ -280,7 +280,9 @@ struct RehldsFuncs_t {
|
||||
void(*Steam_NotifyClientDisconnect)(IGameClient* cl);
|
||||
void(*SV_StartSound)(int recipients, edict_t *entity, int channel, const char *sample, int volume, float attenuation, int flags, int pitch);
|
||||
bool(*SV_EmitSound2)(edict_t *entity, IGameClient *receiver, int channel, const char *sample, float volume, float attenuation, int flags, int pitch, int emitFlags, const float *pOrigin);
|
||||
void (* SV_UpdateUserInfo)(IGameClient *pGameClient);
|
||||
void(*SV_UpdateUserInfo)(IGameClient *pGameClient);
|
||||
bool(*StripUnprintableAndSpace)(char *pch);
|
||||
void(*Cmd_RemoveCmd)(char *cmd_name);
|
||||
};
|
||||
|
||||
class IRehldsApi {
|
||||
|
@ -186,6 +186,7 @@
|
||||
<ClCompile Include="..\src\linkent.cpp" />
|
||||
<ClCompile Include="..\src\linkgame.cpp" />
|
||||
<ClCompile Include="..\src\log_meta.cpp" />
|
||||
<ClCompile Include="..\src\metamod_rehlds_api.cpp" />
|
||||
<ClCompile Include="..\src\meta_eiface.cpp" />
|
||||
<ClCompile Include="..\src\metamod.cpp" />
|
||||
<ClCompile Include="..\src\mlist.cpp" />
|
||||
@ -198,6 +199,7 @@
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\public_amalgamation.cpp" />
|
||||
<ClCompile Include="..\src\reg_support.cpp" />
|
||||
<ClCompile Include="..\src\sdk_util.cpp" />
|
||||
<ClCompile Include="..\src\studioapi.cpp" />
|
||||
@ -218,6 +220,7 @@
|
||||
<ClInclude Include="..\src\jitasm.h" />
|
||||
<ClInclude Include="..\src\linkent.h" />
|
||||
<ClInclude Include="..\src\log_meta.h" />
|
||||
<ClInclude Include="..\src\metamod_rehlds_api.h" />
|
||||
<ClInclude Include="..\src\meta_api.h" />
|
||||
<ClInclude Include="..\src\meta_eiface.h" />
|
||||
<ClInclude Include="..\src\metamod.h" />
|
||||
|
@ -86,6 +86,12 @@
|
||||
<ClCompile Include="..\src\callback_jit.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\metamod_rehlds_api.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\public_amalgamation.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\api_info.h">
|
||||
@ -178,6 +184,9 @@
|
||||
<ClInclude Include="..\src\jitasm.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\metamod_rehlds_api.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="metamod.def">
|
||||
|
@ -20,7 +20,7 @@ void META_CONS(const char *fmt, ...)
|
||||
unsigned int len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = Q_vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
|
||||
len = Q_vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
buf[len] = '\n';
|
||||
|
70
metamod/src/metamod_rehlds_api.cpp
Normal file
70
metamod/src/metamod_rehlds_api.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#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, majorVersion);
|
||||
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;
|
||||
}
|
8
metamod/src/metamod_rehlds_api.h
Normal file
8
metamod/src/metamod_rehlds_api.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
extern IRehldsApi* g_RehldsApi;
|
||||
extern const RehldsFuncs_t* g_RehldsFuncs;
|
||||
extern IRehldsHookchains* g_RehldsHookchains;
|
||||
extern IRehldsServerStatic* g_RehldsSvs;
|
||||
|
||||
extern bool meta_init_rehlds_api();
|
@ -1068,7 +1068,7 @@ bool MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASO
|
||||
// successful detach, or forced unload
|
||||
|
||||
// Unmark registered commands for this plugin (by index number).
|
||||
g_regCmds->disable(index);
|
||||
g_regCmds->remove(index);
|
||||
// Unmark registered cvars for this plugin (by index number).
|
||||
g_regCvars->disable(index);
|
||||
|
||||
|
@ -1,125 +1,82 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
// Init values. It would probably be more "proper" to use containers and
|
||||
// constructors, rather than arrays and init-functions.
|
||||
void MRegCmd::init(int idx)
|
||||
MRegCmd::MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin) : pfnCmd(cmd_handler), status(RG_VALID), plugid(cmd_plugin->index)
|
||||
{
|
||||
index = idx;
|
||||
name = NULL;
|
||||
pfnCmd = NULL;
|
||||
name = _strdup(name);
|
||||
}
|
||||
|
||||
bool MRegCmd::call() const
|
||||
{
|
||||
pfnCmd();
|
||||
return status != RG_INVALID;
|
||||
}
|
||||
|
||||
void MRegCmd::disable()
|
||||
{
|
||||
pfnCmd = [](){};
|
||||
plugid = 0;
|
||||
status = RG_INVALID;
|
||||
}
|
||||
|
||||
// Try to call the function. Relies on OS-specific routine to attempt
|
||||
// calling the function without generating a segfault from an unloaded
|
||||
// plugin DLL.
|
||||
// meta_errno values:
|
||||
// - ME_BADREQ function disabled/invalid
|
||||
// - ME_ARGUMENT function pointer is null
|
||||
bool MRegCmd::call()
|
||||
char* MRegCmd::getname() const
|
||||
{
|
||||
bool ret;
|
||||
|
||||
// can we expect to call this function?
|
||||
if (status != RG_VALID)
|
||||
RETURN_ERRNO(false, ME_BADREQ);
|
||||
|
||||
if (!pfnCmd)
|
||||
RETURN_ERRNO(false, ME_ARGUMENT);
|
||||
|
||||
// try to call this function
|
||||
ret = os_safe_call(pfnCmd);
|
||||
if (!ret)
|
||||
{
|
||||
META_DEBUG(4, ("Plugin reg_cmd '%s' called after unloaded; removed from list", name));
|
||||
status = RG_INVALID;
|
||||
pfnCmd = NULL;
|
||||
// NOTE: we can't free the malloc'd space for the name, as that
|
||||
// would just re-introduce the segfault problem..
|
||||
}
|
||||
|
||||
// meta_errno (if failed) is set already in os_safe_call()
|
||||
return ret;
|
||||
return name;
|
||||
}
|
||||
|
||||
MRegCmdList::MRegCmdList() : mlist(0), size(REG_CMD_GROWSIZE), endlist(0)
|
||||
MRegCmdList::MRegCmdList() : m_list()
|
||||
{
|
||||
mlist = (MRegCmd *)Q_malloc(size * sizeof(MRegCmd));
|
||||
|
||||
// initialize array
|
||||
for (int i = 0; i < size; i++)
|
||||
mlist[i].init(i + 1); // 1-based index
|
||||
|
||||
endlist = 0;
|
||||
}
|
||||
|
||||
// Try to find a registered function with the given name.
|
||||
// meta_errno values:
|
||||
// - ME_NOTFOUND couldn't find a matching function
|
||||
MRegCmd *MRegCmdList::find(const char *findname) const
|
||||
MRegCmd *MRegCmdList::find(const char *name) const
|
||||
{
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (auto icmd : m_list)
|
||||
{
|
||||
if (!Q_stricmp(mlist[i].name, findname))
|
||||
return &mlist[i];
|
||||
if (!Q_stricmp(icmd->name, name))
|
||||
return icmd;
|
||||
}
|
||||
|
||||
RETURN_ERRNO(NULL, ME_NOTFOUND);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add the given name to the list and return the instance. This only
|
||||
// writes the "name" to the new cmd; other fields are writtin by caller
|
||||
// (meta_AddServerCommand).
|
||||
// meta_errno values:
|
||||
// - ME_NOMEM couldn't realloc or malloc for various parts
|
||||
MRegCmd *MRegCmdList::add(const char *addname)
|
||||
MRegCmd *MRegCmdList::add(char *addname, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin)
|
||||
{
|
||||
if (endlist == size)
|
||||
{
|
||||
// grow array
|
||||
int newsize = size + REG_CMD_GROWSIZE;
|
||||
META_DEBUG(6, ("Growing reg cmd list from %d to %d", size, newsize));
|
||||
|
||||
MRegCmd *temp = (MRegCmd *) realloc(mlist, newsize * sizeof(MRegCmd));
|
||||
if (!temp)
|
||||
{
|
||||
META_ERROR("Couldn't grow registered command list to %d for '%s': %s", newsize, addname, strerror(errno));
|
||||
RETURN_ERRNO(NULL, ME_NOMEM);
|
||||
}
|
||||
|
||||
mlist = temp;
|
||||
size = newsize;
|
||||
|
||||
// initialize new (unused) entries
|
||||
for (int i = endlist; i < size; i++)
|
||||
mlist[i].init(i + 1); // 1-based
|
||||
}
|
||||
|
||||
MRegCmd *icmd = &mlist[endlist];
|
||||
// Malloc space separately for the command name, because:
|
||||
// - Can't point to memory loc in plugin (another segv waiting to
|
||||
// happen).
|
||||
// - Can't point to memory in mlist which might get moved later by
|
||||
// realloc (again, segv).
|
||||
icmd->name = Q_strdup(addname);
|
||||
if (!icmd->name)
|
||||
{
|
||||
META_ERROR("Couldn't Q_strdup for adding reg cmd name '%s': %s", addname, strerror(errno));
|
||||
RETURN_ERRNO(NULL, ME_NOMEM);
|
||||
}
|
||||
|
||||
endlist++;
|
||||
auto icmd = new MRegCmd(addname, cmd_handler, cmd_plugin);
|
||||
m_list.push_back(icmd);
|
||||
return icmd;
|
||||
}
|
||||
|
||||
// Disable any functions belonging to the given plugin (by index id).
|
||||
void MRegCmdList::disable(int plugin_id) const
|
||||
void MRegCmdList::remove(char* cmd_name)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (mlist[i].plugid == plugin_id)
|
||||
mlist[i].status = RG_INVALID;
|
||||
for (auto it = m_list.begin(), end = m_list.end(); it != end; ++it) {
|
||||
auto icmd = *it;
|
||||
|
||||
if (!Q_stricmp(icmd->name, cmd_name)) {
|
||||
if (g_RehldsFuncs) {
|
||||
g_RehldsFuncs->Cmd_RemoveCmd(cmd_name);
|
||||
m_list.erase(it);
|
||||
}
|
||||
else {
|
||||
icmd->disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disable any functions belonging to the given plugin (by index id).
|
||||
void MRegCmdList::remove(int owner_plugin_id)
|
||||
{
|
||||
for (auto it = m_list.begin(), end = m_list.end(); it != end; ++it) {
|
||||
auto icmd = *it;
|
||||
|
||||
if (icmd->plugid == owner_plugin_id) {
|
||||
if (g_RehldsFuncs) {
|
||||
g_RehldsFuncs->Cmd_RemoveCmd(icmd->name);
|
||||
m_list.erase(it);
|
||||
}
|
||||
else {
|
||||
icmd->disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,28 +84,19 @@ void MRegCmdList::disable(int plugin_id) const
|
||||
void MRegCmdList::show() const
|
||||
{
|
||||
int n = 0, a = 0;
|
||||
MRegCmd *icmd;
|
||||
MPlugin *iplug;
|
||||
char bplug[18 + 1]; // +1 for term null
|
||||
|
||||
META_CONS("Registered plugin commands:");
|
||||
META_CONS(" %*s %-*s %-s", WIDTH_MAX_REG, "", sizeof(bplug) - 1, "plugin", "command");
|
||||
for (int i = 0; i < endlist; i++)
|
||||
META_CONS(" %*s %-*s %-s", WIDTH_MAX_REG, "", sizeof bplug - 1, "plugin", "command");
|
||||
|
||||
for (auto icmd : m_list)
|
||||
{
|
||||
icmd = &mlist[i];
|
||||
if (icmd->status == RG_VALID)
|
||||
{
|
||||
iplug = g_plugins->find(icmd->plugid);
|
||||
if (iplug)
|
||||
{
|
||||
Q_strncpy(bplug, iplug->desc, sizeof bplug - 1);
|
||||
bplug[sizeof bplug - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncpy(bplug, "(unknown)", sizeof bplug - 1);
|
||||
bplug[sizeof bplug - 1] = '\0';
|
||||
}
|
||||
auto iplug = g_plugins->find(icmd->plugid);
|
||||
|
||||
Q_strncpy(bplug, iplug ? iplug->desc : "(unknown)", sizeof bplug - 1);
|
||||
bplug[sizeof bplug - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -156,27 +104,23 @@ void MRegCmdList::show() const
|
||||
bplug[sizeof bplug - 1] = '\0';
|
||||
}
|
||||
|
||||
META_CONS(" [%*d] %-*s %-s", WIDTH_MAX_REG, icmd->index, sizeof(bplug) - 1, bplug, icmd->name);
|
||||
META_CONS(" [%*d] %-*s %-s", WIDTH_MAX_REG, ++n, sizeof bplug - 1, bplug, icmd->name);
|
||||
|
||||
if (icmd->status == RG_VALID)
|
||||
a++;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
META_CONS("%d commands, %d available (%d allocated)", n, a, size);
|
||||
META_CONS("%d commands, %d available", n, a);
|
||||
}
|
||||
|
||||
// List all the registered commands for the given plugin id.
|
||||
void MRegCmdList::show(int plugin_id) const
|
||||
{
|
||||
int n = 0;
|
||||
MRegCmd *icmd;
|
||||
|
||||
META_CONS("Registered commands:");
|
||||
for (int i = 0; i < endlist; i++)
|
||||
for (auto icmd : m_list)
|
||||
{
|
||||
icmd = &mlist[i];
|
||||
|
||||
if (icmd->plugid != plugin_id)
|
||||
continue;
|
||||
|
||||
|
@ -24,21 +24,23 @@ enum REG_STATUS { RG_INVALID, RG_VALID };
|
||||
// Pointer to function registered by AddServerCommand.
|
||||
typedef void (*REG_CMD_FN)();
|
||||
|
||||
class MPlugin;
|
||||
|
||||
// An individual registered function/command.
|
||||
class MRegCmd {
|
||||
public:
|
||||
friend class MRegCmdList;
|
||||
MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin);
|
||||
bool call() const; // try to call the function
|
||||
void disable();
|
||||
char* getname() const;
|
||||
|
||||
private:
|
||||
char *name; // space is malloc'd
|
||||
REG_CMD_FN pfnCmd; // pointer to the function
|
||||
int plugid; // index id of corresponding plugin
|
||||
REG_STATUS status; // whether corresponding plugin is loaded
|
||||
|
||||
void init(int idx); // init values, as not using constructors
|
||||
bool call(); // try to call the function
|
||||
|
||||
private:
|
||||
int index; // 1-based
|
||||
friend class MRegCmdList;
|
||||
};
|
||||
|
||||
// A list of registered commands.
|
||||
@ -46,21 +48,15 @@ class MRegCmdList {
|
||||
public:
|
||||
MRegCmdList();
|
||||
|
||||
MRegCmd *find(const char *findname) const; // find by MRegCmd->name
|
||||
MRegCmd *add(const char *addname);
|
||||
void disable(int plugin_id) const; // change status to Invalid
|
||||
MRegCmd *find(const char *name) const; // find by MRegCmd->name
|
||||
MRegCmd *add(char *name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin);
|
||||
void remove(char* cmd_name);
|
||||
void remove(int owner_plugin_id); // change status to Invalid
|
||||
void show() const; // list all funcs to console
|
||||
void show(int plugin_id) const; // list given plugin's funcs to console
|
||||
|
||||
private:
|
||||
MRegCmd *mlist; // malloc'd array of registered commands
|
||||
int size; // current size of list
|
||||
int endlist; // index of last used entry
|
||||
|
||||
// Private; to satisfy -Weffc++ "has pointer data members but does
|
||||
// not override" copy/assignment constructor.
|
||||
void operator=(const MRegCmdList &src);
|
||||
MRegCmdList(const MRegCmdList &src);
|
||||
std::vector<MRegCmd *> m_list;
|
||||
};
|
||||
|
||||
// An individual registered cvar.
|
||||
|
@ -12,14 +12,17 @@
|
||||
#include <signal.h> // sigaction, etc
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#include "jitasm.h"
|
||||
|
||||
#define CreateInterface mm_CreateInterface
|
||||
|
||||
#include <extdll.h>
|
||||
#include <studio.h>
|
||||
#include <studioapi.h>
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <rehlds_api.h>
|
||||
|
||||
#include "osdep.h"
|
||||
#include "api_info.h"
|
||||
@ -32,7 +35,6 @@
|
||||
#include "engine_api.h"
|
||||
#include "game_support.h"
|
||||
#include "h_export.h"
|
||||
#include "linkent.h"
|
||||
#include "meta_eiface.h"
|
||||
#include "mreg.h"
|
||||
#include "meta_api.h"
|
||||
@ -47,3 +49,7 @@
|
||||
#include "enginecallbacks.h"
|
||||
#include "utils.h"
|
||||
#include "callback_jit.h"
|
||||
#include "metamod_rehlds_api.h"
|
||||
|
||||
#undef CreateInterface
|
||||
#include "linkent.h"
|
||||
|
5
metamod/src/public_amalgamation.cpp
Normal file
5
metamod/src/public_amalgamation.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "sys_shared.cpp"
|
||||
#include "interface.cpp"
|
||||
#include "crc32c.cpp"
|
@ -1,74 +1,22 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
// "Register" support.
|
||||
//
|
||||
// This code is necessary to support the different "register" engine
|
||||
// functions that can be called by plugins, so that the plugins can be
|
||||
// safely unloaded without incurring segmentation faults.
|
||||
//
|
||||
// The problem was that, when a plugin called, say:
|
||||
// REG_SVR_COMMAND("stub_version", svr_stub_version);
|
||||
//
|
||||
// the engine stored the address to the "stub_version" string, as well as,
|
||||
// of course, the svr_stub_version() function pointer. If the plugin was
|
||||
// unloaded, and dlclose()'d, the memory locations for both the string and
|
||||
// function became invalid and unavailable. If the engine tried to
|
||||
// strcmp() against the string, or tried to call the function pointer, it
|
||||
// generated a segfault and killed the process.
|
||||
//
|
||||
// The solution used here is to create strings and functions allocated
|
||||
// locally, in metamod.dll, which won't become unavailable or invalid due
|
||||
// to a dlclose(). These local copies are passed to the engine instead of
|
||||
// those allocated in the plugin DLLs. Thus, when a plugin is later
|
||||
// unloaded and dlclose'd, the engine can still reference the memory
|
||||
// locations of registered strings and functions, without segfaulting.
|
||||
//
|
||||
// Now, what happens with a registered string or function after a plugin is
|
||||
// unloaded not quite as nice as I'd like.
|
||||
//
|
||||
// Console commands will print a message along the lines of:
|
||||
// [metamod: command '%s' unavailable; plugin unloaded]
|
||||
//
|
||||
// Cvars though, have their value unaffected. This can be convenient when
|
||||
// reloading a plugin, as the cvars keep their old values. However it can
|
||||
// also be confusing, as there is no indication when viewing/setting cvars
|
||||
// from the console that they no longer have an effect.
|
||||
//
|
||||
// Also note, the console commands for listing registered cmds and cvars
|
||||
// will try to show the name of the associated plugin. However, this only
|
||||
// works under linux; under windows it will say "(unknown)". Linux
|
||||
// provides a routine "dladdr()" which can indicate (during Reg request)
|
||||
// which plugin it's coming from, and this is stored with the cvar entry.
|
||||
// Windows didn't seem to have a similar routine, and I couldn't find
|
||||
// another way to get the information..
|
||||
|
||||
// Generic command handler, passed to the engine for any AddServerCommand
|
||||
// calls made by the plugin. It finds the appropriate plugin function
|
||||
// pointer to call based on CMD_ARGV(0).
|
||||
void EXT_FUNC meta_command_handler()
|
||||
{
|
||||
META_DEBUG(5, ("called: meta_command_handler; arg0=%s args='%s'", CMD_ARGV(0), CMD_ARGS()));
|
||||
const char *cmd = CMD_ARGV(0);
|
||||
if (!cmd)
|
||||
{
|
||||
META_ERROR("Null command name in meta_command_handler() ??");
|
||||
return;
|
||||
}
|
||||
|
||||
MRegCmd *icmd = g_regCmds->find(cmd);
|
||||
|
||||
if (!icmd)
|
||||
{
|
||||
META_ERROR("Couldn't find registered plugin command: %s", cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (icmd->call() != true)
|
||||
if (!icmd->call())
|
||||
{
|
||||
META_CONS("[metamod: command '%s' unavailable; plugin unloaded]", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Replacement for engine routine AddServerCommand; called by plugins.
|
||||
// Rather then handing the engine the plugin's command string and function
|
||||
// pointer (both of which are allocated in the plugin DLL), this hands the
|
||||
@ -85,11 +33,8 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
|
||||
META_DEBUG(4, ("called: meta_AddServerCommand; cmd_name=%s, function=%d", cmd_name, function));
|
||||
|
||||
// try to find which plugin is registering this command
|
||||
if (!iplug)
|
||||
{
|
||||
// if this isn't supported on this OS, don't log an error
|
||||
if (meta_errno != ME_OSNOTSUP)
|
||||
META_ERROR("Failed to find memloc for regcmd '%s'", cmd_name);
|
||||
if (!iplug) {
|
||||
META_ERROR("Failed to find memloc for regcmd '%s'", cmd_name);
|
||||
}
|
||||
|
||||
// See if this command was previously registered, ie a "reloaded" plugin.
|
||||
@ -97,25 +42,15 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
|
||||
if (!icmd)
|
||||
{
|
||||
// If not found, add.
|
||||
icmd = g_regCmds->add(cmd_name);
|
||||
icmd = g_regCmds->add(cmd_name, function, iplug);
|
||||
if (!icmd)
|
||||
{
|
||||
// error details logged in add()
|
||||
return;
|
||||
}
|
||||
|
||||
// Only register if not previously registered..
|
||||
REG_SVR_COMMAND(icmd->name, meta_command_handler);
|
||||
REG_SVR_COMMAND(icmd->getname(), meta_command_handler);
|
||||
}
|
||||
|
||||
icmd->pfnCmd = function;
|
||||
icmd->status = RG_VALID;
|
||||
// Store which plugin this is for, if we know. We can use '0' for
|
||||
// unknown plugin, since plugin index starts at 1.
|
||||
if (iplug)
|
||||
icmd->plugid = iplug->index;
|
||||
else
|
||||
icmd->plugid = 0;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user