nuclide/src/server/plugins.qc

340 lines
6.3 KiB
Plaintext

/*
* Copyright (c) 2016-2022 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
typedef struct
{
string m_strPath;
float m_flProgsID;
} plugin_t;
plugin_t *g_plugindb;
var int g_plugincount;
void
Plugin_Init(void)
{
filestream pdb;
string tmp;
int i;
if (autocvar_sv_plugins) {
g_plugins_enabled = 1;
} else {
g_plugins_enabled = 0;
return;
}
InitStart();
pdb = fopen("plugins.txt", FILE_READ);
if (pdb < 0) {
NSWarning("No plugins.txt found. Plugins disabled.\n");
g_plugins_enabled = 0;
InitEnd();
return;
}
/* count valid progs */
g_plugincount = 0;
while ((tmp = fgets(pdb))) {
int argc = tokenize_console(tmp);
/* check for valid entries/comments */
if (argc <= 0)
continue;
g_plugincount++;
}
g_plugindb = memalloc(sizeof(plugin_t) * g_plugincount);
fseek(pdb, 0);
i = 0;
while ((tmp = fgets(pdb))) {
int a = tokenize_console(tmp);
/* check for valid entries/comments */
if (a <= 0)
continue;
g_plugindb[i].m_strPath = strcat("plugins/", argv(0));
g_plugindb[i].m_flProgsID = addprogs(g_plugindb[i].m_strPath);
i++;
}
fclose(pdb);
void(void) vFunc;
for (i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_Init");
if (vFunc) {
vFunc();
}
}
NSLog("...initialized %i plugins.", g_plugincount);
InitEnd();
}
/*
=================
Plugin_Shutdown
Allows every plugin to properly free and unallocate whatever it is they've done
=================
*/
void
Plugin_Shutdown(void)
{
void(void) vFunc;
if (g_plugincount <= 0)
return;
for (int i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_Shutdown");
if (vFunc) {
vFunc();
}
}
memfree(g_plugindb);
g_plugincount = 0;
}
/*
=================
Plugin_InitEnts
Called once entity slots are available for use.
=================
*/
void
Plugin_InitEnts(void)
{
void(void) vFunc;
if (g_plugins_enabled == 0)
return (0);
for (int i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_InitEnts");
if (vFunc) {
vFunc();
}
}
}
/*
=================
Plugin_RunClientCommand
Funtion that can interrupt client commands before physics are run
=================
*/
int
Plugin_RunClientCommand(void)
{
int rval;
int tval;
int(void) vFunc;
if (g_plugins_enabled == 0)
return (0);
/* rval = final return value, tval = temporary return value.
if at least one of the plugins returns TRUE, then RunClientCommand
will not be called by the engine, as it should be */
rval = FALSE;
tval = FALSE;
for (int i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_RunClientCommand");
if (vFunc) {
tval = vFunc();
rval |= tval;
}
}
return rval;
}
/*
=================
Plugin_ParseClientCommand
Intercepts 'cmd' calls. We use it to intercept
chat messages and handle distribution ourselves.
=================
*/
string
Plugin_ParseClientCommand(string msg)
{
string(string msg) vFunc;
if (g_plugins_enabled == 0)
return (0);
for (int i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_ParseClientCommand");
if (vFunc) {
string new;
new = vFunc(msg);
/* pass valid overrides forward */
if (new != __NULL__)
msg = new;
}
}
return msg;
}
/*
=================
Plugin_PlayerConnect
Called whenever a new client connect to the game
=================
*/
int
Plugin_PlayerConnect(NSClientPlayer cl)
{
int rval;
int tval;
int(entity) vFunc;
if (g_plugins_enabled == 0)
return (0);
/* rval = final return value, tval = temporary return value.
if at least one of the plugins returns TRUE, then RunClientCommand
will not be called by the engine, as it should be */
rval = FALSE;
tval = FALSE;
for (int i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_PlayerConnect");
if (vFunc) {
tval = vFunc(cl);
rval |= tval;
}
}
return rval;
}
/*
=================
Plugin_PlayerDisconnect
Called whenever a client leaves the game
=================
*/
int
Plugin_PlayerDisconnect(NSClientPlayer cl)
{
int rval;
int tval;
int(entity) vFunc;
if (g_plugins_enabled == 0)
return (0);
/* rval = final return value, tval = temporary return value.
if at least one of the plugins returns TRUE, then RunClientCommand
will not be called by the engine, as it should be */
rval = FALSE;
tval = FALSE;
for (int i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_PlayerDisconnect");
if (vFunc) {
tval = vFunc(cl);
rval |= tval;
}
}
return rval;
}
/*
=================
Plugin_PlayerEntered
Called when a player has fully connected and entered the server
=================
*/
int
Plugin_PlayerEntered(NSClientPlayer cl)
{
int rval;
int tval;
int(entity) vFunc;
if (g_plugins_enabled == 0)
return (0);
/* rval = final return value, tval = temporary return value.
if at least one of the plugins returns TRUE, then RunClientCommand
will not be called by the engine, as it should be */
rval = FALSE;
tval = FALSE;
for (int i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_PlayerEntered");
if (vFunc) {
tval = vFunc(cl);
rval |= tval;
}
}
return rval;
}
/*
=================
Plugin_PlayerObituary
Deathmessage hook
=================
*/
void
Plugin_PlayerObituary(entity attk, entity targ, int weapon, bodyType_t body, int dmg)
{
void(entity,entity,int,int,int) vFunc;
if (g_plugins_enabled == 0)
return (0);
for (int i = 0; i < g_plugincount; i++) {
vFunc = externvalue(g_plugindb[i].m_flProgsID, "FMX_PlayerObituary");
if (vFunc) {
vFunc(attk, targ, weapon, body, dmg);
}
}
}