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 #pragma once
#define MM_PRE_HOOK
#define MM_POST_HOOK
enum enum
{ {
P_PRE, // plugin function called before gamedll 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) size_t CJit::compile_callback(jitdata_t* jitdata)
{ {
if (!is_hook_needed(jitdata)) { if (!is_hook_needed(jitdata)) {
@ -326,7 +330,7 @@ size_t CJit::compile_callback(jitdata_t* jitdata)
auto code = callback.GetCode(); auto code = callback.GetCode();
auto codeSize = callback.GetCodeSize(); auto codeSize = callback.GetCodeSize();
auto ptr = m_allocator.allocate(codeSize); auto ptr = m_callback_allocator.allocate(codeSize);
return (size_t)memcpy(ptr, code, 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 code = jmp.GetCode();
auto codeSize = jmp.GetCodeSize(); 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); return (size_t)memcpy(ptr, code, codeSize);
} }
void CJit::clear_callbacks() 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) bool CJit::is_hook_needed(jitdata_t* jitdata)

View File

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

View File

@ -54,7 +54,7 @@ bool MConfig::set(option_t* setp, const char* setstr)
return false; return false;
} }
*optval = Q_atoi(setstr); *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; break;
case CF_BOOL: case CF_BOOL:
if (is_yes(setstr)) if (is_yes(setstr))

View File

@ -12,17 +12,17 @@ NEW_DLL_FUNCTIONS sNewFunctionTable;
NEW_DLL_FUNCTIONS sNewFunctionTable_jit; NEW_DLL_FUNCTIONS sNewFunctionTable_jit;
NEW_DLL_FUNCTIONS *pHookedNewDllFunctions = &sNewFunctionTable; 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); 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); 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")) { if (!strcmp(CMD_ARGV(0), "meta")) {
client_meta(pEntity); client_meta(pEntity);
@ -147,7 +147,7 @@ compile_data_t g_newdllfunc_cdata[] =
// GetAPI or not.. // GetAPI or not..
C_DLLEXPORT int GetEntityAPI(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion) 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) if (!pFunctionTable)
{ {
META_ERROR("GetEntityAPI called with null 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) 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) 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) 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... #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 // Don't provide these functions to engine if gamedll doesn't provide
// them. Otherwise, we're in the position of having to provide answers // 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_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) #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 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); g_players.set_player_cvar_query(pEdict, cvarName);
} }
// int -> void // 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. // 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 imsgid = *(int *)(g_metaGlobals.status == MRES_OVERRIDE ? g_metaGlobals.override_ret : g_metaGlobals.orig_ret);
auto nmsg = g_regMsgs->find(imsgid); auto nmsg = g_regMsgs->find(imsgid);
if (nmsg) { if (nmsg) {
if (!strcmp(pszName, nmsg->name)) if (!Q_strcmp(pszName, nmsg->getname()))
// This name/msgid pair was already registered. // 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 else
// This msgid was previously used by a different message name. // 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 else
g_regMsgs->add(pszName, imsgid, iSize); g_regMsgs->add(pszName, imsgid, iSize);

View File

@ -11,11 +11,11 @@
extern cvar_t meta_debug; extern cvar_t meta_debug;
template<typename ...t_args> 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) if (meta_debug.value < level)
return; 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, ...); void META_CONS(const char *fmt, ...);

View File

@ -391,11 +391,11 @@ bool MPluginList::ini_startup()
{ {
if (pmatch->pfspecific >= plist[n].pfspecific) 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; 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; int _index = pmatch->index;
Q_memset(pmatch, 0, sizeof(MPlugin)); Q_memset(pmatch, 0, sizeof(MPlugin));
pmatch->index = _index; pmatch->index = _index;
@ -462,19 +462,19 @@ bool MPluginList::ini_refresh()
{ {
if (pl_found->pfspecific >= pl_temp.pfspecific) 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; continue;
} }
if (PA_LOAD == pl_found->action) 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; int _index = pl_found->index;
Q_memset(pl_found, 0, sizeof(MPlugin)); Q_memset(pl_found, 0, sizeof(MPlugin));
pl_found->index = _index; pl_found->index = _index;
} }
else 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; 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 (!engine_table) engine_table = (meta_enginefuncs_t *)calloc(1, sizeof(meta_enginefuncs_t));
if (meta_table.pfnGetEngineFunctions(engine_table, &iface_vers)) { if (meta_table.pfnGetEngineFunctions(engine_table, &iface_vers)) {
do { 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); while (0);
} }
@ -1412,7 +1413,7 @@ bool MPlugin::newer_file()
return false; return false;
file_time = st.st_ctime > st.st_mtime ? st.st_ctime : st.st_mtime; 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) if (file_time > time_loaded)
return true; return true;
else else

View File

@ -1,26 +1,31 @@
#include "precompiled.h" #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 bool MRegCmd::call() const
{ {
pfnCmd(); m_pfunction();
return status != RG_INVALID; return m_status != RG_INVALID;
} }
void MRegCmd::disable() void MRegCmd::disable()
{ {
pfnCmd = [](){}; m_pfunction = [](){};
plugid = 0; m_plugid = 0;
status = RG_INVALID; m_status = RG_INVALID;
} }
char* MRegCmd::getname() const char* MRegCmd::getname() const
{ {
return name; return m_name;
}
REG_CMD_FN MRegCmd::gethandler() const
{
return m_pfunction;
} }
MRegCmdList::MRegCmdList() : m_list() MRegCmdList::MRegCmdList() : m_list()
@ -29,10 +34,10 @@ MRegCmdList::MRegCmdList() : m_list()
MRegCmd *MRegCmdList::find(const char *name) const MRegCmd *MRegCmdList::find(const char *name) const
{ {
for (auto icmd : m_list) for (auto reg : m_list)
{ {
if (!Q_stricmp(icmd->name, name)) if (!Q_stricmp(reg->m_name, name))
return icmd; return reg;
} }
return nullptr; 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) MRegCmd *MRegCmdList::add(char *addname, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin)
{ {
auto icmd = new MRegCmd(addname, cmd_handler, cmd_plugin); auto reg = new MRegCmd(addname, cmd_handler, cmd_plugin);
m_list.push_back(icmd); m_list.push_back(reg);
return icmd; return reg;
} }
void MRegCmdList::remove(char* cmd_name) void MRegCmdList::remove(char* cmd_name)
{ {
for (auto it = m_list.begin(), end = m_list.end(); it != end; ++it) { 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) { if (g_RehldsFuncs) {
g_RehldsFuncs->Cmd_RemoveCmd(cmd_name); g_RehldsFuncs->Cmd_RemoveCmd(cmd_name);
m_list.erase(it); m_list.erase(it);
} }
else { else {
icmd->disable(); reg->disable();
} }
} }
} }
@ -66,15 +71,15 @@ void MRegCmdList::remove(char* cmd_name)
void MRegCmdList::remove(int owner_plugin_id) void MRegCmdList::remove(int owner_plugin_id)
{ {
for (auto it = m_list.begin(), end = m_list.end(); it != end; ++it) { 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) { if (g_RehldsFuncs) {
g_RehldsFuncs->Cmd_RemoveCmd(icmd->name); g_RehldsFuncs->Cmd_RemoveCmd(reg->m_name);
m_list.erase(it); m_list.erase(it);
} }
else { else {
icmd->disable(); reg->disable();
} }
} }
} }
@ -83,17 +88,17 @@ void MRegCmdList::remove(int owner_plugin_id)
// List all the registered commands. // List all the registered commands.
void MRegCmdList::show() const void MRegCmdList::show() const
{ {
int n = 0, a = 0; int total_count = 0, valid_count = 0;
char bplug[18 + 1]; // +1 for term null char bplug[18 + 1]; // +1 for term null
META_CONS("Registered plugin commands:"); META_CONS("Registered plugin commands:");
META_CONS(" %*s %-*s %-s", WIDTH_MAX_REG, "", sizeof bplug - 1, "plugin", "command"); 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); Q_strncpy(bplug, iplug ? iplug->desc : "(unknown)", sizeof bplug - 1);
bplug[sizeof bplug - 1] = '\0'; bplug[sizeof bplug - 1] = '\0';
@ -104,136 +109,67 @@ void MRegCmdList::show() const
bplug[sizeof bplug - 1] = '\0'; 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) if (reg->m_status == RG_VALID)
a++; 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. // List all the registered commands for the given plugin id.
void MRegCmdList::show(int plugin_id) const void MRegCmdList::show(int plugin_id) const
{ {
int n = 0; int total_count = 0;
META_CONS("Registered commands:"); 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; continue;
META_CONS(" %s", icmd->name); META_CONS(" %s", reg->m_name);
n++; 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 MRegCvar::MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin) : m_cvar(cv_ptr), m_plugid(cv_plugin->index), m_status(RG_VALID)
// constructors, rather than arrays and init-functions.
void MRegCvar::init(int idx)
{ {
index = idx; m_cvar = g_static_allocator.allocate<cvar_t>();
data = NULL; m_cvar->name = _strdup(cv_ptr->name);
plugid = 0; m_cvar->string = _strdup(cv_ptr->string);
status = RG_INVALID; 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. cvar_t* MRegCvar::getcvar() const
// meta_errno values:
// - ME_ARGUMENT given cvar doesn't match this cvar
bool MRegCvar::set(cvar_t *src) const
{ {
if (Q_stricmp(src->name, data->name)) return m_cvar;
{
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;
} }
// Constructor // Constructor
MRegCvarList::MRegCvarList() MRegCvarList::MRegCvarList() : m_list()
: vlist(0), size(REG_CVAR_GROWSIZE), endlist(0)
{ {
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 MRegCvar *MRegCvarList::add(cvar_t* src, MPlugin* plugin)
// 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 *icvar; MRegCvar *reg_cvar = new(g_static_allocator.allocate<MRegCvar>()) MRegCvar(src, plugin);
if (endlist == size) m_list.push_back(reg_cvar);
{ return reg_cvar;
// 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;
} }
// 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) 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)) if (!Q_stricmp(reg->m_cvar->name, findname))
return &vlist[i]; return reg;
} }
return NULL; return NULL;
@ -242,18 +178,12 @@ MRegCvar *MRegCvarList::find(const char *findname)
// Disable any cvars belonging to the given plugin (by index id). // Disable any cvars belonging to the given plugin (by index id).
void MRegCvarList::disable(int plugin_id) const void MRegCvarList::disable(int plugin_id) const
{ {
int i; for (auto reg : m_list)
MRegCvar *icvar;
for (i = 0; i < size; i++)
{ {
icvar = &vlist[i]; if (reg->m_plugid == plugin_id)
if (icvar->plugid == plugin_id)
{ {
icvar->status = RG_INVALID; reg->m_status = RG_INVALID;
icvar->plugid = 0; reg->m_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]");
} }
} }
} }
@ -261,29 +191,19 @@ void MRegCvarList::disable(int plugin_id) const
// List all the registered cvars. // List all the registered cvars.
void MRegCvarList::show() const void MRegCvarList::show() const
{ {
int i, n = 0, a = 0; int total_count = 0, valid_count = 0;
MRegCvar *icvar;
MPlugin *iplug;
char bplug[13 + 1], bname[20 + 1], bval[15 + 1]; // +1 for term null char bplug[13 + 1], bname[20 + 1], bval[15 + 1]; // +1 for term null
META_CONS("Registered plugin cvars:"); 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"); 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++)
for (auto reg : m_list)
{ {
icvar = &vlist[i]; if (reg->m_status == RG_VALID)
if (icvar->status == RG_VALID)
{ {
iplug = g_plugins->find(icvar->plugid); auto plug = g_plugins->find(reg->m_plugid);
if (iplug) Q_strncpy(bplug, plug ? plug->desc : "(unknown)", sizeof bplug - 1);
{ bplug[sizeof bplug - 1] = '\0';
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';
}
} }
else else
{ {
@ -291,127 +211,110 @@ void MRegCvarList::show() const
bplug[sizeof bplug - 1] = '\0'; 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'; bname[sizeof bname - 1] = '\0';
Q_snprintf(bval, sizeof(bval), "%f", icvar->data->value); Q_snprintf(bval, sizeof bval, "%f", reg->m_cvar->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); 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) if (reg->m_status == RG_VALID)
a++; valid_count++;
n++;
} }
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. // List the registered cvars for the given plugin id.
void MRegCvarList::show(int plugin_id) const void MRegCvarList::show(int plugin_id) const
{ {
int n = 0; int total_count = 0;
MRegCvar *icvar;
char bname[30 + 1], bval[15 + 1]; // +1 for term null 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"); META_CONS("%-*s %*s %s", sizeof(bname) - 1, "Registered cvars:", sizeof bval - 1, "float value", "string value");
for (int i = 0; i < endlist; i++)
for (auto reg : m_list)
{ {
icvar = &vlist[i]; if (reg->m_plugid != plugin_id)
if (icvar->plugid != plugin_id)
continue; 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'; bname[sizeof bname - 1] = '\0';
Q_snprintf(bval, sizeof(bval), "%f", icvar->data->value); Q_snprintf(bval, sizeof(bval), "%f", reg->m_cvar->value);
META_CONS(" %-*s %*s %s", sizeof(bname) - 1, bname, sizeof(bval) - 1, bval, icvar->data->string); META_CONS(" %-*s %*s %s", sizeof(bname) - 1, bname, sizeof(bval) - 1, bval, reg->m_cvar->string);
n++; total_count++;
} }
META_CONS("%d cvars", n); META_CONS("%d cvars", total_count);
} }
// Constructor MRegMsg::MRegMsg(const char* name, int msgid, int size) : m_name(name), m_msgid(msgid), m_size(size)
MRegMsgList::MRegMsgList() {
: size(MAX_REG_MSGS), endlist(0)
}
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()
{ {
// 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
MRegMsg *MRegMsgList::add(const char *addname, int addmsgid, int addsize) 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. // Copy msg data into empty slot.
// Note: 'addname' assumed to be a constant string allocated in the // Note: 'addname' assumed to be a constant string allocated in the
// gamedll. // gamedll.
imsg->name = addname; auto msg = new(g_static_allocator.allocate<MRegMsg>()) MRegMsg(addname, addmsgid, addsize);
imsg->msgid = addmsgid; m_list.push_back(msg);
imsg->size = addsize; return msg;
return imsg;
} }
// 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) 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)) if (!Q_strcmp(msg->m_name, findname))
return &mlist[i]; 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) MRegMsg *MRegMsgList::find(int findmsgid)
{ {
for (int i = 0; i < endlist; i++) for (auto msg : m_list) {
{ if (msg->m_msgid == findmsgid)
if (mlist[i].msgid == findmsgid) return msg;
return &mlist[i];
} }
return NULL; return nullptr;
} }
// List the registered usermsgs for the gamedll. // List the registered usermsgs for the gamedll.
void MRegMsgList::show() void MRegMsgList::show()
{ {
int i, n = 0; int total_count = 0;
MRegMsg *imsg;
char bname[25 + 1]; // +1 for term null char bname[25 + 1]; // +1 for term null
META_CONS("%-*s %5s %5s", sizeof(bname) - 1, "Game registered user msgs:", "msgid", "size"); META_CONS("%-*s %5s %5s", sizeof(bname) - 1, "Game registered user msgs:", "msgid", "size");
for (i = 0; i < endlist; i++)
{ for (auto msg : m_list) {
imsg = &mlist[i]; Q_strncpy(bname, msg->m_name, sizeof bname - 1);
Q_strncpy(bname, imsg->name, sizeof bname - 1);
bname[sizeof bname - 1] = '\0'; bname[sizeof bname - 1] = '\0';
META_CONS(" %-*s %3d %3d", sizeof(bname) - 1, bname, imsg->msgid, imsg->size); META_CONS(" %-*s %3d %3d", sizeof(bname) - 1, bname, msg->m_msgid, msg->m_size);
n++; 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 #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. // 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 // 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; class MPlugin;
// An individual registered function/command. // An individual registered function/command.
class MRegCmd { class MRegCmd
{
public: public:
MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin); MRegCmd(char* cmd_name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin);
bool call() const; // try to call the function bool call() const; // try to call the function
void disable(); void disable();
char* getname() const; char* getname() const;
REG_CMD_FN gethandler() const;
private: private:
char *name; // space is malloc'd char* m_name; // space is malloc'd
REG_CMD_FN pfnCmd; // pointer to the function REG_CMD_FN m_pfunction; // pointer to the function
int plugid; // index id of corresponding plugin int m_plugid; // index id of corresponding plugin
REG_STATUS status; // whether corresponding plugin is loaded REG_STATUS m_status; // whether corresponding plugin is loaded
friend class MRegCmdList; friend class MRegCmdList;
}; };
// A list of registered commands. // A list of registered commands.
class MRegCmdList { class MRegCmdList
{
public: public:
MRegCmdList(); MRegCmdList();
MRegCmd *find(const char *name) const;
MRegCmd *find(const char *name) const; // find by MRegCmd->name
MRegCmd *add(char *name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin); MRegCmd *add(char *name, REG_CMD_FN cmd_handler, MPlugin* cmd_plugin);
void remove(char* cmd_name); void remove(char* cmd_name);
void remove(int owner_plugin_id); // change status to Invalid void remove(int owner_plugin_id);
void show() const; // list all funcs to console void show() const;
void show(int plugin_id) const; // list given plugin's funcs to console void show(int plugin_id) const;
private: private:
std::vector<MRegCmd *> m_list; std::vector<MRegCmd *> m_list;
}; };
// An individual registered cvar. // An individual registered cvar.
class MRegCvar { class MRegCvar
{
public: public:
friend class MRegCvarList; MRegCvar(cvar_t* cv_ptr, MPlugin* cv_plugin);
cvar_t* getcvar() const;
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;
private: private:
int index; // 1-based cvar_t* m_cvar;
int m_plugid;
REG_STATUS m_status;
friend class MRegCvarList;
}; };
// A list of registered cvars. // A list of registered cvars.
class MRegCvarList { class MRegCvarList
{
public: public:
MRegCvarList(); MRegCvarList();
MRegCvar *add(cvar_t* src, MPlugin* plugin);
MRegCvar *add(const char *addname);
MRegCvar *find(const char *findname); // find by MRegCvar->data.name MRegCvar *find(const char *findname); // find by MRegCvar->data.name
void disable(int plugin_id) const; // change status to Invalid void disable(int plugin_id) const; // change status to Invalid
void show() const; // list all cvars to console void show() const; // list all cvars to console
void show(int plugin_id) const; // list given plugin's cvars to console void show(int plugin_id) const; // list given plugin's cvars to console
private: private:
MRegCvar *vlist; // malloc'd array of registered cvars std::vector<MRegCvar *> m_list;
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);
}; };
// An individual registered user msg, from gamedll. // An individual registered user msg, from gamedll.
class MRegMsg { class MRegMsg
{
public: public:
friend class MRegMsgList; MRegMsg(const char* name, int msgid, int size);
const char* getname() const;
const char *name; // name, assumed constant string in gamedll int getid() const;
int msgid; // msgid, assigned by engine int getsize() const;
int size; // size, if given by gamedll
private: private:
int index; // 1-based const char* m_name;
int m_msgid;
int m_size;
friend class MRegMsgList;
}; };
// A list of registered user msgs. // A list of registered user msgs.
class MRegMsgList { class MRegMsgList
{
public: public:
MRegMsgList(); MRegMsgList();
MRegMsg *add(const char *addname, int addmsgid, int addsize); MRegMsg *add(const char *addname, int addmsgid, int addsize);
MRegMsg *find(const char *findname); MRegMsg *find(const char *findname);
MRegMsg *find(int findmsgid); MRegMsg *find(int findmsgid);
void show(); // list all msgs to console void show();
private: private:
MRegMsg mlist[MAX_REG_MSGS]; // array of registered msgs std::vector<MRegMsg *> m_list;
int size; // size of list, ie MAX_REG_MSGS
int endlist; // index of last used entry
}; };

View File

@ -1,6 +1,6 @@
#include "precompiled.h" #include "precompiled.h"
hudtextparms_t default_csay_tparms = { static hudtextparms_t g_default_csay_tparms = {
-1, 0.25, // x, y -1, 0.25, // x, y
2, // effect 2, // effect
0, 255, 0, 0, // r, g, b, a1 0, 255, 0, 0, // r, g, b, a1
@ -9,23 +9,81 @@ hudtextparms_t default_csay_tparms = {
1 // channel 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. // Log to console; newline added.
void EXT_FUNC mutil_LogConsole(plid_t plid, const char *fmt, ...) void EXT_FUNC mutil_LogConsole(plid_t plid, const char *fmt, ...)
{ {
va_list ap;
char buf[MAX_LOGMSG_LEN]; char buf[MAX_LOGMSG_LEN];
unsigned int len;
va_list ap;
va_start(ap, fmt); 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); va_end(ap);
// end msg with newline buf[len] = '\n';
len = Q_strlen(buf); buf[len + 1] = '\0';
if (len < sizeof(buf) - 2) // -1 null, -1 for newline
Q_strcat(buf, "\n");
else
buf[len - 1] = '\n';
SERVER_PRINT(buf); 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. // Log regular message to logs; newline added.
void EXT_FUNC mutil_LogMessage(plid_t plid, const char *fmt, ...) void EXT_FUNC mutil_LogMessage(plid_t plid, const char *fmt, ...)
{ {
va_list ap;
char buf[MAX_LOGMSG_LEN]; char buf[MAX_LOGMSG_LEN];
plugin_info_t *plinfo = (plugin_info_t *)plid;
va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
Q_vsnprintf(buf, sizeof(buf), fmt, ap); Q_vsnprintf(buf, sizeof buf, fmt, ap);
va_end(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. // Log an error message to logs; newline added.
void EXT_FUNC mutil_LogError(plid_t plid, const char *fmt, ...) void EXT_FUNC mutil_LogError(plid_t plid, const char *fmt, ...)
{ {
va_list ap;
char buf[MAX_LOGMSG_LEN]; char buf[MAX_LOGMSG_LEN];
plugin_info_t *plinfo = (plugin_info_t *)plid;
va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
Q_vsnprintf(buf, sizeof(buf), fmt, ap); Q_vsnprintf(buf, sizeof buf, fmt, ap);
va_end(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. // Log a message only if cvar "developer" set; newline added.
void EXT_FUNC mutil_LogDeveloper(plid_t plid, const char* fmt, ...) void EXT_FUNC mutil_LogDeveloper(plid_t plid, const char* fmt, ...)
{ {
va_list ap;
char buf[MAX_LOGMSG_LEN]; char buf[MAX_LOGMSG_LEN];
plugin_info_t* plinfo;
if ((int) CVAR_GET_FLOAT("developer") == 0) if ((int)CVAR_GET_FLOAT("developer") == 0)
return; return;
plinfo = (plugin_info_t *)plid; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
Q_vsnprintf(buf, sizeof(buf), fmt, ap); Q_vsnprintf(buf, sizeof buf, fmt, ap);
va_end(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 // 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_list ap;
va_start(ap, fmt); va_start(ap, fmt);
mutil_CenterSayVarargs(plid, default_csay_tparms, fmt, ap); mutil_CenterSayVarargs(plid, g_default_csay_tparms, fmt, ap);
va_end(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) void EXT_FUNC mutil_CenterSayVarargs(plid_t plid, hudtextparms_t tparms, const char* fmt, va_list ap)
{ {
char buf[MAX_LOGMSG_LEN]; char buf[MAX_LOGMSG_LEN];
int n; Q_vsnprintf(buf, sizeof buf, fmt, ap);
edict_t *pEntity;
Q_vsnprintf(buf, sizeof(buf), fmt, ap);
mutil_LogMessage(plid, "(centersay) %s", buf); 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) if (FNullEnt(pEntity) || pEntity->free)
continue; 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. // Jussi Kivilinna.
qboolean EXT_FUNC mutil_CallGameEntity(plid_t plid, const char *entStr, entvars_t *pev) 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, plid->name));
META_DEBUG(8, ("Looking up game entity '%s' for plugin '%s'", entStr, plinfo->name));
ENTITY_FN pfnEntity = (ENTITY_FN)GameDLL.sys_module.getsym(entStr); ENTITY_FN pfnEntity = (ENTITY_FN)GameDLL.sys_module.getsym(entStr);
if (!pfnEntity) 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; 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); (*pfnEntity)(pev);
return true; 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). // msgname, and return remaining info about it (msgid, size).
int EXT_FUNC mutil_GetUserMsgID(plid_t plid, const char* msgname, int* 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, plid->name);
META_DEBUG(8, ("Looking up usermsg name '%s' for plugin '%s'", msgname, plinfo->name));
MRegMsg *umsg = g_regMsgs->find(msgname); MRegMsg *umsg = g_regMsgs->find(msgname);
if (umsg) if (umsg)
{ {
if (size) if (size) *size = umsg->getsize();
*size = umsg->size; return umsg->getid();
return umsg->msgid;
} }
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 // 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) const char* EXT_FUNC mutil_GetUserMsgName(plid_t plid, int msgid, int *size)
{ {
plugin_info_t *plinfo = (plugin_info_t *)plid; 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; // Guess names for any built-in g_engine messages mentioned in the SDK;
// from dlls/util.h. // from dlls/util.h.
if (msgid < 64) if (msgid < arraysize(g_engine_msg_names))
{ {
switch (msgid) if (size) *size = -1;
{ return g_engine_msg_names[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?";
}
} }
MRegMsg *umsg = g_regMsgs->find(msgid); MRegMsg *umsg = g_regMsgs->find(msgid);
if (umsg) if (umsg)
{ {
if (size) if (size) *size = umsg->getsize();
*size = umsg->size;
// 'name' is assumed to be a constant string, allocated in the // 'name' is assumed to be a constant string, allocated in the
// gamedll. // gamedll.
return umsg->name; return umsg->getname();
} }
else
return NULL; return nullptr;
} }
// Return the full path of the plugin's loaded dll/so file. // Return the full path of the plugin's loaded dll/so file.
const char* EXT_FUNC mutil_GetPluginPath(plid_t plid) const char* EXT_FUNC mutil_GetPluginPath(plid_t plid)
{ {
static char buf[PATH_MAX ]; static char buf[PATH_MAX];
MPlugin *plug;
plug = g_plugins->find(plid); auto plug = g_plugins->find(plid);
if (!plug) if (!plug)
{ {
META_ERROR("GetPluginPath: couldn't find plugin '%s'", plid->name); META_ERROR("GetPluginPath: couldn't find plugin '%s'", plid->name);
return NULL; return nullptr;
} }
Q_strncpy(buf, plug->pathname, sizeof buf - 1); 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]; static char buf[MAX_STRBUF_LEN];
const char *cp; const char *cp;
switch (type) switch (type)
{ {
case GINFO_NAME: case GINFO_NAME:
@ -241,7 +285,7 @@ const char* EXT_FUNC mutil_GetGameInfo(plid_t plid, ginfo_t type)
break; break;
default: default:
META_ERROR("GetGameInfo: invalid request '%d' from plugin '%s'", type, plid->name); META_ERROR("GetGameInfo: invalid request '%d' from plugin '%s'", type, plid->name);
return NULL; return nullptr;
} }
Q_strncpy(buf, cp, sizeof buf - 1); 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) int EXT_FUNC mutil_LoadMetaPlugin(plid_t plid, const char* fname, PLUG_LOADTIME now, void **plugin_handle)
{ {
MPlugin *pl_loaded;
if (!fname) if (!fname)
{ {
return 1; 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) if (plugin_handle)
*plugin_handle = nullptr; *plugin_handle = nullptr;
return 1; return 1; // TODO: WTF
} }
else else
{ {
if (plugin_handle) if (plugin_handle)
*plugin_handle = (void *)pl_loaded->sys_module.gethandle(); *plugin_handle = (void *)pl_loaded->sys_module.gethandle();
return 0; return 0;
} }
} }
int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME now, PL_UNLOAD_REASON reason) int EXT_FUNC mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{ {
MPlugin *findp = nullptr; MPlugin *findp;
int pindex;
char *endptr;
if (!fname) if (!fname)
{ {
return 1; return 1;
} }
pindex = strtol(fname, &endptr, 10); char *endptr;
int pindex = strtol(fname, &endptr, 10);
if (*fname != '\0' && *endptr == '\0') if (*fname != '\0' && *endptr == '\0')
findp = g_plugins->find(pindex); findp = g_plugins->find(pindex);
else 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) int EXT_FUNC mutil_UnloadMetaPluginByHandle(plid_t plid, void *plugin_handle, PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{ {
MPlugin *findp;
if (!plugin_handle) if (!plugin_handle)
{ {
return 1; 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; return 1;
if (findp->plugin_unload(plid, now, reason)) if (findp->plugin_unload(plid, now, reason))

View File

@ -146,50 +146,3 @@ const char* str_os_error()
#endif #endif
} }
#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; 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. // Windows doesn't have an strtok_r() routine, so we write our own.
#ifdef _WIN32 #ifdef _WIN32
#define strtok_r(s, delim, ptrptr) mm_strtok_r(s, delim, ptrptr) #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")); 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) { if (!plug) {
META_ERROR("Failed to find memloc for regcmd '%s'", cmd_name); META_ERROR("Failed to find memloc for regcmd '%s'", cmd_name);
} }
// See if this command was previously registered, ie a "reloaded" plugin. // See if this command was previously registered, ie a "reloaded" plugin.
auto icmd = g_regCmds->find(cmd_name); auto cmd = g_regCmds->find(cmd_name);
if (!icmd) if (!cmd)
{ {
// If not found, add. // If not found, add.
icmd = g_regCmds->add(cmd_name, function, plug); cmd = g_regCmds->add(cmd_name, function, plug);
if (!icmd) REG_SVR_COMMAND(cmd->getname(), g_RehldsFuncs ? cmd->gethandler() : meta_command_handler);
{
return;
}
// Only register if not previously registered..
REG_SVR_COMMAND(icmd->getname(), meta_command_handler);
} }
} }
@ -68,43 +61,24 @@ void EXT_FUNC meta_AddServerCommand(char *cmd_name, void (*function)())
// it will fail to work properly. // it will fail to work properly.
void EXT_FUNC meta_CVarRegister(cvar_t *pCvar) 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 // 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. // See if this cvar was previously registered, ie a "reloaded" plugin.
auto icvar = g_regCvars->find(pCvar->name); auto reg = g_regCvars->find(pCvar->name);
if (!icvar)
if (!reg)
{ {
// If not found, add. reg = g_regCvars->add(pCvar, plug);
icvar = g_regCvars->add(pCvar->name); CVAR_REGISTER(reg->getcvar());
if (!icvar)
{
// error details logged in add()
return;
}
// Reset to given value
icvar->set(pCvar);
CVAR_REGISTER(icvar->data);
} }
// 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 // Replacement for engine routine RegUserMsg; called by plugins. Rather

View File

@ -12,17 +12,72 @@ char *UTIL_VarArgs(char *format, ...)
return string; return string;
} }
// UTIL_LogPrintf - Prints a logged message to console. short FixedSigned16(float value, float scale)
// Preceded by LOG: ( timestamp ) < message >
void UTIL_LogPrintf(char *fmt, ...)
{ {
va_list argptr; int output;
char string[1024];
va_start(argptr, fmt); output = (int)(value * scale);
Q_vsnprintf(string, sizeof(string), fmt, argptr);
va_end(argptr);
// Print to server console if (output > 32767)
ALERT(at_logged, "%s", string); 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. // defined.
#include "enginecallbacks.h" #include "enginecallbacks.h"
#include <util.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 // "Couldn't get server .dll studio model blending interface. Version
// mismatch?", but this will only show in "developer" (-dev) mode. // 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) if (missing)
{ {
META_DEBUG(6, ("Skipping Server_GetBlendingInterface; was previously found missing")); META_DEBUG(6, "Skipping Server_GetBlendingInterface; was previously found missing");
return 0; return 0;
} }
if (!getblend) 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"); getblend = (GETBLENDAPI_FN)GameDLL.sys_module.getsym("Server_GetBlendingInterface");
} }
if (!getblend) 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; missing = 1;
return 0; return 0;
} }
META_DEBUG(6, ("Calling Server_GetBlendingInterface")); META_DEBUG(6, "Calling Server_GetBlendingInterface");
return (getblend)(version, ppinterface, pstudio, rotationmatrix, bonetransform); return getblend(version, ppinterface, pstudio, rotationmatrix, bonetransform);
} }

View File

@ -1,5 +1,7 @@
#include "precompiled.h" #include "precompiled.h"
static_allocator g_static_allocator(static_allocator::mp_readwrite);
bool is_yes(const char* str) bool is_yes(const char* str)
{ {
return !Q_strcmp(str, "true") || !Q_strcmp(str, "yes") || !Q_strcmp(str, "1"); 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); 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) if (!m_pages.size() || m_used + n > Pagesize)
allocate_page(); allocate_page();
@ -30,7 +37,13 @@ char* execmem_allocator::allocate(const size_t n)
return ptr; 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) for (auto page : m_pages)
#ifdef WIN32 #ifdef WIN32
@ -42,12 +55,12 @@ void execmem_allocator::deallocate_all()
m_pages.clear(); m_pages.clear();
} }
size_t execmem_allocator::memoryUsed() const size_t static_allocator::memory_used() const
{ {
return (m_pages.size() - 1) * Pagesize + m_used; return (m_pages.size() - 1) * Pagesize + m_used;
} }
void execmem_allocator::allocate_page() void static_allocator::allocate_page()
{ {
#ifdef WIN32 #ifdef WIN32
auto page = VirtualAlloc(NULL, Pagesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); auto page = VirtualAlloc(NULL, Pagesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

View File

@ -1,11 +1,34 @@
#pragma once #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: 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* allocate(const size_t n);
char* strdup(const char* string);
void deallocate_all(); void deallocate_all();
size_t memoryUsed() const; size_t memory_used() const;
template<typename T>
T* allocate()
{
return (T *)allocate(sizeof(T));
}
private: private:
void allocate_page(); void allocate_page();
@ -17,8 +40,11 @@ private:
size_t m_used = 0; size_t m_used = 0;
std::vector<void *> m_pages; std::vector<void *> m_pages;
memory_protection m_protection;
}; };
extern static_allocator g_static_allocator;
bool is_yes(const char* str); bool is_yes(const char* str);
bool is_no(const char* str); bool is_no(const char* str);