From 52850efb875574fec20308c6871e5be77933dbc8 Mon Sep 17 00:00:00 2001 From: Spoike Date: Fri, 24 Sep 2004 02:45:00 +0000 Subject: [PATCH] going for plugins. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@240 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/common/plugin.c | 315 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 engine/common/plugin.c diff --git a/engine/common/plugin.c b/engine/common/plugin.c new file mode 100644 index 000000000..6aa6249f3 --- /dev/null +++ b/engine/common/plugin.c @@ -0,0 +1,315 @@ +//This file should be easily portable. +//The biggest strength of this plugin system is that ALL interactions are performed via +//named functions, this makes it *really* easy to port plugins from one engine to annother. + +#include "quakedef.h" + + + +typedef struct plugin_s { + char *name; + vm_t *vm; + int tick; + int executestring; + + struct plugin_s *next; +} plugin_t; + +plugin_t *currentplug; + +//custom plugin builtins. +typedef int (*Plug_Builtin_t)(void *offset, unsigned int mask, const long *arg); +void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags); +#define PLUG_BIF_DLLONLY 1 +#define PLUG_BIF_QVMONLY 2 + +void Plug_Init(void); + +void Plug_Tick(void); +qboolean Plugin_ExecuteString(void); +void Plug_Shutdown(void); + + +static plugin_t *plugs; + + +typedef struct { + char *name; + Plug_Builtin_t func; +} Plug_Plugins_t; +Plug_Plugins_t *plugbuiltins; +int numplugbuiltins; + +void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags) +{ + //randomize the order a little. + int newnum; + + newnum = rand()%128; + while(newnum < numplugbuiltins && plugbuiltins[newnum].func) + newnum+=128; + + if (newnum > numplugbuiltins) + { + numplugbuiltins = newnum+128; + plugbuiltins = BZ_Realloc(plugbuiltins, sizeof(Plug_Plugins_t)*numplugbuiltins); + } + + //got an empty number. + plugbuiltins[newnum].name = name; + plugbuiltins[newnum].func = bi; +} + +/* +static void Plug_RegisterBuiltinIndex(char *name, Plug_Builtin_t bi, int flags, int index) //I d +{ + //randomize the order a little. + int newnum; + + newnum = rand()%128; + while(newnum+1 < numplugbuiltins && plugbuiltins[newnum+1].func) + newnum+=128; + + newnum++; + + if (newnum > numplugbuiltins) + { + numplugbuiltins = newnum+128; + plugbuiltins = BZ_Realloc(plugbuiltins, sizeof(Plug_Plugins_t)*numplugbuiltins); + } + + //got an empty number. + plugbuiltins[newnum].name = name; + plugbuiltins[newnum].func = bi; +} +*/ + +int Plug_FindBuiltin(void *offset, unsigned int mask, const long *args) +{ + int i; + for (i = 0; i < numplugbuiltins; i++) + if (plugbuiltins[i].name) + if (!strcmp(plugbuiltins[i].name, (char *)offset+args[0])) + return -i; + + return 0; +} + +long Plug_SystemCallsEx(void *offset, unsigned int mask, int fn, const long *arg) +{ + fn = fn+1; + + if (fn>=0 && fn < numplugbuiltins && plugbuiltins[fn].func!=NULL) + return plugbuiltins[fn].func(offset, mask, arg); + + Sys_Error("QVM Plugin tried calling invalid builtin %i", fn); + return 0; +} + +#ifdef _DEBUG +static long Plug_SystemCallsExWrapper(void *offset, unsigned int mask, int fn, const long *arg) +{ //this is so we can use edit and continue properly (vc doesn't like function pointers for edit+continue) + return Plug_SystemCallsEx(offset, mask, fn, arg); +} +#define Plug_SystemCallsEx Plug_SystemCallsExWrapper +#endif + +//I'm not keen on this. +//but dlls call it without saying what sort of vm it comes from, so I've got to have them as specifics +static int EXPORT_FN Plug_SystemCalls(int arg, ...) +{ + long args[9]; + va_list argptr; + + va_start(argptr, arg); + args[0]=va_arg(argptr, int); + args[1]=va_arg(argptr, int); + args[2]=va_arg(argptr, int); + args[3]=va_arg(argptr, int); + args[4]=va_arg(argptr, int); + args[5]=va_arg(argptr, int); + args[6]=va_arg(argptr, int); + args[7]=va_arg(argptr, int); + args[8]=va_arg(argptr, int); + va_end(argptr); + + arg = -arg; + + if (arg>=0 && arg < numplugbuiltins && plugbuiltins[arg].func) + return plugbuiltins[arg].func(NULL, ~0, args); + + Sys_Error("DLL Plugin tried calling invalid biultin %i", arg); + return 0; +} + + +plugin_t *Plug_Load(char *file) +{ + plugin_t *newplug; + int argarray; + + for (newplug = plugs; newplug; newplug = newplug->next) + { + if (!stricmp(newplug->name, file)) + return NULL; + } + + newplug = Z_Malloc(sizeof(plugin_t)+strlen(file)+1); + newplug->name = (char*)(newplug+1); + strcpy(newplug->name, file); + + newplug->vm = VM_Create(NULL, file, Plug_SystemCalls, Plug_SystemCallsEx); + currentplug = newplug; + if (newplug->vm) + { + newplug->next = plugs; + plugs = newplug; + + argarray = (int)"Plug_GetEngineFunction"; + VM_Call(newplug->vm, 0, Plug_FindBuiltin(NULL, ~0, &argarray)); + } + else + { + Z_Free(newplug); + newplug = NULL; + } + currentplug = NULL; + + return newplug; +} + +int Plug_Emumerated (char *name, int size, void *param) +{ + char vmname[MAX_QPATH]; + strcpy(vmname, name); + vmname[strlen(vmname) - strlen(param)] = '\0'; + Plug_Load(vmname); + + return true; +} + +int Plug_Con_Print(void *offset, unsigned int mask, const long *arg) +{ + Con_Print((char*)offset+arg[0]); + return 0; +} +int Plug_Sys_Error(void *offset, unsigned int mask, const long *arg) +{ + Sys_Error("%s", (char*)offset+arg[0]); + return 0; +} +int Plug_ExportToEngine(void *offset, unsigned int mask, const long *arg) +{ + char *name = (char*)offset+arg[0]; + if (!strcmp(name, "Tick")) + currentplug->tick = arg[1]; + else if (!strcmp(name, "ExecuteCommand")) + currentplug->executestring = arg[1]; + else + return 0; + return 1; +} +//void(char *buffer, int buffersize) +int Plug_Cmd_Args(void *offset, unsigned int mask, const long *arg) +{ + char *buffer = (char*)offset+arg[0]; + char *args; + args = Cmd_Args(); + if (strlen(args)+1>arg[1]) + return 0; + strcpy(buffer, args); + return 1; +} +//void(int num, char *buffer, int buffersize) +int Plug_Cmd_Argv(void *offset, unsigned int mask, const long *arg) +{ + char *buffer = (char*)offset+arg[1]; + char *args; + args = Cmd_Argv(arg[0]); + if (strlen(args)+1>arg[2]) + return 0; + strcpy(buffer, args); + return 1; +} +//int(void) +int Plug_Cmd_Argc(void *offset, unsigned int mask, const long *arg) +{ + return Cmd_Argc(); +} +void Plug_Init(void) +{ + Plug_RegisterBuiltin("Plug_GetEngineFunction", Plug_FindBuiltin, 0);//plugin wishes to find a builtin number. + Plug_RegisterBuiltin("Plug_ExportToEngine", Plug_ExportToEngine, 0); //plugin has a call back that we might be interested in. + Plug_RegisterBuiltin("Con_Print", Plug_Con_Print, 0); //printf is not possible - qvm floats are never doubles, vararg floats in a cdecl call are always converted to doubles. + Plug_RegisterBuiltin("Sys_Error", Plug_Sys_Error, 0); + Plug_RegisterBuiltin("Com_Error", Plug_Sys_Error, 0); //make zquake programmers happy. + + Plug_RegisterBuiltin("Cmd_Args", Plug_Cmd_Args, 0); + Plug_RegisterBuiltin("Cmd_Argc", Plug_Cmd_Argc, 0); + Plug_RegisterBuiltin("Cmd_Argv", Plug_Cmd_Argv, 0); + + + +#ifdef _WIN32 + COM_EnumerateFiles("plugins/*x86.dll", Plug_Emumerated, "x86.dll"); +#elif defined(__linux__) + COM_EnumerateFiles("plugins/*x86.so", Plug_Emumerated, "x86.so"); +#endif + COM_EnumerateFiles("plugins/*.qvm", Plug_Emumerated, ".qvm"); +} + +void Plug_Tick(void) +{ + plugin_t *plug; + for (plug = plugs; plug; plug = plug->next) + { + if (plug->tick) + { + currentplug = plug; + VM_Call(plug->vm, plug->tick, (int)(realtime*1000)); + } + } +} + +qboolean Plugin_ExecuteString(void) +{ + plugin_t *plug; + if (Cmd_Argc()>0) + { + for (plug = plugs; plug; plug = plug->next) + { + if (plug->executestring) + { + currentplug = plug; + if (VM_Call(plug->vm, plug->executestring, 0)) + return true; + } + } + } + return false; +} + +void Plug_Close(plugin_t *plug) +{ + if (plugs == plug) + plugs = plug->next; + else + { + plugin_t *prev; + for (prev = plugs; prev; prev = prev->next) + { + if (prev->next == plug) + break; + } + if (!prev) + Sys_Error("Plug_Close: not linked\n"); + prev->next = plug->next; + } + + VM_Destroy(plug->vm); +} + +void Plug_Shutdown(void) +{ + +} \ No newline at end of file