2
0
mirror of https://github.com/rehlds/metamod-r.git synced 2025-01-27 22:17:54 +03:00

Finished rewriting of mreg code

Debug macro replaced to inline function
This commit is contained in:
asmodai 2017-01-09 01:30:23 +03:00
parent be24b08896
commit ccea6516cb
20 changed files with 472 additions and 500 deletions

View File

@ -1,5 +1,8 @@
#pragma once
#define MM_PRE_HOOK
#define MM_POST_HOOK
enum
{
P_PRE, // plugin function called before gamedll

View File

@ -315,6 +315,10 @@ void CSimpleJmp::naked_main()
}*/
}
CJit::CJit() : m_callback_allocator(static_allocator::mp_rwx), m_tramp_allocator(static_allocator::mp_rwx)
{
}
size_t CJit::compile_callback(jitdata_t* jitdata)
{
if (!is_hook_needed(jitdata)) {
@ -326,7 +330,7 @@ size_t CJit::compile_callback(jitdata_t* jitdata)
auto code = callback.GetCode();
auto codeSize = callback.GetCodeSize();
auto ptr = m_allocator.allocate(codeSize);
auto ptr = m_callback_allocator.allocate(codeSize);
return (size_t)memcpy(ptr, code, codeSize);
}
@ -338,14 +342,19 @@ size_t CJit::compile_tramp(size_t ptr_to_func/*, size_t hook, size_t hook_time*/
auto code = jmp.GetCode();
auto codeSize = jmp.GetCodeSize();
auto ptr = m_static_allocator.allocate(codeSize);
auto ptr = m_tramp_allocator.allocate(codeSize);
return (size_t)memcpy(ptr, code, codeSize);
}
void CJit::clear_callbacks()
{
m_allocator.deallocate_all();
m_callback_allocator.deallocate_all();
}
void CJit::clear_tramps()
{
m_tramp_allocator.deallocate_all();
}
bool CJit::is_hook_needed(jitdata_t* jitdata)

View File

@ -80,16 +80,18 @@ bool is_varargs(ret_t (*)(t_args..., ...))
class CJit
{
public:
CJit();
size_t compile_callback(jitdata_t* jitdata);
size_t compile_tramp(size_t ptr_to_func/*, size_t hook, size_t hook_time*/);
void clear_callbacks();
void clear_tramps();
private:
static bool is_hook_needed(jitdata_t* jitdata);
private:
execmem_allocator m_allocator;
execmem_allocator m_static_allocator;
static_allocator m_callback_allocator;
static_allocator m_tramp_allocator;
};
extern CJit g_jit;

View File

@ -54,7 +54,7 @@ bool MConfig::set(option_t* setp, const char* setstr)
return false;
}
*optval = Q_atoi(setstr);
META_DEBUG(3, ("set config int: %s = %d", setp->name, *optval));
META_DEBUG(3, "set config int: %s = %d", setp->name, *optval);
break;
case CF_BOOL:
if (is_yes(setstr))

View File

@ -12,17 +12,17 @@ NEW_DLL_FUNCTIONS sNewFunctionTable;
NEW_DLL_FUNCTIONS sNewFunctionTable_jit;
NEW_DLL_FUNCTIONS *pHookedNewDllFunctions = &sNewFunctionTable;
void mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] )
void MM_PRE_HOOK EXT_FUNC mm_ClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128] )
{
g_players.clear_player_cvar_query(pEntity);
}
void mm_ClientDisconnect(edict_t *pEntity)
void MM_PRE_HOOK EXT_FUNC mm_ClientDisconnect(edict_t *pEntity)
{
g_players.clear_player_cvar_query(pEntity);
}
void mm_ClientCommand(edict_t *pEntity)
void MM_PRE_HOOK mm_ClientCommand(edict_t *pEntity)
{
if (!strcmp(CMD_ARGV(0), "meta")) {
client_meta(pEntity);
@ -147,7 +147,7 @@ compile_data_t g_newdllfunc_cdata[] =
// GetAPI or not..
C_DLLEXPORT int GetEntityAPI(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion)
{
META_DEBUG(3, ("called: GetEntityAPI; version=%d", interfaceVersion));
META_DEBUG(3, "called: GetEntityAPI; version=%d", interfaceVersion);
if (!pFunctionTable)
{
META_ERROR("GetEntityAPI called with null pFunctionTable");
@ -165,7 +165,7 @@ C_DLLEXPORT int GetEntityAPI(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion
C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion)
{
META_DEBUG(3, ("called: GetEntityAPI2; version=%d", *interfaceVersion));
META_DEBUG(3, "called: GetEntityAPI2; version=%d", *interfaceVersion);
if (!pFunctionTable)
{
@ -186,7 +186,7 @@ C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersi
C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion)
{
META_DEBUG(6, ("called: GetNewDLLFunctions; version=%d", *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

View File

@ -3,28 +3,28 @@
#define CDATA_ENG_H(x, p, h) CDATA_ENTRY(enginefuncs_t, x, p, size_t(h))
#define CDATA_ENG(x) CDATA_ENTRY(enginefuncs_t, x, P_PRE, 0u)
meta_enginefuncs_t meta_engfuncs; // static addresses for gamedll
meta_enginefuncs_t meta_engfuncs; // static trampolines to dynamic callbacks (for gamedll)
meta_enginefuncs_t meta_engfuncs_jit; // dynamic jit callbacks
void mm_QueryClientCvarValue(const edict_t* pEdict, const char* cvarName)
void MM_PRE_HOOK mm_QueryClientCvarValue(const edict_t* pEdict, const char* cvarName)
{
g_players.set_player_cvar_query(pEdict, cvarName);
}
// int -> void
void mm_RegUserMsg(const char* pszName, int iSize)
void MM_POST_HOOK mm_RegUserMsg(const char* pszName, int iSize)
{
// Add the msgid, name, and size to our saved list, if we haven't already.
auto imsgid = *(int *)(g_metaGlobals.status == MRES_OVERRIDE ? g_metaGlobals.override_ret : g_metaGlobals.orig_ret);
auto nmsg = g_regMsgs->find(imsgid);
if (nmsg) {
if (!strcmp(pszName, nmsg->name))
if (!Q_strcmp(pszName, nmsg->getname()))
// This name/msgid pair was already registered.
META_DEBUG(3, ("user message registered again: name=%s, msgid=%d", pszName, imsgid));
META_DEBUG(3, "user message registered again: name=%s, msgid=%d", pszName, imsgid);
else
// This msgid was previously used by a different message name.
META_ERROR("user message id reused: msgid=%d, oldname=%s, newname=%s", imsgid, nmsg->name, pszName);
META_ERROR("user message id reused: msgid=%d, oldname=%s, newname=%s", imsgid, nmsg->getname(), pszName);
}
else
g_regMsgs->add(pszName, imsgid, iSize);

View File

@ -11,11 +11,11 @@
extern cvar_t meta_debug;
template<typename ...t_args>
void META_DEBUG(int level, t_args... args)
void META_DEBUG(int level, const char* fmt, t_args... args)
{
if (meta_debug.value < level)
return;
ALERT(at_logged, "[META] (debug:%i) %s\n", level, args...);
ALERT(at_logged, "[META] (debug:%i) %s\n", level, args...); // TODO
}
void META_CONS(const char *fmt, ...);

View File

@ -391,11 +391,11 @@ bool MPluginList::ini_startup()
{
if (pmatch->pfspecific >= plist[n].pfspecific)
{
META_DEBUG(1, ("ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, inifile, pmatch->pfspecific, plist[n].pfspecific));
META_DEBUG(1, "ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, inifile, pmatch->pfspecific, plist[n].pfspecific);
continue;
}
META_DEBUG(1, ("ini: Plugin in line %d overrides existing plugin with lower platform specific level %d, ours %d", ln, pmatch->pfspecific, plist[n].pfspecific));
META_DEBUG(1, "ini: Plugin in line %d overrides existing plugin with lower platform specific level %d, ours %d", ln, pmatch->pfspecific, plist[n].pfspecific);
int _index = pmatch->index;
Q_memset(pmatch, 0, sizeof(MPlugin));
pmatch->index = _index;
@ -462,19 +462,19 @@ bool MPluginList::ini_refresh()
{
if (pl_found->pfspecific >= pl_temp.pfspecific)
{
META_DEBUG(1, ("ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, inifile, pl_found->pfspecific, pl_temp.pfspecific));
META_DEBUG(1, "ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, inifile, pl_found->pfspecific, pl_temp.pfspecific);
continue;
}
if (PA_LOAD == pl_found->action)
{
META_DEBUG(1, ("ini: Plugin in line %d overrides loading of plugin with lower platform specific level %d, ours %d", ln, pl_found->pfspecific, pl_temp.pfspecific));
META_DEBUG(1, "ini: Plugin in line %d overrides loading of plugin with lower platform specific level %d, ours %d", ln, pl_found->pfspecific, pl_temp.pfspecific);
int _index = pl_found->index;
Q_memset(pl_found, 0, sizeof(MPlugin));
pl_found->index = _index;
}
else
{
META_DEBUG(1, ("ini: Plugin in line %d should override existing plugin with lower platform specific level %d, ours %d. Unable to comply.", ln, pl_found->pfspecific, pl_temp.pfspecific));
META_DEBUG(1, "ini: Plugin in line %d should override existing plugin with lower platform specific level %d, ours %d. Unable to comply.", ln, pl_found->pfspecific, pl_temp.pfspecific);
continue;
}
}

View File

@ -946,7 +946,8 @@ bool MPlugin::attach(PLUG_LOADTIME now)
if (!engine_table) engine_table = (meta_enginefuncs_t *)calloc(1, sizeof(meta_enginefuncs_t));
if (meta_table.pfnGetEngineFunctions(engine_table, &iface_vers)) {
do {
if (meta_debug.value < 3) break; else (*g_engfuncs.pfnAlertMessage)(at_logged, "[META] (debug:%d) %s\n", 3, UTIL_VarArgs("dll: Plugin '%s': Found %s", desc, "GetEngineFunctions"));
if (meta_debug.value < 3) break;
else (*g_engfuncs.pfnAlertMessage)(at_logged, "[META] (debug:%d) %s\n", 3, UTIL_VarArgs("dll: Plugin '%s': Found %s", desc, "GetEngineFunctions"));
}
while (0);
}
@ -1412,7 +1413,7 @@ bool MPlugin::newer_file()
return false;
file_time = st.st_ctime > st.st_mtime ? st.st_ctime : st.st_mtime;
META_DEBUG(5, ("newer_file? file=%s; load=%d, file=%d; ctime=%d, mtime=%d", file, time_loaded, file_time, st.st_ctime, st.st_mtime));
META_DEBUG(5, "newer_file? file=%s; load=%d, file=%d; ctime=%d, mtime=%d", file, time_loaded, file_time, st.st_ctime, st.st_mtime);
if (file_time > time_loaded)
return true;
else

View File

@ -1,26 +1,31 @@
#include "precompiled.h"
MRegCmd::MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin) : pfnCmd(cmd_handler), status(RG_VALID), plugid(cmd_plugin->index)
MRegCmd::MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin) : m_pfunction(cmd_handler), m_status(RG_VALID), m_plugid(cmd_plugin->index)
{
name = _strdup(name);
m_name = _strdup(m_name);
}
bool MRegCmd::call() const
{
pfnCmd();
return status != RG_INVALID;
m_pfunction();
return m_status != RG_INVALID;
}
void MRegCmd::disable()
{
pfnCmd = [](){};
plugid = 0;
status = RG_INVALID;
m_pfunction = [](){};
m_plugid = 0;
m_status = RG_INVALID;
}
char* MRegCmd::getname() const
{
return name;
return m_name;
}
REG_CMD_FN MRegCmd::gethandler() const
{
return m_pfunction;
}
MRegCmdList::MRegCmdList() : m_list()
@ -29,10 +34,10 @@ MRegCmdList::MRegCmdList() : m_list()
MRegCmd *MRegCmdList::find(const char *name) const
{
for (auto icmd : m_list)
for (auto reg : m_list)
{
if (!Q_stricmp(icmd->name, name))
return icmd;
if (!Q_stricmp(reg->m_name, name))
return reg;
}
return nullptr;
@ -40,23 +45,23 @@ MRegCmd *MRegCmdList::find(const char *name) const
MRegCmd *MRegCmdList::add(char *addname, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin)
{
auto icmd = new MRegCmd(addname, cmd_handler, cmd_plugin);
m_list.push_back(icmd);
return icmd;
auto reg = new MRegCmd(addname, cmd_handler, cmd_plugin);
m_list.push_back(reg);
return reg;
}
void MRegCmdList::remove(char* cmd_name)
{
for (auto it = m_list.begin(), end = m_list.end(); it != end; ++it) {
auto icmd = *it;
auto reg = *it;
if (!Q_stricmp(icmd->name, cmd_name)) {
if (!Q_stricmp(reg->m_name, cmd_name)) {
if (g_RehldsFuncs) {
g_RehldsFuncs->Cmd_RemoveCmd(cmd_name);
m_list.erase(it);
}
else {
icmd->disable();
reg->disable();
}
}
}
@ -66,15 +71,15 @@ void MRegCmdList::remove(char* cmd_name)
void MRegCmdList::remove(int owner_plugin_id)
{
for (auto it = m_list.begin(), end = m_list.end(); it != end; ++it) {
auto icmd = *it;
auto reg = *it;
if (icmd->plugid == owner_plugin_id) {
if (reg->m_plugid == owner_plugin_id) {
if (g_RehldsFuncs) {
g_RehldsFuncs->Cmd_RemoveCmd(icmd->name);
g_RehldsFuncs->Cmd_RemoveCmd(reg->m_name);
m_list.erase(it);
}
else {
icmd->disable();
reg->disable();
}
}
}
@ -83,17 +88,17 @@ void MRegCmdList::remove(int owner_plugin_id)
// List all the registered commands.
void MRegCmdList::show() const
{
int n = 0, a = 0;
int total_count = 0, valid_count = 0;
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 (auto icmd : m_list)
for (auto reg : m_list)
{
if (icmd->status == RG_VALID)
if (reg->m_status == RG_VALID)
{
auto iplug = g_plugins->find(icmd->plugid);
auto iplug = g_plugins->find(reg->m_plugid);
Q_strncpy(bplug, iplug ? iplug->desc : "(unknown)", sizeof bplug - 1);
bplug[sizeof bplug - 1] = '\0';
@ -104,136 +109,67 @@ void MRegCmdList::show() const
bplug[sizeof bplug - 1] = '\0';
}
META_CONS(" [%*d] %-*s %-s", WIDTH_MAX_REG, ++n, sizeof bplug - 1, bplug, icmd->name);
META_CONS(" [%*d] %-*s %-s", WIDTH_MAX_REG, ++total_count, sizeof bplug - 1, bplug, reg->m_name);
if (icmd->status == RG_VALID)
a++;
if (reg->m_status == RG_VALID)
valid_count++;
}
META_CONS("%d commands, %d available", n, a);
META_CONS("%d commands, %d available", total_count, valid_count);
}
// List all the registered commands for the given plugin id.
void MRegCmdList::show(int plugin_id) const
{
int n = 0;
int total_count = 0;
META_CONS("Registered commands:");
for (auto icmd : m_list)
for (auto reg : m_list)
{
if (icmd->plugid != plugin_id)
if (reg->m_plugid != plugin_id)
continue;
META_CONS(" %s", icmd->name);
n++;
META_CONS(" %s", reg->m_name);
total_count++;
}
META_CONS("%d commands", n);
META_CONS("%d commands", total_count);
}
// Init values. It would probably be more "proper" to use containers and
// constructors, rather than arrays and init-functions.
void MRegCvar::init(int idx)
MRegCvar::MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin) : m_cvar(cv_ptr), m_plugid(cv_plugin->index), m_status(RG_VALID)
{
index = idx;
data = NULL;
plugid = 0;
status = RG_INVALID;
m_cvar = g_static_allocator.allocate<cvar_t>();
m_cvar->name = _strdup(cv_ptr->name);
m_cvar->string = _strdup(cv_ptr->string);
m_cvar->flags = cv_ptr->flags;
m_cvar->value = cv_ptr->value;
m_cvar->next = cv_ptr->next;
}
// Set the cvar, copying values from given cvar.
// meta_errno values:
// - ME_ARGUMENT given cvar doesn't match this cvar
bool MRegCvar::set(cvar_t *src) const
cvar_t* MRegCvar::getcvar() const
{
if (Q_stricmp(src->name, data->name))
{
META_ERROR("Tried to set cvar with mismatched name; src=%s dst=%s", src->name, data->name);
return false;
}
// Would like to free() existing string, but can't tell where it was
// allocated...
data->string = Q_strdup(src->string);
data->flags = src->flags;
data->value = src->value;
data->next = src->next;
return true;
return m_cvar;
}
// Constructor
MRegCvarList::MRegCvarList()
: vlist(0), size(REG_CVAR_GROWSIZE), endlist(0)
MRegCvarList::MRegCvarList() : m_list()
{
vlist = (MRegCvar *)Q_malloc(size * sizeof(MRegCvar));
// initialize array
for (int i = 0; i < size; i++)
vlist[i].init(i + 1); // 1 - based
endlist = 0;
}
// Add the given cvar name to the list and return the instance. This only
// writes the "name" to the new cvar; other fields are written with
// cvar::set().
// meta_errno values:
// - ME_NOMEM couldn't alloc or realloc for various parts
MRegCvar *MRegCvarList::add(const char *addname)
MRegCvar *MRegCvarList::add(cvar_t* src, MPlugin* plugin)
{
MRegCvar *icvar;
if (endlist == size)
{
// grow array
int newsize = size + REG_CVAR_GROWSIZE;
META_DEBUG(6, ("Growing reg cvar list from %d to %d", size, newsize));
MRegCvar *temp = (MRegCvar *) realloc(vlist, newsize * sizeof(MRegCvar));
if (!temp)
{
META_ERROR("Couldn't grow registered cvar list to %d for '%s'; %s", newsize, addname, strerror(errno));
return NULL;
}
vlist = temp;
size = newsize;
// initialize new (unused) entries
for (int i = endlist; i < size; i++)
vlist[i].init(i + 1); // 1-based
}
icvar = &vlist[endlist];
// Malloc space for the cvar and cvar name, for two reasons:
// - Can't point to memory loc in plugin (another segv waiting to
// happen).
// - Can't point to memory in vlist which might get moved later by
// realloc (again, segv).
icvar->data = (cvar_t *)Q_malloc(sizeof(cvar_t));
if (!icvar->data)
{
META_ERROR("Couldn't malloc cvar for adding reg cvar name '%s': %s", addname, strerror(errno));
return NULL;
}
icvar->data->name = Q_strdup(addname);
if (!icvar->data->name)
{
META_ERROR("Couldn't Q_strdup for adding reg cvar name '%s': %s", addname, strerror(errno));
return NULL;
}
endlist++;
return icvar;
MRegCvar *reg_cvar = new(g_static_allocator.allocate<MRegCvar>()) MRegCvar(src, plugin);
m_list.push_back(reg_cvar);
return reg_cvar;
}
// Try to find a registered cvar with the given name.
// meta_errno values:
// - ME_NOTFOUND couldn't find a matching cvar
MRegCvar *MRegCvarList::find(const char *findname)
{
for (int i = 0; i < endlist; i++)
for (auto reg : m_list)
{
if (!_stricmp(vlist[i].data->name, findname))
return &vlist[i];
if (!Q_stricmp(reg->m_cvar->name, findname))
return reg;
}
return NULL;
@ -242,18 +178,12 @@ MRegCvar *MRegCvarList::find(const char *findname)
// Disable any cvars belonging to the given plugin (by index id).
void MRegCvarList::disable(int plugin_id) const
{
int i;
MRegCvar *icvar;
for (i = 0; i < size; i++)
for (auto reg : m_list)
{
icvar = &vlist[i];
if (icvar->plugid == plugin_id)
if (reg->m_plugid == plugin_id)
{
icvar->status = RG_INVALID;
icvar->plugid = 0;
// Decided not to do this, in order to keep pre-existing values
// after a plugin reload.
// CVAR_SET_STRING(icvar->data->name, "[metamod: cvar invalid; plugin unloaded]");
reg->m_status = RG_INVALID;
reg->m_plugid = 0;
}
}
}
@ -261,29 +191,19 @@ void MRegCvarList::disable(int plugin_id) const
// List all the registered cvars.
void MRegCvarList::show() const
{
int i, n = 0, a = 0;
MRegCvar *icvar;
MPlugin *iplug;
int total_count = 0, valid_count = 0;
char bplug[13 + 1], bname[20 + 1], bval[15 + 1]; // +1 for term null
META_CONS("Registered plugin cvars:");
META_CONS(" %*s %-*s %-*s %*s %s", WIDTH_MAX_REG, "", sizeof(bplug) - 1, "plugin", sizeof(bname) - 1, "cvar", sizeof(bval) - 1, "float value", "string value");
for (i = 0; i < endlist; i++)
META_CONS(" %*s %-*s %-*s %*s %s", WIDTH_MAX_REG, "", sizeof bplug - 1, "plugin", sizeof bname - 1, "cvar", sizeof bval - 1, "float value", "string value");
for (auto reg : m_list)
{
icvar = &vlist[i];
if (icvar->status == RG_VALID)
if (reg->m_status == RG_VALID)
{
iplug = g_plugins->find(icvar->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 plug = g_plugins->find(reg->m_plugid);
Q_strncpy(bplug, plug ? plug->desc : "(unknown)", sizeof bplug - 1);
bplug[sizeof bplug - 1] = '\0';
}
else
{
@ -291,127 +211,110 @@ void MRegCvarList::show() const
bplug[sizeof bplug - 1] = '\0';
}
Q_strncpy(bname, icvar->data->name, sizeof bname - 1);
Q_strncpy(bname, reg->m_cvar->name, sizeof bname - 1);
bname[sizeof bname - 1] = '\0';
Q_snprintf(bval, sizeof(bval), "%f", icvar->data->value);
META_CONS(" [%*d] %-*s %-*s %*s %s", WIDTH_MAX_REG, icvar->index, sizeof(bplug) - 1, bplug, sizeof(bname) - 1, bname, sizeof(bval) - 1, bval, icvar->data->string);
Q_snprintf(bval, sizeof bval, "%f", reg->m_cvar->value);
META_CONS(" [%*d] %-*s %-*s %*s %s", WIDTH_MAX_REG, ++total_count, sizeof bplug - 1, bplug, sizeof bname - 1, bname, sizeof bval - 1, bval, reg->m_cvar->string);
if (icvar->status == RG_VALID)
a++;
n++;
if (reg->m_status == RG_VALID)
valid_count++;
}
META_CONS("%d cvars, %d available (%d allocated)", n, a, size);
META_CONS("%d cvars, %d available", total_count, valid_count);
}
// List the registered cvars for the given plugin id.
void MRegCvarList::show(int plugin_id) const
{
int n = 0;
MRegCvar *icvar;
int total_count = 0;
char bname[30 + 1], bval[15 + 1]; // +1 for term null
META_CONS("%-*s %*s %s", sizeof(bname) - 1, "Registered cvars:", sizeof(bval) - 1, "float value", "string value");
for (int i = 0; i < endlist; i++)
META_CONS("%-*s %*s %s", sizeof(bname) - 1, "Registered cvars:", sizeof bval - 1, "float value", "string value");
for (auto reg : m_list)
{
icvar = &vlist[i];
if (icvar->plugid != plugin_id)
if (reg->m_plugid != plugin_id)
continue;
Q_strncpy(bname, icvar->data->name, sizeof bname - 1);
Q_strncpy(bname, reg->m_cvar->name, sizeof bname - 1);
bname[sizeof bname - 1] = '\0';
Q_snprintf(bval, sizeof(bval), "%f", icvar->data->value);
META_CONS(" %-*s %*s %s", sizeof(bname) - 1, bname, sizeof(bval) - 1, bval, icvar->data->string);
n++;
Q_snprintf(bval, sizeof(bval), "%f", reg->m_cvar->value);
META_CONS(" %-*s %*s %s", sizeof(bname) - 1, bname, sizeof(bval) - 1, bval, reg->m_cvar->string);
total_count++;
}
META_CONS("%d cvars", n);
META_CONS("%d cvars", total_count);
}
// Constructor
MRegMsgList::MRegMsgList()
: size(MAX_REG_MSGS), endlist(0)
MRegMsg::MRegMsg(const char* name, int msgid, int size) : m_name(name), m_msgid(msgid), m_size(size)
{
// initialize array
Q_memset(mlist, 0, sizeof(mlist));
for (int i = 0; i < size; i++)
{
mlist[i].index = i + 1; // 1-based
}
endlist = 0;
}
// Add the given user msg the list and return the instance.
// meta_errno values:
// - ME_MAXREACHED reached max number of msgs allowed
const char* MRegMsg::getname() const
{
return m_name;
}
int MRegMsg::getid() const
{
return m_msgid;
}
int MRegMsg::getsize() const
{
return m_size;
}
MRegMsgList::MRegMsgList() : m_list()
{
}
MRegMsg *MRegMsgList::add(const char *addname, int addmsgid, int addsize)
{
if (endlist == size)
{
// all slots used
META_ERROR("Couldn't add registered msg '%s' to list; reached max msgs (%d)", addname, size);
return NULL;
}
MRegMsg *imsg = &mlist[endlist];
endlist++;
// Copy msg data into empty slot.
// Note: 'addname' assumed to be a constant string allocated in the
// gamedll.
imsg->name = addname;
imsg->msgid = addmsgid;
imsg->size = addsize;
return imsg;
auto msg = new(g_static_allocator.allocate<MRegMsg>()) MRegMsg(addname, addmsgid, addsize);
m_list.push_back(msg);
return msg;
}
// Try to find a registered msg with the given name.
// meta_errno values:
// - ME_NOTFOUND couldn't find a matching cvar
MRegMsg *MRegMsgList::find(const char *findname)
{
for (int i = 0; i < endlist; i++)
for (auto msg : m_list)
{
if (!Q_strcmp(mlist[i].name, findname))
return &mlist[i];
if (!Q_strcmp(msg->m_name, findname))
return msg;
}
return NULL;
return nullptr;
}
// Try to find a registered msg with the given msgid.
// meta_errno values:
// - ME_NOTFOUND couldn't find a matching cvar
MRegMsg *MRegMsgList::find(int findmsgid)
{
for (int i = 0; i < endlist; i++)
{
if (mlist[i].msgid == findmsgid)
return &mlist[i];
for (auto msg : m_list) {
if (msg->m_msgid == findmsgid)
return msg;
}
return NULL;
return nullptr;
}
// List the registered usermsgs for the gamedll.
void MRegMsgList::show()
{
int i, n = 0;
MRegMsg *imsg;
int total_count = 0;
char bname[25 + 1]; // +1 for term null
META_CONS("%-*s %5s %5s", sizeof(bname) - 1, "Game registered user msgs:", "msgid", "size");
for (i = 0; i < endlist; i++)
{
imsg = &mlist[i];
Q_strncpy(bname, imsg->name, sizeof bname - 1);
for (auto msg : m_list) {
Q_strncpy(bname, msg->m_name, sizeof bname - 1);
bname[sizeof bname - 1] = '\0';
META_CONS(" %-*s %3d %3d", sizeof(bname) - 1, bname, imsg->msgid, imsg->size);
n++;
META_CONS(" %-*s %3d %3d", sizeof(bname) - 1, bname, msg->m_msgid, msg->m_size);
total_count++;
}
META_CONS("%d game user msgs", n);
META_CONS("%d game user msgs", total_count);
}

View File

@ -1,10 +1,4 @@
#pragma once
#include "types_meta.h" // bool
// Number of entries to add to reglists when they need to grow. Typically
// more cvars than commands, so we grow them at different increments.
#define REG_CMD_GROWSIZE 32
#define REG_CVAR_GROWSIZE 64
// Width required to printf a Reg*List index number, for show() functions.
// This used to correspond to the number of digits in MAX_REG, which was a
@ -27,101 +21,97 @@ typedef void (*REG_CMD_FN)();
class MPlugin;
// An individual registered function/command.
class MRegCmd {
class MRegCmd
{
public:
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;
REG_CMD_FN gethandler() 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
char* m_name; // space is malloc'd
REG_CMD_FN m_pfunction; // pointer to the function
int m_plugid; // index id of corresponding plugin
REG_STATUS m_status; // whether corresponding plugin is loaded
friend class MRegCmdList;
};
// A list of registered commands.
class MRegCmdList {
class MRegCmdList
{
public:
MRegCmdList();
MRegCmd *find(const char *name) const; // find by MRegCmd->name
MRegCmd *find(const char *name) const;
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
void remove(int owner_plugin_id);
void show() const;
void show(int plugin_id) const;
private:
std::vector<MRegCmd *> m_list;
};
// An individual registered cvar.
class MRegCvar {
class MRegCvar
{
public:
friend class MRegCvarList;
cvar_t *data; // actual cvar structure, malloc'd
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 set(cvar_t *src) const;
MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin);
cvar_t* getcvar() const;
private:
int index; // 1-based
cvar_t* m_cvar;
int m_plugid;
REG_STATUS m_status;
friend class MRegCvarList;
};
// A list of registered cvars.
class MRegCvarList {
class MRegCvarList
{
public:
MRegCvarList();
MRegCvar *add(const char *addname);
MRegCvar *add(cvar_t* src, MPlugin* plugin);
MRegCvar *find(const char *findname); // find by MRegCvar->data.name
void disable(int plugin_id) const; // change status to Invalid
void show() const; // list all cvars to console
void show(int plugin_id) const; // list given plugin's cvars to console
private:
MRegCvar *vlist; // malloc'd array of registered cvars
int size; // size of list, ie MAX_REG_CVARS
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 MRegCvarList &src);
MRegCvarList(const MRegCvarList &src);
std::vector<MRegCvar *> m_list;
};
// An individual registered user msg, from gamedll.
class MRegMsg {
class MRegMsg
{
public:
friend class MRegMsgList;
const char *name; // name, assumed constant string in gamedll
int msgid; // msgid, assigned by engine
int size; // size, if given by gamedll
MRegMsg(const char* name, int msgid, int size);
const char* getname() const;
int getid() const;
int getsize() const;
private:
int index; // 1-based
const char* m_name;
int m_msgid;
int m_size;
friend class MRegMsgList;
};
// A list of registered user msgs.
class MRegMsgList {
class MRegMsgList
{
public:
MRegMsgList();
MRegMsg *add(const char *addname, int addmsgid, int addsize);
MRegMsg *find(const char *findname);
MRegMsg *find(int findmsgid);
void show(); // list all msgs to console
void show();
private:
MRegMsg mlist[MAX_REG_MSGS]; // array of registered msgs
int size; // size of list, ie MAX_REG_MSGS
int endlist; // index of last used entry
std::vector<MRegMsg *> m_list;
};

View File

@ -1,6 +1,6 @@
#include "precompiled.h"
hudtextparms_t default_csay_tparms = {
static hudtextparms_t g_default_csay_tparms = {
-1, 0.25, // x, y
2, // effect
0, 255, 0, 0, // r, g, b, a1
@ -9,23 +9,81 @@ hudtextparms_t default_csay_tparms = {
1 // channel
};
static const char* g_engine_msg_names[] =
{
"svc_bad",
"svc_nop",
"svc_disconnect",
"svc_event",
"svc_version",
"svc_setview",
"svc_sound",
"svc_time",
"svc_print",
"svc_stufftext",
"svc_setangle",
"svc_serverinfo",
"svc_lightstyle",
"svc_updateuserinfo",
"svc_deltadescription",
"svc_clientdata",
"svc_stopsound",
"svc_pings",
"svc_particle",
"svc_damage",
"svc_spawnstatic",
"svc_event_reliable",
"svc_spawnbaseline",
"svc_temp_entity",
"svc_setpause",
"svc_signonnum",
"svc_centerprint",
"svc_killedmonster",
"svc_foundsecret",
"svc_spawnstaticsound",
"svc_intermission",
"svc_finale",
"svc_cdtrack",
"svc_restore",
"svc_cutscene",
"svc_weaponanim",
"svc_decalname",
"svc_roomtype",
"svc_addangle",
"svc_newusermsg",
"svc_packetentities",
"svc_deltapacketentities",
"svc_choke",
"svc_resourcelist",
"svc_newmovevars",
"svc_resourcerequest",
"svc_customization",
"svc_crosshairangle",
"svc_soundfade",
"svc_filetxferfailed",
"svc_hltv",
"svc_director",
"svc_voiceinit",
"svc_voicedata",
"svc_sendextrainfo",
"svc_timescale",
"svc_resourcelocation",
"svc_sendcvarvalue",
"svc_sendcvarvalue2"
};
// Log to console; newline added.
void EXT_FUNC mutil_LogConsole(plid_t plid, const char *fmt, ...)
{
va_list ap;
char buf[MAX_LOGMSG_LEN];
unsigned int len;
va_list ap;
va_start(ap, fmt);
Q_vsnprintf(buf, sizeof(buf), fmt, ap);
size_t len = Q_vsnprintf(buf, sizeof buf - 1, fmt, ap);
va_end(ap);
// end msg with newline
len = Q_strlen(buf);
if (len < sizeof(buf) - 2) // -1 null, -1 for newline
Q_strcat(buf, "\n");
else
buf[len - 1] = '\n';
buf[len] = '\n';
buf[len + 1] = '\0';
SERVER_PRINT(buf);
}
@ -33,44 +91,43 @@ void EXT_FUNC mutil_LogConsole(plid_t plid, const char *fmt, ...)
// Log regular message to logs; newline added.
void EXT_FUNC mutil_LogMessage(plid_t plid, const char *fmt, ...)
{
va_list ap;
char buf[MAX_LOGMSG_LEN];
plugin_info_t *plinfo = (plugin_info_t *)plid;
va_list ap;
va_start(ap, fmt);
Q_vsnprintf(buf, sizeof(buf), fmt, ap);
Q_vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
ALERT(at_logged, "[%s] %s\n", plinfo->logtag, buf);
ALERT(at_logged, "[%s] %s\n", plid->logtag, buf);
}
// Log an error message to logs; newline added.
void EXT_FUNC mutil_LogError(plid_t plid, const char *fmt, ...)
{
va_list ap;
char buf[MAX_LOGMSG_LEN];
plugin_info_t *plinfo = (plugin_info_t *)plid;
va_list ap;
va_start(ap, fmt);
Q_vsnprintf(buf, sizeof(buf), fmt, ap);
Q_vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
ALERT(at_logged, "[%s] ERROR: %s\n", plinfo->logtag, buf);
ALERT(at_logged, "[%s] ERROR: %s\n", plid->logtag, buf);
}
// Log a message only if cvar "developer" set; newline added.
void EXT_FUNC mutil_LogDeveloper(plid_t plid, const char* fmt, ...)
{
va_list ap;
char buf[MAX_LOGMSG_LEN];
plugin_info_t* plinfo;
if ((int) CVAR_GET_FLOAT("developer") == 0)
if ((int)CVAR_GET_FLOAT("developer") == 0)
return;
plinfo = (plugin_info_t *)plid;
va_list ap;
va_start(ap, fmt);
Q_vsnprintf(buf, sizeof(buf), fmt, ap);
Q_vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
ALERT(at_logged, "[%s] dev: %s\n", plinfo->logtag, buf);
ALERT(at_logged, "[%s] dev: %s\n", plid->logtag, buf);
}
// Print message on center of all player's screens. Uses default text
@ -79,7 +136,7 @@ void EXT_FUNC mutil_CenterSay(plid_t plid, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
mutil_CenterSayVarargs(plid, default_csay_tparms, fmt, ap);
mutil_CenterSayVarargs(plid, g_default_csay_tparms, fmt, ap);
va_end(ap);
}
@ -97,18 +154,18 @@ void EXT_FUNC mutil_CenterSayParms(plid_t plid, hudtextparms_t tparms, const cha
void EXT_FUNC mutil_CenterSayVarargs(plid_t plid, hudtextparms_t tparms, const char* fmt, va_list ap)
{
char buf[MAX_LOGMSG_LEN];
int n;
edict_t *pEntity;
Q_vsnprintf(buf, sizeof(buf), fmt, ap);
Q_vsnprintf(buf, sizeof buf, fmt, ap);
mutil_LogMessage(plid, "(centersay) %s", buf);
for (n = 1; n <= gpGlobals->maxClients; n++)
for (int n = 1; n <= gpGlobals->maxClients; n++)
{
pEntity = INDEXENT(n);
auto pEntity = INDEXENT(n);
if (FNullEnt(pEntity) || pEntity->free)
continue;
//META_UTIL_HudMessage(pEntity, tparms, buf); // TODO
UTIL_HudMessage(pEntity, tparms, buf);
}
}
@ -117,16 +174,16 @@ void EXT_FUNC mutil_CenterSayVarargs(plid_t plid, hudtextparms_t tparms, const c
// Jussi Kivilinna.
qboolean EXT_FUNC mutil_CallGameEntity(plid_t plid, const char *entStr, entvars_t *pev)
{
plugin_info_t *plinfo = (plugin_info_t *)plid;
META_DEBUG(8, ("Looking up game entity '%s' for plugin '%s'", entStr, plinfo->name));
META_DEBUG(8, ("Looking up game entity '%s' for plugin '%s'", entStr, plid->name));
ENTITY_FN pfnEntity = (ENTITY_FN)GameDLL.sys_module.getsym(entStr);
if (!pfnEntity)
{
META_ERROR("Couldn't find game entity '%s' in game DLL '%s' for plugin '%s'", entStr, GameDLL.name, plinfo->name);
META_ERROR("Couldn't find game entity '%s' in game DLL '%s' for plugin '%s'", entStr, GameDLL.name, plid->name);
return false;
}
META_DEBUG(7, ("Calling game entity '%s' for plugin '%s'", entStr, plinfo->name));
META_DEBUG(7, ("Calling game entity '%s' for plugin '%s'", entStr, plid->name));
(*pfnEntity)(pev);
return true;
}
@ -135,18 +192,24 @@ qboolean EXT_FUNC mutil_CallGameEntity(plid_t plid, const char *entStr, entvars_
// msgname, and return remaining info about it (msgid, size).
int EXT_FUNC mutil_GetUserMsgID(plid_t plid, const char* msgname, int* size)
{
plugin_info_t *plinfo = (plugin_info_t *)plid;
META_DEBUG(8, ("Looking up usermsg name '%s' for plugin '%s'", msgname, plinfo->name));
META_DEBUG(8, "Looking up usermsg name '%s' for plugin '%s'", msgname, plid->name);
MRegMsg *umsg = g_regMsgs->find(msgname);
if (umsg)
{
if (size)
*size = umsg->size;
return umsg->msgid;
if (size) *size = umsg->getsize();
return umsg->getid();
}
else
return 0;
for (int n = 1; n < arraysize(g_engine_msg_names); n++) {
if (!strcmp(msgname, g_engine_msg_names[n])) {
if (size) *size = -1;
return n;
}
}
return 0;
}
// Find a usermsg, registered by the gamedll, with the corresponding
@ -154,59 +217,39 @@ int EXT_FUNC mutil_GetUserMsgID(plid_t plid, const char* msgname, int* size)
const char* EXT_FUNC mutil_GetUserMsgName(plid_t plid, int msgid, int *size)
{
plugin_info_t *plinfo = (plugin_info_t *)plid;
META_DEBUG(8, ("Looking up usermsg id '%d' for plugin '%s'", msgid, plinfo->name));
META_DEBUG(8, "Looking up usermsg id '%d' for plugin '%s'", msgid, plinfo->name);
// Guess names for any built-in g_engine messages mentioned in the SDK;
// from dlls/util.h.
if (msgid < 64)
if (msgid < arraysize(g_engine_msg_names))
{
switch (msgid)
{
case SVC_TEMPENTITY:
if (size) *size = -1;
return "tempentity?";
case SVC_INTERMISSION:
if (size) *size = -1;
return "intermission?";
case SVC_CDTRACK:
if (size) *size = -1;
return "cdtrack?";
case SVC_WEAPONANIM:
if (size) *size = -1;
return "weaponanim?";
case SVC_ROOMTYPE:
if (size) *size = -1;
return "roomtype?";
case SVC_DIRECTOR:
if (size) *size = -1;
return "director?";
}
if (size) *size = -1;
return g_engine_msg_names[msgid];
}
MRegMsg *umsg = g_regMsgs->find(msgid);
if (umsg)
{
if (size)
*size = umsg->size;
if (size) *size = umsg->getsize();
// 'name' is assumed to be a constant string, allocated in the
// gamedll.
return umsg->name;
return umsg->getname();
}
else
return NULL;
return nullptr;
}
// Return the full path of the plugin's loaded dll/so file.
const char* EXT_FUNC mutil_GetPluginPath(plid_t plid)
{
static char buf[PATH_MAX ];
MPlugin *plug;
static char buf[PATH_MAX];
plug = g_plugins->find(plid);
auto plug = g_plugins->find(plid);
if (!plug)
{
META_ERROR("GetPluginPath: couldn't find plugin '%s'", plid->name);
return NULL;
return nullptr;
}
Q_strncpy(buf, plug->pathname, sizeof buf - 1);
@ -219,6 +262,7 @@ const char* EXT_FUNC mutil_GetGameInfo(plid_t plid, ginfo_t type)
{
static char buf[MAX_STRBUF_LEN];
const char *cp;
switch (type)
{
case GINFO_NAME:
@ -241,7 +285,7 @@ const char* EXT_FUNC mutil_GetGameInfo(plid_t plid, ginfo_t type)
break;
default:
META_ERROR("GetGameInfo: invalid request '%d' from plugin '%s'", type, plid->name);
return NULL;
return nullptr;
}
Q_strncpy(buf, cp, sizeof buf - 1);
@ -251,39 +295,41 @@ const char* EXT_FUNC mutil_GetGameInfo(plid_t plid, ginfo_t type)
int EXT_FUNC mutil_LoadMetaPlugin(plid_t plid, const char* fname, PLUG_LOADTIME now, void **plugin_handle)
{
MPlugin *pl_loaded;
if (!fname)
{
return 1;
}
if (!(pl_loaded = g_plugins->plugin_addload(plid, fname, now)))
auto pl_loaded = g_plugins->plugin_addload(plid, fname, now);
if (!pl_loaded)
{
if (plugin_handle)
*plugin_handle = nullptr;
return 1;
return 1; // TODO: WTF
}
else
{
if (plugin_handle)
*plugin_handle = (void *)pl_loaded->sys_module.gethandle();
return 0;
}
}
int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{
MPlugin *findp = nullptr;
int pindex;
char *endptr;
MPlugin *findp;
if (!fname)
{
return 1;
}
pindex = strtol(fname, &endptr, 10);
char *endptr;
int pindex = strtol(fname, &endptr, 10);
if (*fname != '\0' && *endptr == '\0')
findp = g_plugins->find(pindex);
else
@ -300,14 +346,14 @@ int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIM
int EXT_FUNC mutil_UnloadMetaPluginByHandle(plid_t plid, void *plugin_handle, PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{
MPlugin *findp;
if (!plugin_handle)
{
return 1;
}
if (!(findp = g_plugins->find((module_handle_t)plugin_handle)))
auto findp = g_plugins->find((module_handle_t)plugin_handle);
if (!findp)
return 1;
if (findp->plugin_unload(plid, now, reason))

View File

@ -146,50 +146,3 @@ const char* str_os_error()
#endif
}
#endif
// Determine whether the given memory location is valid (ie whether we
// should expect to be able to reference strings or functions at this
// location without segfaulting).
#if defined(linux) || defined(__APPLE__)
// Simulate this with dladdr. I'm not convinced this will be as generally
// applicable as the native windows routine below, but it should do what
// we need it for in this particular situation.
// meta_errno values:
// - ME_NOTFOUND couldn't find a matching sharedlib for this ptr
bool IS_VALID_PTR(void *memptr)
{
Dl_info dli;
Q_memset(&dli, 0, sizeof(dli));
if (dladdr(memptr, &dli))
return true;
else
RETURN_ERRNO(false, ME_NOTFOUND);
}
#elif defined(_WIN32)
// Use the native windows routine IsBadCodePtr.
// meta_errno values:
// - ME_BADMEMPTR not a valid memory pointer
bool IS_VALID_PTR(void *memptr)
{
if (IsBadCodePtr((FARPROC) memptr))
return false;
else
return true;
}
#endif // _WIN32
// This used to be OS-dependent, as it used a SEGV signal handler under
// linux, but that was removed because (a) it masked legitimate segfaults
// in plugin commands and produced confusing output ("plugin has been
// unloaded", when really it segfaultd), and (b) wasn't necessary since
// IS_VALID_PTR() should cover the situation.
bool os_safe_call(REG_CMD_FN pfn)
{
// try and see if this is a valid memory location
if (!IS_VALID_PTR((void *)pfn))
// meta_errno should be already set in is_valid_ptr()
return false;
pfn();
return true;
}

View File

@ -40,11 +40,6 @@ private:
uintptr_t m_size;
};
bool IS_VALID_PTR(void *memptr);
// Attempt to call the given function pointer, without segfaulting.
bool os_safe_call(REG_CMD_FN pfn);
// Windows doesn't have an strtok_r() routine, so we write our own.
#ifdef _WIN32
#define strtok_r(s, delim, ptrptr) mm_strtok_r(s, delim, ptrptr)

View File

@ -32,24 +32,17 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
META_DEBUG(4, ("called: meta_AddServerCommand; cmd_name=%s, function=%d, plugin=%s", cmd_name, function, plug ? plug->file : "unknown"));
// try to find which plugin is registering this command
if (!plug) {
META_ERROR("Failed to find memloc for regcmd '%s'", cmd_name);
}
// See if this command was previously registered, ie a "reloaded" plugin.
auto icmd = g_regCmds->find(cmd_name);
if (!icmd)
auto cmd = g_regCmds->find(cmd_name);
if (!cmd)
{
// If not found, add.
icmd = g_regCmds->add(cmd_name, function, plug);
if (!icmd)
{
return;
}
// Only register if not previously registered..
REG_SVR_COMMAND(icmd->getname(), meta_command_handler);
cmd = g_regCmds->add(cmd_name, function, plug);
REG_SVR_COMMAND(cmd->getname(), g_RehldsFuncs ? cmd->gethandler() : meta_command_handler);
}
}
@ -68,43 +61,24 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
// it will fail to work properly.
void EXT_FUNC meta_CVarRegister(cvar_t *pCvar)
{
MPlugin *iplug = g_plugins->find_memloc(pCvar);
MPlugin *plug = g_plugins->find_memloc(pCvar);
META_DEBUG(4, ("called: meta_CVarRegister; name=%s", pCvar->name));
META_DEBUG(4, "called: meta_CVarRegister; name=%s", pCvar->name);
// try to find which plugin is registering this cvar
if (!iplug)
if (!plug)
{
META_DEBUG(1, ("Failed to find memloc for regcvar '%s'", pCvar->name));
META_DEBUG(1, "Failed to find memloc for regcvar '%s'", pCvar->name);
}
// See if this cvar was previously registered, ie a "reloaded" plugin.
auto icvar = g_regCvars->find(pCvar->name);
if (!icvar)
auto reg = g_regCvars->find(pCvar->name);
if (!reg)
{
// If not found, add.
icvar = g_regCvars->add(pCvar->name);
if (!icvar)
{
// error details logged in add()
return;
}
// Reset to given value
icvar->set(pCvar);
CVAR_REGISTER(icvar->data);
reg = g_regCvars->add(pCvar, plug);
CVAR_REGISTER(reg->getcvar());
}
// Note: if not a new cvar, then we don't set the values, and just keep
// the pre-existing value.
icvar->status = RG_VALID;
// Store which plugin this is for, if we know. Use '0' for unknown
// plugin, as plugin index starts at 1.
if (iplug)
icvar->plugid = iplug->index;
else
icvar->plugid = 0;
}
// Replacement for engine routine RegUserMsg; called by plugins. Rather

View File

@ -12,17 +12,72 @@ char *UTIL_VarArgs(char *format, ...)
return string;
}
// UTIL_LogPrintf - Prints a logged message to console.
// Preceded by LOG: ( timestamp ) < message >
void UTIL_LogPrintf(char *fmt, ...)
short FixedSigned16(float value, float scale)
{
va_list argptr;
char string[1024];
int output;
va_start(argptr, fmt);
Q_vsnprintf(string, sizeof(string), fmt, argptr);
va_end(argptr);
output = (int)(value * scale);
// Print to server console
ALERT(at_logged, "%s", string);
if (output > 32767)
output = 32767;
if (output < -32768)
output = -32768;
return (short)output;
}
unsigned short FixedUnsigned16(float value, float scale)
{
int output;
output = (int)(value * scale);
if (output < 0)
output = 0;
if (output > 0xFFFF)
output = 0xFFFF;
return (unsigned short)output;
}
void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage)
{
if (FNullEnt(pEntity) || pEntity->free)
return;
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
WRITE_BYTE(TE_TEXTMESSAGE);
WRITE_BYTE(textparms.channel & 0xFF);
WRITE_SHORT(FixedSigned16(textparms.x, 1 << 13));
WRITE_SHORT(FixedSigned16(textparms.y, 1 << 13));
WRITE_BYTE(textparms.effect);
WRITE_BYTE(textparms.r1);
WRITE_BYTE(textparms.g1);
WRITE_BYTE(textparms.b1);
WRITE_BYTE(textparms.a1);
WRITE_BYTE(textparms.r2);
WRITE_BYTE(textparms.g2);
WRITE_BYTE(textparms.b2);
WRITE_BYTE(textparms.a2);
WRITE_SHORT(FixedUnsigned16(textparms.fadeinTime, 1 << 8));
WRITE_SHORT(FixedUnsigned16(textparms.fadeoutTime, 1 << 8));
WRITE_SHORT(FixedUnsigned16(textparms.holdTime, 1 << 8));
if (textparms.effect == 2)
WRITE_SHORT(FixedUnsigned16(textparms.fxTime, 1 << 8));
if (strlen(pMessage) < 512) {
WRITE_STRING(pMessage);
}
else {
char tmp[512];
strncpy(tmp, pMessage, sizeof tmp - 1);
tmp[sizeof tmp - 1] = 0;
WRITE_STRING(tmp);
}
MESSAGE_END();
}

View File

@ -12,3 +12,5 @@
// defined.
#include "enginecallbacks.h"
#include <util.h>
void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage);

View File

@ -35,24 +35,24 @@ C_DLLEXPORT int Server_GetBlendingInterface(int version,
// "Couldn't get server .dll studio model blending interface. Version
// mismatch?", but this will only show in "developer" (-dev) mode.
META_DEBUG(6, ("called: Server_GetBlendingInterface; version=%d", version));
META_DEBUG(6, "called: Server_GetBlendingInterface; version=%d", version);
if (missing)
{
META_DEBUG(6, ("Skipping Server_GetBlendingInterface; was previously found missing"));
META_DEBUG(6, "Skipping Server_GetBlendingInterface; was previously found missing");
return 0;
}
if (!getblend)
{
META_DEBUG(6, ("Looking up Server_GetBlendingInterface"));
META_DEBUG(6, "Looking up Server_GetBlendingInterface");
getblend = (GETBLENDAPI_FN)GameDLL.sys_module.getsym("Server_GetBlendingInterface");
}
if (!getblend)
{
META_DEBUG(6, ("Couldn't find Server_GetBlendingInterface in game DLL '%s': %s", GameDLL.name, "function not found"));
META_DEBUG(6, "Couldn't find Server_GetBlendingInterface in game DLL '%s': %s", GameDLL.name, "function not found");
missing = 1;
return 0;
}
META_DEBUG(6, ("Calling Server_GetBlendingInterface"));
return (getblend)(version, ppinterface, pstudio, rotationmatrix, bonetransform);
META_DEBUG(6, "Calling Server_GetBlendingInterface");
return getblend(version, ppinterface, pstudio, rotationmatrix, bonetransform);
}

View File

@ -1,5 +1,7 @@
#include "precompiled.h"
static_allocator g_static_allocator(static_allocator::mp_readwrite);
bool is_yes(const char* str)
{
return !Q_strcmp(str, "true") || !Q_strcmp(str, "yes") || !Q_strcmp(str, "1");
@ -20,7 +22,12 @@ const char* LOCALINFO(char* key)
return ENTITY_KEYVALUE(NULL, key);
}
char* execmem_allocator::allocate(const size_t n)
static_allocator::static_allocator(memory_protection protection) : m_protection(protection)
{
}
char* static_allocator::allocate(const size_t n)
{
if (!m_pages.size() || m_used + n > Pagesize)
allocate_page();
@ -30,7 +37,13 @@ char* execmem_allocator::allocate(const size_t n)
return ptr;
}
void execmem_allocator::deallocate_all()
char* static_allocator::strdup(const char* string)
{
size_t len = strlen(string) + 1;
return (char *)memcpy(allocate(len), string, len);
}
void static_allocator::deallocate_all()
{
for (auto page : m_pages)
#ifdef WIN32
@ -42,12 +55,12 @@ void execmem_allocator::deallocate_all()
m_pages.clear();
}
size_t execmem_allocator::memoryUsed() const
size_t static_allocator::memory_used() const
{
return (m_pages.size() - 1) * Pagesize + m_used;
}
void execmem_allocator::allocate_page()
void static_allocator::allocate_page()
{
#ifdef WIN32
auto page = VirtualAlloc(NULL, Pagesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

View File

@ -1,11 +1,34 @@
#pragma once
class execmem_allocator
template <typename T, size_t N>
char(&ArraySizeHelper(T(&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
class static_allocator
{
public:
enum memory_protection : uint8
{
#ifdef _WIN32
mp_readwrite = PAGE_READWRITE,
mp_rwx = PAGE_EXECUTE_READWRITE
#else
mp_readwrite = PROT_READ | PROT_WRITE,
mp_rwx = PROT_READ | PROT_WRITE | PROT_EXEC
#endif
};
static_allocator(memory_protection protection);
char* allocate(const size_t n);
char* strdup(const char* string);
void deallocate_all();
size_t memoryUsed() const;
size_t memory_used() const;
template<typename T>
T* allocate()
{
return (T *)allocate(sizeof(T));
}
private:
void allocate_page();
@ -17,8 +40,11 @@ private:
size_t m_used = 0;
std::vector<void *> m_pages;
memory_protection m_protection;
};
extern static_allocator g_static_allocator;
bool is_yes(const char* str);
bool is_no(const char* str);