From 98fc04e0413d34d8096fe08ae1c9fa6d857e43ec Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Tue, 27 Aug 2002 04:47:49 +0000 Subject: [PATCH] Added threads and callbacks to GIB, as well as several QW callbacks dealing with player status. --- include/QF/Makefile.am | 14 ++-- include/QF/gib_function.h | 2 +- include/QF/gib_thread.h | 43 ++++++++++++ libs/util/Makefile.am | 6 +- libs/util/gib_builtin.c | 51 +++++++++++++- libs/util/gib_function.c | 25 +++---- libs/util/gib_parse.c | 10 ++- libs/util/gib_thread.c | 143 ++++++++++++++++++++++++++++++++++++++ nq/source/host.c | 5 ++ qw/source/cl_main.c | 5 ++ qw/source/cl_parse.c | 25 ++++++- qw/source/sv_main.c | 5 ++ 12 files changed, 299 insertions(+), 35 deletions(-) create mode 100644 include/QF/gib_thread.h create mode 100644 libs/util/gib_thread.c diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index 35c1d1c9c..d1d6c0f20 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -3,10 +3,10 @@ SUBDIRS = GL plugin includedir = $(prefix)/include/QF include_HEADERS = bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ console.h crc.h csqc.h cvar.h dstring.h draw.h gcc_attr.h gib_buffer.h \ - gib_builtin.h gib_function.h gib_parse.h gib_process.h gib_vars.h hash.h hl.h \ - idparse.h in_event.h info.h input.h joystick.h keys.h link.h locs.h \ - mathlib.h mdfour.h model.h modelgen.h msg.h pak.h pakfile.h pcx.h \ - plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h qargs.h qdefs.h qendian.h \ - qfplist.h qtypes.h render.h screen.h sizebuf.h skin.h sound.h \ - spritegn.h sys.h teamplay.h texture.h tga.h uint32.h va.h ver_check.h \ - vfile.h vfs.h vid.h wad.h zone.h + gib_builtin.h gib_function.h gib_parse.h gib_process.h gib_thread.h \ + gib_vars.h hash.h hl.h idparse.h in_event.h info.h input.h joystick.h \ + keys.h link.h locs.h mathlib.h mdfour.h model.h modelgen.h msg.h pak.h \ + pakfile.h pcx.h plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h qargs.h \ + qdefs.h qendian.h qfplist.h qtypes.h render.h screen.h sizebuf.h skin.h \ + sound.h spritegn.h sys.h teamplay.h texture.h tga.h uint32.h va.h \ + ver_check.h vfile.h vfs.h vid.h wad.h zone.h diff --git a/include/QF/gib_function.h b/include/QF/gib_function.h index 289919bba..2d762f173 100644 --- a/include/QF/gib_function.h +++ b/include/QF/gib_function.h @@ -36,4 +36,4 @@ typedef struct gib_function_s { void GIB_Function_Define (const char *name, const char *program); gib_function_t *GIB_Function_Find (const char *name); -void GIB_Function_Execute (gib_function_t *func); +void GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, cbuf_args_t *args); diff --git a/include/QF/gib_thread.h b/include/QF/gib_thread.h new file mode 100644 index 000000000..aadc9c01c --- /dev/null +++ b/include/QF/gib_thread.h @@ -0,0 +1,43 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2002 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +typedef struct gib_thread_s { + unsigned long int id; + struct cbuf_s *cbuf; + struct gib_thread_s *next,*prev; +} gib_thread_t; + +void GIB_Thread_Add (gib_thread_t *thread); +void GIB_Thread_Remove (gib_thread_t *thread); +gib_thread_t *GIB_Thread_Find (unsigned long int id); +gib_thread_t *GIB_Thread_New (void); +void GIB_Thread_Execute (void); +void GIB_Thread_Callback (const char *func, unsigned int argc, ...); diff --git a/libs/util/Makefile.am b/libs/util/Makefile.am index 74f029563..77af014da 100644 --- a/libs/util/Makefile.am +++ b/libs/util/Makefile.am @@ -28,9 +28,9 @@ libQFutil_la_DEPENDENCIES= libasm.la libQFutil_la_SOURCES= \ bspfile.c buildnum.c cbuf.c checksum.c cmd.c crc.c cvar.c dstring.c \ exp.c fendian.c getopt.c getopt1.c gib_buffer.c gib_builtin.c \ - gib_function.c gib_parse.c gib_process.c gib_vars.c hash.c idparse.c \ - info.c link.c mathlib.c mdfour.c msg.c ops.c pakfile.c pcx.c plugin.c \ - qargs.c qendian.c qfplist.c quakefs.c quakeio.c sizebuf.c string.c \ + gib_function.c gib_parse.c gib_process.c gib_thread.c gib_vars.c hash.c \ + idparse.c info.c link.c mathlib.c mdfour.c msg.c ops.c pakfile.c pcx.c \ + plugin.c qargs.c qendian.c qfplist.c quakefs.c quakeio.c sizebuf.c string.c \ sys.c tga.c va.c ver_check.c wad.c zone.c \ $(fnmatch) diff --git a/libs/util/gib_builtin.c b/libs/util/gib_builtin.c index d5d2b9967..74499a836 100644 --- a/libs/util/gib_builtin.c +++ b/libs/util/gib_builtin.c @@ -49,6 +49,7 @@ static const char rcsid[] = #include "QF/gib_buffer.h" #include "QF/gib_function.h" #include "QF/gib_vars.h" +#include "QF/gib_thread.h" hashtab_t *gib_builtins; @@ -334,8 +335,13 @@ GIB_Runexported_f (void) Sys_Printf ("Error: No function found for exported command \"%s\".\n" "This is most likely a bug, please report it to" "The QuakeForge developers.", Cmd_Argv(0)); - else - GIB_Function_Execute (f); + else { + cbuf_t *sub = Cbuf_New (&gib_interp); + GIB_Function_Execute (sub, f, cbuf_active->args); + cbuf_active->down = sub; + sub->up = cbuf_active; + cbuf_active->state = CBUF_STATE_STACK; + } } void @@ -377,6 +383,45 @@ GIB_String_Equal_f (void) GIB_Return (va("%i", !strcmp(GIB_Argv(1), GIB_Argv(2)))); } +void +GIB_Thread_Create_f (void) +{ + if (GIB_Argc() != 2) + Cbuf_Error ("syntax", + "thread.create: invalid syntax\n" + "usage: thread.create program"); + else { + gib_thread_t *thread = GIB_Thread_New (); + Cbuf_AddText (thread->cbuf, GIB_Argv(1)); + GIB_Thread_Add (thread); + GIB_Return (va("%lu", thread->id)); + } +} + +void +GIB_Thread_Kill_f (void) +{ + if (GIB_Argc() != 2) + Cbuf_Error ("syntax", + "thread.kill: invalid syntax\n" + "usage: thread.kill id"); + else { + gib_thread_t *thread; + cbuf_t *cur; + unsigned long int id = strtoul (GIB_Argv(1), 0, 10); + thread = GIB_Thread_Find (id); + if (!thread) { + Cbuf_Error ("thread", "thread.kill: thread %ul does not exist.", id); + return; + } + for (cur = thread->cbuf; cur; cur = cur->down) { + GIB_DATA(cur)->type = GIB_BUFFER_NORMAL; + dstring_clearstr (cur->line); + dstring_clearstr (cur->buf); + } + } +} + void GIB_Builtin_Init (void) { @@ -394,4 +439,6 @@ GIB_Builtin_Init (void) GIB_Builtin_Add ("break", GIB_Break_f, GIB_BUILTIN_NORMAL); GIB_Builtin_Add ("string.length", GIB_String_Length_f, GIB_BUILTIN_NORMAL); GIB_Builtin_Add ("string.equal", GIB_String_Equal_f, GIB_BUILTIN_NORMAL); + GIB_Builtin_Add ("thread.create", GIB_Thread_Create_f, GIB_BUILTIN_NORMAL); + GIB_Builtin_Add ("thread.kill", GIB_Thread_Kill_f, GIB_BUILTIN_NORMAL); } diff --git a/libs/util/gib_function.c b/libs/util/gib_function.c index addcf7caf..bdda5bd88 100644 --- a/libs/util/gib_function.c +++ b/libs/util/gib_function.c @@ -37,6 +37,7 @@ static const char rcsid[] = #include +#include "QF/sys.h" #include "QF/dstring.h" #include "QF/hash.h" #include "QF/cbuf.h" @@ -123,26 +124,16 @@ GIB_Function_Find (const char *name) /* GIB_Function_Execute - Creates a new buffer on the current stack - and copies the program text of a function - into it. Also sets local variables on the - buffer for all arguments passed to the - function + Prepares a buffer to execute + a GIB function with certain arguments */ void -GIB_Function_Execute (gib_function_t *func) +GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, cbuf_args_t *args) { - cbuf_t *sub = Cbuf_New (&gib_interp); int i; - Cbuf_AddText (sub, func->program->str); - if (cbuf_active->down) - Cbuf_DeleteStack (cbuf_active->down); - cbuf_active->down = sub; - sub->up = cbuf_active; - cbuf_active->state = CBUF_STATE_STACK; - - for (i = 0; i < cbuf_active->args->argc; i++) - GIB_Var_Set_Local (sub, va("%i", i), cbuf_active->args->argv[i]->str); - GIB_Var_Set_Local (sub, "argc", va("%i", cbuf_active->args->argc)); + Cbuf_AddText (cbuf, func->program->str); + for (i = 0; i < args->argc; i++) + GIB_Var_Set_Local (cbuf, va("%i", i), args->argv[i]->str); + GIB_Var_Set_Local (cbuf, "argc", va("%i", args->argc)); } diff --git a/libs/util/gib_parse.c b/libs/util/gib_parse.c index 22c6f96ea..231b6e790 100644 --- a/libs/util/gib_parse.c +++ b/libs/util/gib_parse.c @@ -466,9 +466,13 @@ void GIB_Parse_Execute_Line (cbuf_t *cbuf) if ((b = GIB_Builtin_Find (args->argv[0]->str))) b->func (); - else if ((f = GIB_Function_Find (args->argv[0]->str))) - GIB_Function_Execute (f); - else if (args->argc == 3 && !strcmp (args->argv[1]->str, "=")) { + else if ((f = GIB_Function_Find (args->argv[0]->str))) { + cbuf_t *sub = Cbuf_New (&gib_interp); + GIB_Function_Execute (sub, f, cbuf_active->args); + cbuf_active->down = sub; + sub->up = cbuf_active; + cbuf_active->state = CBUF_STATE_STACK; + } else if (args->argc == 3 && !strcmp (args->argv[1]->str, "=")) { // First, determine global versus local int glob = 0; char *c = 0; diff --git a/libs/util/gib_thread.c b/libs/util/gib_thread.c new file mode 100644 index 000000000..b337353f7 --- /dev/null +++ b/libs/util/gib_thread.c @@ -0,0 +1,143 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2002 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +static const char rcsid[] = + "$Id$"; + +#include +#include + +#include "QF/sys.h" +#include "QF/cbuf.h" +#include "QF/gib_parse.h" +#include "QF/gib_thread.h" +#include "QF/gib_function.h" +#include "QF/dstring.h" + +gib_thread_t *gib_threads; +static unsigned long int nextid = 0; + +void +GIB_Thread_Add (gib_thread_t *thread) +{ + thread->prev = 0; + thread->next = gib_threads; + if (gib_threads) + gib_threads->prev = thread; + gib_threads = thread; +} + +void +GIB_Thread_Remove (gib_thread_t *thread) +{ + if (thread == gib_threads) { + gib_threads = gib_threads->next; + if (gib_threads) + gib_threads->prev = 0; + } else { + thread->prev->next = thread->next; + if (thread->next) + thread->next->prev = thread->prev; + } +} + +gib_thread_t * +GIB_Thread_Find (unsigned long int id) +{ + gib_thread_t *cur; + + for (cur = gib_threads; cur; cur=cur->next) + if (cur->id == id) + return cur; + return 0; +} + +gib_thread_t * +GIB_Thread_New (void) +{ + gib_thread_t *new = calloc (1, sizeof(gib_thread_t)); + new->cbuf = Cbuf_New (&gib_interp); + new->id = nextid; + nextid++; + return new; +} + +void +GIB_Thread_Delete (gib_thread_t *thread) +{ + Cbuf_DeleteStack (thread->cbuf); + free (thread); +} + +void +GIB_Thread_Execute (void) +{ + gib_thread_t *cur, *tmp; + if (!gib_threads) + return; + + for (cur = gib_threads; cur->next; cur = cur->next); + for (; cur; cur = tmp) { + tmp = cur->prev; + if (!cur->cbuf->buf->str[0] && !cur->cbuf->down) { + GIB_Thread_Remove (cur); + GIB_Thread_Delete (cur); + } else + Cbuf_Execute_Stack (cur->cbuf); + } +} + +void +GIB_Thread_Callback (const char *func, unsigned int argc, ...) +{ + gib_function_t *f = GIB_Function_Find (func); + gib_thread_t *thread; + cbuf_args_t *args; + va_list ap; + unsigned int i; + + if (!f) + return; + + thread = GIB_Thread_New (); + args = Cbuf_ArgsNew (); + + va_start (ap, argc); + + Cbuf_ArgsAdd (args, func); + for (i = 0; i < argc; i++) + Cbuf_ArgsAdd (args, va_arg (ap, const char *)); + + va_end (ap); + + GIB_Function_Execute (thread->cbuf, f, args); + GIB_Thread_Add (thread); + Cbuf_ArgsDelete (args); +} \ No newline at end of file diff --git a/nq/source/host.c b/nq/source/host.c index b6ce36225..16e1b52e8 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -50,6 +50,7 @@ static const char rcsid[] = #include "QF/sys.h" #include "QF/va.h" #include "QF/vid.h" +#include "QF/gib_thread.h" #include "buildnum.h" #include "chase.h" @@ -605,6 +606,10 @@ _Host_Frame (float time) IN_Commands (); } + // process gib threads + + GIB_Thread_Execute (); + // process console commands cmd_source = src_command; Cbuf_Execute_Stack (host_cbuf); diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index d2772a9a0..37904bcfd 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -79,6 +79,7 @@ static const char rcsid[] = #include "QF/va.h" #include "QF/vfs.h" #include "QF/vid.h" +#include "QF/gib_thread.h" #include "bothdefs.h" #include "buildnum.h" @@ -1531,6 +1532,10 @@ Host_Frame (float time) // allow mouses or other external controllers to add commands IN_Commands (); + // process gib threads + + GIB_Thread_Execute (); + // process console commands Cbuf_Execute_Stack (cl_cbuf); diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 7cea08545..394314529 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -57,6 +57,7 @@ static const char rcsid[] = #include "QF/vfile.h" #include "QF/dstring.h" #include "QF/gib_vars.h" +#include "QF/gib_thread.h" #include "bothdefs.h" #include "cl_ents.h" @@ -775,7 +776,7 @@ CL_ParseModellist (void) cl_playerindex = nummodels; else if (!strcmp (cl.model_name[nummodels], "progs/flag.mdl")) cl_flagindex = nummodels; - // for deadbodyfilter & gibfilter + // for deadbodyfilter & gib filter else if (!strcmp (cl.model_name[nummodels], "progs/h_player.mdl")) cl_h_playerindex = nummodels; else if (!strcmp (cl.model_name[nummodels], "progs/gib1.mdl")) @@ -1055,7 +1056,8 @@ void CL_SetStat (int stat, int value) { int j; - const char *arm; + unsigned int changed; + const char *arm, *cb; if (stat < 0 || stat >= MAX_CL_STATS) Host_Error ("CL_SetStat: %i is invalid", stat); @@ -1064,7 +1066,11 @@ CL_SetStat (int stat, int value) switch (stat) { case STAT_ITEMS: + changed = cl.stats[STAT_ITEMS] ^ value; Sbar_Changed (); + if ((changed & IT_KEY1 || changed & IT_KEY2) && + (cb = GIB_Var_Get_Global ("player.key.callback"))) + GIB_Thread_Callback (cb, 0); GIB_Var_Set_Global ("player.key.1", value & IT_KEY1 ? "1" : "0"); GIB_Var_Set_Global ("player.key.2", value & IT_KEY2 ? "1" : "0"); if (value & IT_ARMOR1) @@ -1076,6 +1082,9 @@ CL_SetStat (int stat, int value) else arm = "none"; GIB_Var_Set_Global ("player.armor.type", arm); + if ((changed & 127 || changed & IT_AXE) && + (cb = GIB_Var_Get_Global ("player.weapon.callback"))) + GIB_Thread_Callback (cb, 0); GIB_Var_Set_Global ("player.weapon.1", value & IT_AXE ? "1" : "0"); for (j = 0; j < 7; j++) GIB_Var_Set_Global (va("player.weapon.%i", j+2), @@ -1085,23 +1094,35 @@ CL_SetStat (int stat, int value) cl.item_gettime[j] = cl.time; break; case STAT_HEALTH: + if ((cb = GIB_Var_Get_Global ("player.health.callback"))) + GIB_Thread_Callback (cb, 1, va("%i", value)); GIB_Var_Set_Global ("player.health", va("%i", value)); if (value <= 0) Team_Dead (); break; case STAT_ARMOR: + if ((cb = GIB_Var_Get_Global ("player.armor.callback"))) + GIB_Thread_Callback (cb, 1, va("%i", value)); GIB_Var_Set_Global ("player.armor", va("%i", value)); break; case STAT_SHELLS: + if ((cb = GIB_Var_Get_Global ("player.ammo.shells.callback"))) + GIB_Thread_Callback (cb, 1, va("%i", value)); GIB_Var_Set_Global ("player.ammo.shells", va("%i", value)); break; case STAT_NAILS: + if ((cb = GIB_Var_Get_Global ("player.ammo.nails.callback"))) + GIB_Thread_Callback (cb, 1, va("%i", value)); GIB_Var_Set_Global ("player.ammo.nails", va("%i", value)); break; case STAT_ROCKETS: + if ((cb = GIB_Var_Get_Global ("player.ammo.rockets.callback"))) + GIB_Thread_Callback (cb, 1, va("%i", value)); GIB_Var_Set_Global ("player.ammo.rockets", va("%i", value)); break; case STAT_CELLS: + if ((cb = GIB_Var_Get_Global ("player.ammo.cells.callback"))) + GIB_Thread_Callback (cb, 1, va("%i", value)); GIB_Var_Set_Global ("player.ammo.cells", va("%i", value)); break; } diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index 9aff32b16..d9970d0bf 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -63,6 +63,7 @@ static const char rcsid[] = #include "QF/idparse.h" #include "QF/gib_parse.h" #include "QF/gib_buffer.h" +#include "QF/gib_thread.h" #include "QF/cmd.h" #include "QF/console.h" #include "QF/cvar.h" @@ -1902,6 +1903,10 @@ SV_Frame (float time) // check for commands typed to the host SV_GetConsoleCommands (); + // process gib threads + + GIB_Thread_Execute (); + // process console commands Cbuf_Execute_Stack (sv_cbuf);