2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 static prvm_prog_t prog_list[PRVM_MAXPROGS];
29 int prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
31 ddef_t *PRVM_ED_FieldAtOfs(int ofs);
32 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash);
34 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
35 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
36 // LordHavoc: counts usage of each QuakeC statement
37 cvar_t prvm_statementprofiling = {0, "prvm_statementprofiling", "0", "counts how many times each QuakeC statement has been executed, these counts are displayed in prvm_printfunction output (if enabled)"};
38 cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"};
39 cvar_t prvm_leaktest = {0, "prvm_leaktest", "0", "try to detect memory leaks in strings or entities"};
40 cvar_t prvm_leaktest_ignore_classnames = {0, "prvm_leaktest_ignore_classnames", "", "classnames of entities to NOT leak check because they are found by find(world, classname, ...) but are actually spawned by QC code (NOT map entities)"};
41 cvar_t prvm_errordump = {0, "prvm_errordump", "0", "write a savegame on crash to crash-server.dmp"};
43 qboolean prvm_runawaycheck = true;
45 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
46 // enables detection of out of bounds memory access in the QuakeC code being run (in other words, prevents really exceedingly bad QuakeC code from doing nasty things to your computer)
47 qboolean prvm_boundscheck = true;
49 extern sizebuf_t vm_tempstringsbuf;
51 //============================================================================
59 void PRVM_MEM_Alloc(void)
63 // reserve space for the null entity aka world
64 // check bound of max_edicts
65 prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
66 prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
68 // edictprivate_size has to be min as big prvm_edict_private_t
69 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
72 prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
74 // alloc edict private space
75 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
78 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
81 for(i = 0; i < prog->max_edicts; i++)
83 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
84 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
90 PRVM_MEM_IncreaseEdicts
93 void PRVM_MEM_IncreaseEdicts(void)
96 int oldmaxedicts = prog->max_edicts;
97 void *oldedictsfields = prog->edictsfields;
98 void *oldedictprivate = prog->edictprivate;
100 if(prog->max_edicts >= prog->limit_edicts)
103 PRVM_GCALL(begin_increase_edicts)();
106 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
108 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
109 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
111 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
112 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
114 //set e and v pointers
115 for(i = 0; i < prog->max_edicts; i++)
117 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
118 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
121 PRVM_GCALL(end_increase_edicts)();
123 Mem_Free(oldedictsfields);
124 Mem_Free(oldedictprivate);
127 //============================================================================
130 int PRVM_ED_FindFieldOffset(const char *field)
133 d = PRVM_ED_FindField(field);
139 int PRVM_ED_FindGlobalOffset(const char *global)
142 d = PRVM_ED_FindGlobal(global);
148 func_t PRVM_ED_FindFunctionOffset(const char *function)
151 f = PRVM_ED_FindFunction(function);
154 return (func_t)(f - prog->functions);
157 qboolean PRVM_ProgLoaded(int prognr)
159 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
162 return (prog_list[prognr].loaded ? TRUE : FALSE);
167 PRVM_SetProgFromString
170 // perhaps add a return value when the str doesnt exist
171 qboolean PRVM_SetProgFromString(const char *str)
174 for(; i < PRVM_MAXPROGS ; i++)
175 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
177 if(prog_list[i].loaded)
179 prog = &prog_list[i];
184 Con_Printf("%s not loaded !\n",PRVM_NAME);
189 Con_Printf("Invalid program name %s !\n", str);
198 void PRVM_SetProg(int prognr)
200 if(0 <= prognr && prognr < PRVM_MAXPROGS)
202 if(prog_list[prognr].loaded)
203 prog = &prog_list[prognr];
205 PRVM_ERROR("%i not loaded !", prognr);
208 PRVM_ERROR("Invalid program number %i", prognr);
215 Sets everything to NULL
218 void PRVM_ED_ClearEdict (prvm_edict_t *e)
220 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
221 e->priv.required->free = false;
223 // AK: Let the init_edict function determine if something needs to be initialized
224 PRVM_GCALL(init_edict)(e);
227 const char *PRVM_AllocationOrigin()
230 if(prog->leaktest_active)
231 if(prog->depth > 0) // actually in QC code and not just parsing the entities block of a map/savegame
233 buf = (char *)PRVM_Alloc(128);
234 PRVM_ShortStackTrace(buf, 128);
243 Either finds a free edict, or allocates a new one.
244 Try to avoid reusing an entity that was recently freed, because it
245 can cause the client to think the entity morphed into something else
246 instead of being removed and recreated, which can cause interpolated
247 angles and bad trails.
250 prvm_edict_t *PRVM_ED_Alloc (void)
255 // the client qc dont need maxclients
256 // thus it doesnt need to use svs.maxclients
257 // AK: changed i=svs.maxclients+1
258 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
259 // although the menu/client has no world
260 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
262 e = PRVM_EDICT_NUM(i);
263 // the first couple seconds of server time can involve a lot of
264 // freeing and allocating, so relax the replacement policy
265 if (e->priv.required->free && ( e->priv.required->freetime < 2 || prog->globaloffsets.time < 0 || (PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float - e->priv.required->freetime) > 0.5 ) )
267 PRVM_ED_ClearEdict (e);
268 e->priv.required->allocation_origin = PRVM_AllocationOrigin();
273 if (i == prog->limit_edicts)
274 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
277 if (prog->num_edicts >= prog->max_edicts)
278 PRVM_MEM_IncreaseEdicts();
280 e = PRVM_EDICT_NUM(i);
281 PRVM_ED_ClearEdict (e);
283 e->priv.required->allocation_origin = PRVM_AllocationOrigin();
292 Marks the edict as free
293 FIXME: walk all entities and NULL out references to this entity
296 void PRVM_ED_Free (prvm_edict_t *ed)
298 // dont delete the null entity (world) or reserved edicts
299 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
302 PRVM_GCALL(free_edict)(ed);
304 ed->priv.required->free = true;
305 ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0;
306 if(ed->priv.required->allocation_origin)
308 PRVM_Free((char *)ed->priv.required->allocation_origin);
309 ed->priv.required->allocation_origin = NULL;
313 //===========================================================================
320 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
325 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
327 def = &prog->globaldefs[i];
339 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
344 for (i=0 ; i<prog->progs->numfielddefs ; i++)
346 def = &prog->fielddefs[i];
358 ddef_t *PRVM_ED_FindField (const char *name)
363 for (i=0 ; i<prog->progs->numfielddefs ; i++)
365 def = &prog->fielddefs[i];
366 if (!strcmp(PRVM_GetString(def->s_name), name))
377 ddef_t *PRVM_ED_FindGlobal (const char *name)
382 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
384 def = &prog->globaldefs[i];
385 if (!strcmp(PRVM_GetString(def->s_name), name))
397 mfunction_t *PRVM_ED_FindFunction (const char *name)
402 for (i=0 ; i<prog->progs->numfunctions ; i++)
404 func = &prog->functions[i];
405 if (!strcmp(PRVM_GetString(func->s_name), name))
416 Returns a string describing *data in a type specific manner
419 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
421 static char line[MAX_INPUTLINE];
426 type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
431 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
435 if (n < 0 || n >= prog->limit_edicts)
436 dpsnprintf (line, sizeof(line), "entity %i (invalid!)", n);
438 dpsnprintf (line, sizeof(line), "entity %i", n);
441 f = prog->functions + val->function;
442 dpsnprintf (line, sizeof(line), "%s()", PRVM_GetString(f->s_name));
445 def = PRVM_ED_FieldAtOfs ( val->_int );
446 dpsnprintf (line, sizeof(line), ".%s", PRVM_GetString(def->s_name));
449 dpsnprintf (line, sizeof(line), "void");
452 // LordHavoc: changed from %5.1f to %10.4f
453 dpsnprintf (line, sizeof(line), "%10.4f", val->_float);
456 // LordHavoc: changed from %5.1f to %10.4f
457 dpsnprintf (line, sizeof(line), "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
460 dpsnprintf (line, sizeof(line), "pointer");
463 dpsnprintf (line, sizeof(line), "bad type %i", (int) type);
474 Returns a string describing *data in a type specific manner
475 Easier to parse than PR_ValueString
478 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
480 static char line[MAX_INPUTLINE];
486 type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
491 // Parse the string a bit to turn special characters
492 // (like newline, specifically) into escape codes,
493 // this fixes saving games from various mods
494 s = PRVM_GetString (val->string);
495 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
524 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
527 f = prog->functions + val->function;
528 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
531 def = PRVM_ED_FieldAtOfs ( val->_int );
532 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
535 dpsnprintf (line, sizeof (line), "void");
538 dpsnprintf (line, sizeof (line), "%f", val->_float);
541 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
544 dpsnprintf (line, sizeof (line), "bad type %i", type);
555 Returns a string with a description and the contents of a global,
556 padded to 20 field width
559 char *PRVM_GlobalString (int ofs)
565 static char line[128];
567 val = (void *)&prog->globals.generic[ofs];
568 def = PRVM_ED_GlobalAtOfs(ofs);
570 dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
573 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
574 dpsnprintf (line, sizeof(line), "%s (=%s)", PRVM_GetString(def->s_name), s);
578 //for ( ; i<20 ; i++)
579 // strcat (line," ");
585 char *PRVM_GlobalStringNoContents (int ofs)
589 static char line[128];
591 def = PRVM_ED_GlobalAtOfs(ofs);
593 dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
595 dpsnprintf (line, sizeof(line), "%s", PRVM_GetString(def->s_name));
598 //for ( ; i<20 ; i++)
599 // strcat (line," ");
613 // LordHavoc: optimized this to print out much more quickly (tempstring)
614 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
615 void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
623 char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
625 if (ed->priv.required->free)
627 Con_Printf("%s: FREE\n",PRVM_NAME);
632 dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
633 for (i=1 ; i<prog->progs->numfielddefs ; i++)
635 d = &prog->fielddefs[i];
636 name = PRVM_GetString(d->s_name);
637 if (name[strlen(name)-2] == '_')
638 continue; // skip _x, _y, _z vars
640 // Check Field Name Wildcard
641 if(wildcard_fieldname)
642 if( !matchpattern(name, wildcard_fieldname, 1) )
643 // Didn't match; skip
646 v = (int *)((char *)ed->fields.vp + d->ofs*4);
648 // if the value is still all 0, skip the field
649 type = d->type & ~DEF_SAVEGLOBAL;
651 for (j=0 ; j<prvm_type_size[type] ; j++)
654 if (j == prvm_type_size[type])
657 if (strlen(name) > sizeof(tempstring2)-4)
659 memcpy (tempstring2, name, sizeof(tempstring2)-4);
660 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
661 tempstring2[sizeof(tempstring2)-1] = 0;
664 strlcat(tempstring, name, sizeof(tempstring));
665 for (l = strlen(name);l < 14;l++)
666 strlcat(tempstring, " ", sizeof(tempstring));
667 strlcat(tempstring, " ", sizeof(tempstring));
669 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
670 if (strlen(name) > sizeof(tempstring2)-4)
672 memcpy (tempstring2, name, sizeof(tempstring2)-4);
673 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
674 tempstring2[sizeof(tempstring2)-1] = 0;
677 strlcat(tempstring, name, sizeof(tempstring));
678 strlcat(tempstring, "\n", sizeof(tempstring));
679 if (strlen(tempstring) >= sizeof(tempstring)/2)
681 Con_Print(tempstring);
686 Con_Print(tempstring);
696 extern cvar_t developer_entityparsing;
697 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
707 if (ed->priv.required->free)
713 for (i=1 ; i<prog->progs->numfielddefs ; i++)
715 d = &prog->fielddefs[i];
716 name = PRVM_GetString(d->s_name);
718 if(developer_entityparsing.integer)
719 Con_Printf("PRVM_ED_Write: at entity %d field %s\n", PRVM_NUM_FOR_EDICT(ed), name);
721 if (name[strlen(name)-2] == '_')
722 continue; // skip _x, _y, _z vars
724 v = (int *)((char *)ed->fields.vp + d->ofs*4);
726 // if the value is still all 0, skip the field
727 type = d->type & ~DEF_SAVEGLOBAL;
728 for (j=0 ; j<prvm_type_size[type] ; j++)
731 if (j == prvm_type_size[type])
734 FS_Printf(f,"\"%s\" ",name);
735 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
741 void PRVM_ED_PrintNum (int ent, const char *wildcard_fieldname)
743 PRVM_ED_Print(PRVM_EDICT_NUM(ent), wildcard_fieldname);
748 PRVM_ED_PrintEdicts_f
750 For debugging, prints all the entities in the current server
753 void PRVM_ED_PrintEdicts_f (void)
756 const char *wildcard_fieldname;
758 if(Cmd_Argc() < 2 || Cmd_Argc() > 3)
760 Con_Print("prvm_edicts <program name> <optional field name wildcard>\n");
765 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
769 wildcard_fieldname = Cmd_Argv(2);
771 wildcard_fieldname = NULL;
773 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
774 for (i=0 ; i<prog->num_edicts ; i++)
775 PRVM_ED_PrintNum (i, wildcard_fieldname);
784 For debugging, prints a single edict
787 void PRVM_ED_PrintEdict_f (void)
790 const char *wildcard_fieldname;
792 if(Cmd_Argc() < 3 || Cmd_Argc() > 4)
794 Con_Print("prvm_edict <program name> <edict number> <optional field name wildcard>\n");
799 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
802 i = atoi (Cmd_Argv(2));
803 if (i >= prog->num_edicts)
805 Con_Print("Bad edict number\n");
810 // Optional Wildcard Provided
811 wildcard_fieldname = Cmd_Argv(3);
814 wildcard_fieldname = NULL;
815 PRVM_ED_PrintNum (i, wildcard_fieldname);
827 // 2 possibilities : 1. just displaying the active edict count
828 // 2. making a function pointer [x]
829 void PRVM_ED_Count_f (void)
837 Con_Print("prvm_count <program name>\n");
842 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
845 if(prog->count_edicts)
846 prog->count_edicts();
850 for (i=0 ; i<prog->num_edicts ; i++)
852 ent = PRVM_EDICT_NUM(i);
853 if (ent->priv.required->free)
858 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
859 Con_Printf("active :%3i\n", active);
866 ==============================================================================
870 FIXME: need to tag constants, doesn't really work
871 ==============================================================================
879 void PRVM_ED_WriteGlobals (qfile_t *f)
887 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
889 def = &prog->globaldefs[i];
891 if ( !(def->type & DEF_SAVEGLOBAL) )
893 type &= ~DEF_SAVEGLOBAL;
895 if (type != ev_string && type != ev_float && type != ev_entity)
898 name = PRVM_GetString(def->s_name);
900 if(developer_entityparsing.integer)
901 Con_Printf("PRVM_ED_WriteGlobals: at global %s\n", name);
903 FS_Printf(f,"\"%s\" ", name);
904 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
914 void PRVM_ED_ParseGlobals (const char *data)
916 char keyname[MAX_INPUTLINE];
922 if (!COM_ParseToken_Simple(&data, false, false))
923 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
924 if (com_token[0] == '}')
927 if (developer_entityparsing.integer)
928 Con_Printf("Key: \"%s\"", com_token);
930 strlcpy (keyname, com_token, sizeof(keyname));
933 if (!COM_ParseToken_Simple(&data, false, true))
934 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
936 if (developer_entityparsing.integer)
937 Con_Printf(" \"%s\"\n", com_token);
939 if (com_token[0] == '}')
940 PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
942 key = PRVM_ED_FindGlobal (keyname);
945 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
949 if (!PRVM_ED_ParseEpair(NULL, key, com_token, true))
950 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
954 //============================================================================
961 Can parse either fields or globals
962 returns false if error
965 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
974 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
976 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
977 switch (key->type & ~DEF_SAVEGLOBAL)
980 l = (int)strlen(s) + 1;
981 val->string = PRVM_AllocString(l, &new_p);
982 for (i = 0;i < l;i++)
984 if (s[i] == '\\' && s[i+1] && parsebackslash)
989 else if (s[i] == 'r')
1000 while (*s && ISWHITESPACE(*s))
1002 val->_float = atof(s);
1006 for (i = 0;i < 3;i++)
1008 while (*s && ISWHITESPACE(*s))
1012 val->vector[i] = atof(s);
1013 while (!ISWHITESPACE(*s))
1021 while (*s && ISWHITESPACE(*s))
1024 if (i >= prog->limit_edicts)
1025 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (unsigned int)i, (unsigned int)MAX_EDICTS, PRVM_NAME);
1026 while (i >= prog->max_edicts)
1027 PRVM_MEM_IncreaseEdicts();
1028 // if IncreaseEdicts was called the base pointer needs to be updated
1030 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
1031 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
1037 Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, PRVM_NAME);
1040 def = PRVM_ED_FindField(s + 1);
1043 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
1046 val->_int = def->ofs;
1050 func = PRVM_ED_FindFunction(s);
1053 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
1056 val->function = func - prog->functions;
1060 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
1070 Console command to send a string to QC function GameCommand of the
1074 sv_cmd adminmsg 3 "do not teamkill"
1075 cl_cmd someclientcommand
1076 menu_cmd somemenucommand
1078 All progs can support this extension; sg calls it in server QC, cg in client
1082 void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
1086 Con_Printf("%s text...\n", whichcmd);
1091 if(!PRVM_SetProgFromString(whichprogs))
1092 // note: this is not PRVM_SetProg because that one aborts "hard" using PRVM_Error
1093 // also, it makes printing error messages easier!
1095 Con_Printf("%s program not loaded.\n", whichprogs);
1099 if(!prog->funcoffsets.GameCommand)
1101 Con_Printf("%s program do not support GameCommand!\n", whichprogs);
1105 int restorevm_tempstringsbuf_cursize;
1110 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1111 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
1112 PRVM_ExecuteProgram (prog->funcoffsets.GameCommand, "QC function GameCommand is missing");
1113 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1118 void PRVM_GameCommand_Server_f(void)
1120 PRVM_GameCommand("server", "sv_cmd");
1122 void PRVM_GameCommand_Client_f(void)
1124 PRVM_GameCommand("client", "cl_cmd");
1126 void PRVM_GameCommand_Menu_f(void)
1128 PRVM_GameCommand("menu", "menu_cmd");
1135 Console command to set a field of a specified edict
1138 void PRVM_ED_EdictSet_f(void)
1145 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1150 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1152 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1156 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1158 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1159 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1161 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4), true);
1167 ====================
1170 Parses an edict out of the given string, returning the new position
1171 ed should be a properly initialized empty edict.
1172 Used for initial level load and for savegames.
1173 ====================
1175 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1185 // go through all the dictionary pairs
1189 if (!COM_ParseToken_Simple(&data, false, false))
1190 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1191 if (developer_entityparsing.integer)
1192 Con_Printf("Key: \"%s\"", com_token);
1193 if (com_token[0] == '}')
1196 // anglehack is to allow QuakeEd to write single scalar angles
1197 // and allow them to be turned into vectors. (FIXME...)
1198 if (!strcmp(com_token, "angle"))
1200 strlcpy (com_token, "angles", sizeof(com_token));
1206 // FIXME: change light to _light to get rid of this hack
1207 if (!strcmp(com_token, "light"))
1208 strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def
1210 strlcpy (keyname, com_token, sizeof(keyname));
1212 // another hack to fix keynames with trailing spaces
1213 n = strlen(keyname);
1214 while (n && keyname[n-1] == ' ')
1221 if (!COM_ParseToken_Simple(&data, false, false))
1222 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1223 if (developer_entityparsing.integer)
1224 Con_Printf(" \"%s\"\n", com_token);
1226 if (com_token[0] == '}')
1227 PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1231 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1235 // keynames with a leading underscore are used for utility comments,
1236 // and are immediately discarded by quake
1237 if (keyname[0] == '_')
1240 key = PRVM_ED_FindField (keyname);
1243 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1250 strlcpy (temp, com_token, sizeof(temp));
1251 dpsnprintf (com_token, sizeof(com_token), "0 %s 0", temp);
1254 if (!PRVM_ED_ParseEpair(ent, key, com_token, strcmp(keyname, "wad") != 0))
1255 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1259 ent->priv.required->free = true;
1267 PRVM_ED_LoadFromFile
1269 The entities are directly placed in the array, rather than allocated with
1270 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1271 number references out of order.
1273 Creates a server's entity / program execution context by
1274 parsing textual entity definitions out of an ent file.
1276 Used for both fresh maps and savegame loads. A fresh map would also need
1277 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1280 void PRVM_ED_LoadFromFile (const char *data)
1283 int parsed, inhibited, spawned, died;
1284 const char *funcname;
1296 // parse the opening brace
1297 if (!COM_ParseToken_Simple(&data, false, false))
1299 if (com_token[0] != '{')
1300 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1302 // CHANGED: this is not conform to PR_LoadFromFile
1303 if(prog->loadintoworld)
1305 prog->loadintoworld = false;
1306 ent = PRVM_EDICT_NUM(0);
1309 ent = PRVM_ED_Alloc();
1312 if (ent != prog->edicts) // hack
1313 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1315 data = PRVM_ED_ParseEdict (data, ent);
1318 // remove the entity ?
1319 if(prog->load_edict && !prog->load_edict(ent))
1326 if (prog->funcoffsets.SV_OnEntityPreSpawnFunction)
1329 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1330 PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityPreSpawnFunction, "QC function SV_OnEntityPreSpawnFunction is missing");
1333 if(ent->priv.required->free)
1340 // immediately call spawn function, but only if there is a self global and a classname
1342 if(!ent->priv.required->free)
1343 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1345 string_t handle = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1348 Con_Print("No classname for:\n");
1349 PRVM_ED_Print(ent, NULL);
1354 // look for the spawn function
1355 funcname = PRVM_GetString(handle);
1356 func = PRVM_ED_FindFunction (va("spawnfunc_%s", funcname));
1358 if(prog->globaloffsets.require_spawnfunc_prefix < 0)
1359 func = PRVM_ED_FindFunction (funcname);
1363 // check for OnEntityNoSpawnFunction
1364 if (prog->funcoffsets.SV_OnEntityNoSpawnFunction)
1367 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1368 PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityNoSpawnFunction, "QC function SV_OnEntityNoSpawnFunction is missing");
1372 if (developer.integer) // don't confuse non-developers with errors
1374 Con_Print("No spawn function for:\n");
1375 PRVM_ED_Print(ent, NULL);
1378 continue; // not included in "inhibited" count
1384 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1385 PRVM_ExecuteProgram (func - prog->functions, "");
1389 if(!ent->priv.required->free)
1390 if (prog->funcoffsets.SV_OnEntityPostSpawnFunction)
1393 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1394 PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityPostSpawnFunction, "QC function SV_OnEntityPostSpawnFunction is missing");
1398 if (ent->priv.required->free)
1402 Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died);
1405 void PRVM_FindOffsets(void)
1407 // field and global searches use -1 for NULL
1408 memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1409 memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1410 // functions use 0 for NULL
1411 memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1413 // server and client qc use a lot of similar fields, so this is combined
1414 prog->fieldoffsets.SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
1415 prog->fieldoffsets.SendFlags = PRVM_ED_FindFieldOffset("SendFlags");
1416 prog->fieldoffsets.Version = PRVM_ED_FindFieldOffset("Version");
1417 prog->fieldoffsets.alpha = PRVM_ED_FindFieldOffset("alpha");
1418 prog->fieldoffsets.ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
1419 prog->fieldoffsets.ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1420 prog->fieldoffsets.ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1421 prog->fieldoffsets.ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
1422 prog->fieldoffsets.ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
1423 prog->fieldoffsets.ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
1424 prog->fieldoffsets.ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
1425 prog->fieldoffsets.angles = PRVM_ED_FindFieldOffset("angles");
1426 prog->fieldoffsets.button3 = PRVM_ED_FindFieldOffset("button3");
1427 prog->fieldoffsets.button4 = PRVM_ED_FindFieldOffset("button4");
1428 prog->fieldoffsets.button5 = PRVM_ED_FindFieldOffset("button5");
1429 prog->fieldoffsets.button6 = PRVM_ED_FindFieldOffset("button6");
1430 prog->fieldoffsets.button7 = PRVM_ED_FindFieldOffset("button7");
1431 prog->fieldoffsets.button8 = PRVM_ED_FindFieldOffset("button8");
1432 prog->fieldoffsets.button9 = PRVM_ED_FindFieldOffset("button9");
1433 prog->fieldoffsets.button10 = PRVM_ED_FindFieldOffset("button10");
1434 prog->fieldoffsets.button11 = PRVM_ED_FindFieldOffset("button11");
1435 prog->fieldoffsets.button12 = PRVM_ED_FindFieldOffset("button12");
1436 prog->fieldoffsets.button13 = PRVM_ED_FindFieldOffset("button13");
1437 prog->fieldoffsets.button14 = PRVM_ED_FindFieldOffset("button14");
1438 prog->fieldoffsets.button15 = PRVM_ED_FindFieldOffset("button15");
1439 prog->fieldoffsets.button16 = PRVM_ED_FindFieldOffset("button16");
1440 prog->fieldoffsets.buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
1441 prog->fieldoffsets.buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
1442 prog->fieldoffsets.chain = PRVM_ED_FindFieldOffset("chain");
1443 prog->fieldoffsets.classname = PRVM_ED_FindFieldOffset("classname");
1444 prog->fieldoffsets.clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
1445 prog->fieldoffsets.color = PRVM_ED_FindFieldOffset("color");
1446 prog->fieldoffsets.colormod = PRVM_ED_FindFieldOffset("colormod");
1447 prog->fieldoffsets.contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
1448 prog->fieldoffsets.cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
1449 prog->fieldoffsets.cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
1450 prog->fieldoffsets.cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1451 prog->fieldoffsets.cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1452 prog->fieldoffsets.cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
1453 prog->fieldoffsets.customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
1454 prog->fieldoffsets.dimension_hit = PRVM_ED_FindFieldOffset("dimension_hit");
1455 prog->fieldoffsets.dimension_solid = PRVM_ED_FindFieldOffset("dimension_solid");
1456 prog->fieldoffsets.disableclientprediction = PRVM_ED_FindFieldOffset("disableclientprediction");
1457 prog->fieldoffsets.dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1458 prog->fieldoffsets.drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
1459 prog->fieldoffsets.exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1460 prog->fieldoffsets.fatness = PRVM_ED_FindFieldOffset("fatness");
1461 prog->fieldoffsets.forceshader = PRVM_ED_FindFieldOffset("forceshader");
1462 prog->fieldoffsets.frame = PRVM_ED_FindFieldOffset("frame");
1463 prog->fieldoffsets.frame1time = PRVM_ED_FindFieldOffset("frame1time");
1464 prog->fieldoffsets.frame2 = PRVM_ED_FindFieldOffset("frame2");
1465 prog->fieldoffsets.frame2time = PRVM_ED_FindFieldOffset("frame2time");
1466 prog->fieldoffsets.shadertime = PRVM_ED_FindFieldOffset("shadertime");
1467 prog->fieldoffsets.fullbright = PRVM_ED_FindFieldOffset("fullbright");
1468 prog->fieldoffsets.glow_color = PRVM_ED_FindFieldOffset("glow_color");
1469 prog->fieldoffsets.glow_size = PRVM_ED_FindFieldOffset("glow_size");
1470 prog->fieldoffsets.glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
1471 prog->fieldoffsets.gravity = PRVM_ED_FindFieldOffset("gravity");
1472 prog->fieldoffsets.groundentity = PRVM_ED_FindFieldOffset("groundentity");
1473 prog->fieldoffsets.hull = PRVM_ED_FindFieldOffset("hull");
1474 prog->fieldoffsets.ideal_yaw = PRVM_ED_FindFieldOffset("ideal_yaw");
1475 prog->fieldoffsets.idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
1476 prog->fieldoffsets.items2 = PRVM_ED_FindFieldOffset("items2");
1477 prog->fieldoffsets.lerpfrac = PRVM_ED_FindFieldOffset("lerpfrac");
1478 prog->fieldoffsets.light_lev = PRVM_ED_FindFieldOffset("light_lev");
1479 prog->fieldoffsets.message = PRVM_ED_FindFieldOffset("message");
1480 prog->fieldoffsets.modelflags = PRVM_ED_FindFieldOffset("modelflags");
1481 prog->fieldoffsets.movement = PRVM_ED_FindFieldOffset("movement");
1482 prog->fieldoffsets.movetypesteplandevent = PRVM_ED_FindFieldOffset("movetypesteplandevent");
1483 prog->fieldoffsets.netaddress = PRVM_ED_FindFieldOffset("netaddress");
1484 prog->fieldoffsets.nextthink = PRVM_ED_FindFieldOffset("nextthink");
1485 prog->fieldoffsets.nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
1486 prog->fieldoffsets.pflags = PRVM_ED_FindFieldOffset("pflags");
1487 prog->fieldoffsets.ping = PRVM_ED_FindFieldOffset("ping");
1488 prog->fieldoffsets.pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
1489 prog->fieldoffsets.playermodel = PRVM_ED_FindFieldOffset("playermodel");
1490 prog->fieldoffsets.playerskin = PRVM_ED_FindFieldOffset("playerskin");
1491 prog->fieldoffsets.pmodel = PRVM_ED_FindFieldOffset("pmodel");
1492 prog->fieldoffsets.punchvector = PRVM_ED_FindFieldOffset("punchvector");
1493 prog->fieldoffsets.renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1494 prog->fieldoffsets.renderflags = PRVM_ED_FindFieldOffset("renderflags");
1495 prog->fieldoffsets.rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1496 prog->fieldoffsets.scale = PRVM_ED_FindFieldOffset("scale");
1497 prog->fieldoffsets.style = PRVM_ED_FindFieldOffset("style");
1498 prog->fieldoffsets.tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
1499 prog->fieldoffsets.tag_index = PRVM_ED_FindFieldOffset("tag_index");
1500 prog->fieldoffsets.think = PRVM_ED_FindFieldOffset("think");
1501 prog->fieldoffsets.viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
1502 prog->fieldoffsets.viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
1503 prog->fieldoffsets.yaw_speed = PRVM_ED_FindFieldOffset("yaw_speed");
1504 prog->fieldoffsets.clientcamera = PRVM_ED_FindFieldOffset("clientcamera");
1505 prog->fieldoffsets.clientstatus = PRVM_ED_FindFieldOffset("clientstatus");
1506 prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1507 prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1508 prog->funcoffsets.CSQC_Ent_Update = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1509 prog->funcoffsets.CSQC_Ent_Spawn = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
1510 prog->funcoffsets.CSQC_Event = PRVM_ED_FindFunctionOffset("CSQC_Event");
1511 prog->funcoffsets.CSQC_Event_Sound = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
1512 prog->funcoffsets.CSQC_Init = PRVM_ED_FindFunctionOffset("CSQC_Init");
1513 prog->funcoffsets.CSQC_InputEvent = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1514 prog->funcoffsets.CSQC_Parse_CenterPrint = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1515 prog->funcoffsets.CSQC_Parse_Print = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1516 prog->funcoffsets.CSQC_Parse_StuffCmd = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1517 prog->funcoffsets.CSQC_Parse_TempEntity = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1518 prog->funcoffsets.CSQC_Shutdown = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1519 prog->funcoffsets.CSQC_UpdateView = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1520 prog->funcoffsets.Gecko_Query = PRVM_ED_FindFunctionOffset("Gecko_Query");
1521 prog->funcoffsets.EndFrame = PRVM_ED_FindFunctionOffset("EndFrame");
1522 prog->funcoffsets.RestoreGame = PRVM_ED_FindFunctionOffset("RestoreGame");
1523 prog->funcoffsets.SV_ChangeTeam = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1524 prog->funcoffsets.SV_ParseClientCommand = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1525 prog->funcoffsets.SV_PlayerPhysics = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1526 prog->funcoffsets.SV_OnEntityNoSpawnFunction = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
1527 prog->funcoffsets.SV_OnEntityPreSpawnFunction = PRVM_ED_FindFunctionOffset("SV_OnEntityPreSpawnFunction");
1528 prog->funcoffsets.SV_OnEntityPostSpawnFunction = PRVM_ED_FindFunctionOffset("SV_OnEntityPostSpawnFunction");
1529 prog->funcoffsets.GameCommand = PRVM_ED_FindFunctionOffset("GameCommand");
1530 prog->funcoffsets.SV_Shutdown = PRVM_ED_FindFunctionOffset("SV_Shutdown");
1531 prog->funcoffsets.URI_Get_Callback = PRVM_ED_FindFunctionOffset("URI_Get_Callback");
1532 prog->funcoffsets.SV_PausedTic = PRVM_ED_FindFunctionOffset("SV_PausedTic");
1533 prog->globaloffsets.SV_InitCmd = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1534 prog->globaloffsets.self = PRVM_ED_FindGlobalOffset("self");
1535 prog->globaloffsets.time = PRVM_ED_FindGlobalOffset("time");
1536 prog->globaloffsets.v_forward = PRVM_ED_FindGlobalOffset("v_forward");
1537 prog->globaloffsets.v_right = PRVM_ED_FindGlobalOffset("v_right");
1538 prog->globaloffsets.v_up = PRVM_ED_FindGlobalOffset("v_up");
1539 prog->globaloffsets.view_angles = PRVM_ED_FindGlobalOffset("view_angles");
1540 prog->globaloffsets.trace_allsolid = PRVM_ED_FindGlobalOffset("trace_allsolid");
1541 prog->globaloffsets.trace_startsolid = PRVM_ED_FindGlobalOffset("trace_startsolid");
1542 prog->globaloffsets.trace_fraction = PRVM_ED_FindGlobalOffset("trace_fraction");
1543 prog->globaloffsets.trace_inwater = PRVM_ED_FindGlobalOffset("trace_inwater");
1544 prog->globaloffsets.trace_inopen = PRVM_ED_FindGlobalOffset("trace_inopen");
1545 prog->globaloffsets.trace_endpos = PRVM_ED_FindGlobalOffset("trace_endpos");
1546 prog->globaloffsets.trace_plane_normal = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1547 prog->globaloffsets.trace_plane_dist = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1548 prog->globaloffsets.trace_ent = PRVM_ED_FindGlobalOffset("trace_ent");
1549 prog->globaloffsets.trace_networkentity = PRVM_ED_FindGlobalOffset("trace_networkentity");
1550 prog->globaloffsets.trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1551 prog->globaloffsets.trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1552 prog->globaloffsets.trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1553 prog->globaloffsets.trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1554 prog->globaloffsets.intermission = PRVM_ED_FindGlobalOffset("intermission");
1555 prog->globaloffsets.coop = PRVM_ED_FindGlobalOffset("coop");
1556 prog->globaloffsets.deathmatch = PRVM_ED_FindGlobalOffset("deathmatch");
1557 prog->globaloffsets.dmg_take = PRVM_ED_FindGlobalOffset("dmg_take");
1558 prog->globaloffsets.dmg_save = PRVM_ED_FindGlobalOffset("dmg_save");
1559 prog->globaloffsets.dmg_origin = PRVM_ED_FindGlobalOffset("dmg_origin");
1560 prog->globaloffsets.sb_showscores = PRVM_ED_FindGlobalOffset("sb_showscores");
1561 prog->globaloffsets.drawfont = PRVM_ED_FindGlobalOffset("drawfont");
1562 prog->globaloffsets.require_spawnfunc_prefix = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
1563 prog->globaloffsets.worldstatus = PRVM_ED_FindGlobalOffset("worldstatus");
1564 prog->globaloffsets.servertime = PRVM_ED_FindGlobalOffset("servertime");
1565 prog->globaloffsets.serverprevtime = PRVM_ED_FindGlobalOffset("serverprevtime");
1566 prog->globaloffsets.serverdeltatime = PRVM_ED_FindGlobalOffset("serverdeltatime");
1567 prog->globaloffsets.gettaginfo_name = PRVM_ED_FindGlobalOffset("gettaginfo_name");
1568 prog->globaloffsets.gettaginfo_parent = PRVM_ED_FindGlobalOffset("gettaginfo_parent");
1569 prog->globaloffsets.gettaginfo_offset = PRVM_ED_FindGlobalOffset("gettaginfo_offset");
1570 prog->globaloffsets.gettaginfo_forward = PRVM_ED_FindGlobalOffset("gettaginfo_forward");
1571 prog->globaloffsets.gettaginfo_right = PRVM_ED_FindGlobalOffset("gettaginfo_right");
1572 prog->globaloffsets.gettaginfo_up = PRVM_ED_FindGlobalOffset("gettaginfo_up");
1574 // menu qc only uses some functions, nothing else
1575 prog->funcoffsets.m_draw = PRVM_ED_FindFunctionOffset("m_draw");
1576 prog->funcoffsets.m_init = PRVM_ED_FindFunctionOffset("m_init");
1577 prog->funcoffsets.m_keydown = PRVM_ED_FindFunctionOffset("m_keydown");
1578 prog->funcoffsets.m_keyup = PRVM_ED_FindFunctionOffset("m_keyup");
1579 prog->funcoffsets.m_shutdown = PRVM_ED_FindFunctionOffset("m_shutdown");
1580 prog->funcoffsets.m_toggle = PRVM_ED_FindFunctionOffset("m_toggle");
1585 typedef struct dpfield_s
1592 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1594 dpfield_t dpfields[] =
1605 void PRVM_LeakTest();
1606 void PRVM_ResetProg()
1609 PRVM_GCALL(reset_cmd)();
1610 Mem_FreePool(&prog->progs_mempool);
1611 memset(prog,0,sizeof(prvm_prog_t));
1612 prog->starttime = Sys_DoubleTime();
1620 void PRVM_LoadLNO( const char *progname ) {
1621 fs_offset_t filesize;
1623 unsigned int *header;
1626 FS_StripExtension( progname, filename, sizeof( filename ) );
1627 strlcat( filename, ".lno", sizeof( filename ) );
1629 lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1635 <Spike> SafeWrite (h, &lnotype, sizeof(int));
1636 <Spike> SafeWrite (h, &version, sizeof(int));
1637 <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
1638 <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
1639 <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
1640 <Spike> SafeWrite (h, &numstatements, sizeof(int));
1641 <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1643 if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1648 header = (unsigned int *) lno;
1649 if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1650 LittleLong( header[ 1 ] ) == 1 &&
1651 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1652 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1653 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1654 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1656 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1657 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1667 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1671 ddef_t *infielddefs;
1672 dfunction_t *dfunctions;
1673 fs_offset_t filesize;
1675 if( prog->loaded ) {
1676 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1679 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1680 if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1681 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1683 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1685 prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1687 // byte swap the header
1688 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1689 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1691 if (prog->progs->version != PROG_VERSION)
1692 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1693 if (prog->progs->crc != prog->headercrc && prog->progs->crc != prog->headercrc2)
1694 PRVM_ERROR ("%s: %s system vars have been modified (CRC of progs.dat systemvars %i != engine %i), progdefs.h is out of date", PRVM_NAME, filename, prog->progs->crc, prog->headercrc);
1696 //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1697 dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1699 if (prog->progs->ofs_strings + prog->progs->numstrings >= (int)filesize)
1700 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1701 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1702 prog->stringssize = prog->progs->numstrings;
1704 prog->numknownstrings = 0;
1705 prog->maxknownstrings = 0;
1706 prog->knownstrings = NULL;
1707 prog->knownstrings_freeable = NULL;
1709 Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
1711 prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1713 // we need to expand the fielddefs list to include all the engine fields,
1714 // so allocate a new place for it
1715 infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1717 prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1719 prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1721 prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1723 // moved edict_size calculation down below field adding code
1725 //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1726 prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1728 // byte swap the lumps
1729 for (i=0 ; i<prog->progs->numstatements ; i++)
1731 prog->statements[i].op = LittleShort(prog->statements[i].op);
1732 prog->statements[i].a = LittleShort(prog->statements[i].a);
1733 prog->statements[i].b = LittleShort(prog->statements[i].b);
1734 prog->statements[i].c = LittleShort(prog->statements[i].c);
1737 prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1738 for (i = 0;i < prog->progs->numfunctions;i++)
1740 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1741 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1742 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1743 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1744 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1745 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1746 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1749 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1751 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1752 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1753 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1756 // copy the progs fields to the new fields list
1757 for (i = 0;i < prog->progs->numfielddefs;i++)
1759 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1760 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1761 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1762 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1763 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1766 // append the required fields
1767 for (i = 0;i < (int) numrequiredfields;i++)
1769 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1770 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1771 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1772 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1773 prog->progs->entityfields += 3;
1775 prog->progs->entityfields++;
1776 prog->progs->numfielddefs++;
1779 // check required functions
1780 for(i=0 ; i < numrequiredfunc ; i++)
1781 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1782 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1784 // check required globals
1785 for(i=0 ; i < numrequiredglobals ; i++)
1786 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1787 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1789 for (i=0 ; i<prog->progs->numglobals ; i++)
1790 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1792 // moved edict_size calculation down here, below field adding code
1793 // LordHavoc: this no longer includes the prvm_edict_t header
1794 prog->edict_size = prog->progs->entityfields * 4;
1795 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1797 // LordHavoc: bounds check anything static
1798 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1804 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1805 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1808 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1809 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1811 // global global global
1846 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1847 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1849 // global none global
1855 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1856 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1872 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1873 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1887 if ((unsigned short) st->a >= prog->progs->numglobals)
1888 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1891 Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1896 PRVM_LoadLNO(filename);
1900 prog->loaded = TRUE;
1902 // set flags & ddef_ts in prog
1908 PRVM_GCALL(init_cmd)();
1915 void PRVM_Fields_f (void)
1917 int i, j, ednum, used, usedamount;
1919 char tempstring[MAX_INPUTLINE], tempstring2[260];
1929 Con_Print("no progs loaded\n");
1936 Con_Print("prvm_fields <program name>\n");
1941 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1944 counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1945 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1947 ed = PRVM_EDICT_NUM(ednum);
1948 if (ed->priv.required->free)
1950 for (i = 1;i < prog->progs->numfielddefs;i++)
1952 d = &prog->fielddefs[i];
1953 name = PRVM_GetString(d->s_name);
1954 if (name[strlen(name)-2] == '_')
1955 continue; // skip _x, _y, _z vars
1956 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1957 // if the value is still all 0, skip the field
1958 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1971 for (i = 0;i < prog->progs->numfielddefs;i++)
1973 d = &prog->fielddefs[i];
1974 name = PRVM_GetString(d->s_name);
1975 if (name[strlen(name)-2] == '_')
1976 continue; // skip _x, _y, _z vars
1977 switch(d->type & ~DEF_SAVEGLOBAL)
1980 strlcat(tempstring, "string ", sizeof(tempstring));
1983 strlcat(tempstring, "entity ", sizeof(tempstring));
1986 strlcat(tempstring, "function ", sizeof(tempstring));
1989 strlcat(tempstring, "field ", sizeof(tempstring));
1992 strlcat(tempstring, "void ", sizeof(tempstring));
1995 strlcat(tempstring, "float ", sizeof(tempstring));
1998 strlcat(tempstring, "vector ", sizeof(tempstring));
2001 strlcat(tempstring, "pointer ", sizeof(tempstring));
2004 dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
2005 strlcat(tempstring, tempstring2, sizeof(tempstring));
2008 if (strlen(name) > sizeof(tempstring2)-4)
2010 memcpy (tempstring2, name, sizeof(tempstring2)-4);
2011 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
2012 tempstring2[sizeof(tempstring2)-1] = 0;
2015 strlcat(tempstring, name, sizeof(tempstring));
2016 for (j = (int)strlen(name);j < 25;j++)
2017 strlcat(tempstring, " ", sizeof(tempstring));
2018 dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]);
2019 strlcat(tempstring, tempstring2, sizeof(tempstring));
2020 strlcat(tempstring, "\n", sizeof(tempstring));
2021 if (strlen(tempstring) >= sizeof(tempstring)/2)
2023 Con_Print(tempstring);
2029 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
2033 Con_Printf("%s: %i entity fields (%i in use), totalling %i bytes per edict (%i in use), %i edicts allocated, %i bytes total spent on edict fields (%i needed)\n", PRVM_NAME, prog->progs->entityfields, used, prog->progs->entityfields * 4, usedamount * 4, prog->max_edicts, prog->progs->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts);
2038 void PRVM_Globals_f (void)
2041 const char *wildcard;
2047 Con_Print("no progs loaded\n");
2050 if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
2052 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
2057 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
2060 if( Cmd_Argc() == 3)
2061 wildcard = Cmd_Argv(2);
2065 Con_Printf("%s :", PRVM_NAME);
2067 for (i = 0;i < prog->progs->numglobaldefs;i++)
2070 if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
2075 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
2077 Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->progs->numglobals, numculled, prog->progs->numglobals * 4);
2087 void PRVM_Global_f(void)
2090 if( Cmd_Argc() != 3 ) {
2091 Con_Printf( "prvm_global <program name> <global name>\n" );
2096 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2099 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2101 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2103 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
2112 void PRVM_GlobalSet_f(void)
2115 if( Cmd_Argc() != 4 ) {
2116 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2121 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2124 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2126 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2128 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3), true );
2137 void PRVM_Init (void)
2139 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2140 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2141 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2142 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2143 Cmd_AddCommand ("prvm_callprofile", PRVM_CallProfile_f, "prints execution statistics about the most time consuming QuakeC calls from the engine in the selected VM (server, client, menu)");
2144 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)");
2145 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2146 Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2147 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2148 Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)");
2149 Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2150 Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2151 Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2152 Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2154 // COMMANDLINEOPTION: PRVM: -noboundscheck disables the bounds checks (security hole if CSQC is in use!)
2155 prvm_boundscheck = !COM_CheckParm("-noboundscheck");
2157 Cvar_RegisterVariable (&prvm_traceqc);
2158 Cvar_RegisterVariable (&prvm_statementprofiling);
2159 Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2160 Cvar_RegisterVariable (&prvm_leaktest);
2161 Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames);
2162 Cvar_RegisterVariable (&prvm_errordump);
2164 // COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!)
2165 prvm_runawaycheck = !COM_CheckParm("-norunaway");
2175 void PRVM_InitProg(int prognr)
2177 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
2178 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
2180 prog = &prog_list[prognr];
2185 memset(prog, 0, sizeof(prvm_prog_t));
2186 prog->starttime = Sys_DoubleTime();
2188 prog->error_cmd = Host_Error;
2189 prog->leaktest_active = prvm_leaktest.integer;
2192 int PRVM_GetProgNr()
2194 return prog - prog_list;
2197 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
2199 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
2202 void _PRVM_Free(void *buffer, const char *filename, int fileline)
2204 _Mem_Free(buffer, filename, fileline);
2207 void _PRVM_FreeAll(const char *filename, int fileline)
2210 prog->fielddefs = NULL;
2211 prog->functions = NULL;
2212 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
2215 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2216 unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, char *filename, int fileline)
2218 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
2223 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
2225 PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
2229 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
2232 n = e - prog->edicts;
2233 if ((unsigned int)n >= prog->limit_edicts)
2234 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
2238 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
2240 // return e - prog->edicts;
2243 //#define PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
2244 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
2245 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
2248 n = e - prog->edicts;
2249 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2250 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2251 return n;// EXPERIMENTAL
2252 //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2254 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2256 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2257 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2258 return prog->edicts + n; // EXPERIMENTAL
2259 //return prog->edicts + ((n) / (progs->entityfields * 4));
2264 sizebuf_t vm_tempstringsbuf;
2266 const char *PRVM_GetString(int num)
2270 if (num < prog->stringssize)
2271 return prog->strings + num;
2274 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2276 num -= prog->stringssize;
2277 if (num < vm_tempstringsbuf.cursize)
2278 return (char *)vm_tempstringsbuf.data + num;
2281 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2288 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
2298 // special range reserved for tempstrings
2300 if (num < vm_tempstringsbuf.cursize)
2301 return (char *)vm_tempstringsbuf.data + num;
2304 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2310 if (num < prog->numknownstrings)
2312 if (!prog->knownstrings[num])
2313 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
2314 return prog->knownstrings[num];
2318 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
2324 int PRVM_SetEngineString(const char *s)
2329 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2330 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2331 // if it's in the tempstrings area, use a reserved range
2332 // (otherwise we'd get millions of useless string offsets cluttering the database)
2333 if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2335 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2337 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2339 // see if it's a known string address
2340 for (i = 0;i < prog->numknownstrings;i++)
2341 if (prog->knownstrings[i] == s)
2343 // new unknown engine string
2344 if (developer.integer >= 200)
2345 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2346 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2347 if (!prog->knownstrings[i])
2349 if (i >= prog->numknownstrings)
2351 if (i >= prog->maxknownstrings)
2353 const char **oldstrings = prog->knownstrings;
2354 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2355 const char **oldstrings_origin = prog->knownstrings_origin;
2356 prog->maxknownstrings += 128;
2357 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2358 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2359 if(prog->leaktest_active)
2360 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2361 if (prog->numknownstrings)
2363 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2364 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2365 if(prog->leaktest_active)
2366 memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
2369 prog->numknownstrings++;
2371 prog->firstfreeknownstring = i + 1;
2372 prog->knownstrings[i] = s;
2373 prog->knownstrings_freeable[i] = false;
2374 if(prog->leaktest_active)
2375 prog->knownstrings_origin[i] = NULL;
2379 // temp string handling
2381 // all tempstrings go into this buffer consecutively, and it is reset
2382 // whenever PRVM_ExecuteProgram returns to the engine
2383 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2384 // restores it on return, so multiple recursive calls can share the same
2386 // the buffer size is automatically grown as needed
2388 int PRVM_SetTempString(const char *s)
2394 size = (int)strlen(s) + 1;
2395 if (developer.integer >= 300)
2396 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2397 if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2399 sizebuf_t old = vm_tempstringsbuf;
2400 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2401 PRVM_ERROR("PRVM_SetTempString: ran out of tempstring memory! (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", vm_tempstringsbuf.cursize, size);
2402 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2403 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2404 vm_tempstringsbuf.maxsize *= 2;
2405 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2407 if (developer.integer >= 100)
2408 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2409 vm_tempstringsbuf.data = (unsigned char *) Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2411 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2416 t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2418 vm_tempstringsbuf.cursize += size;
2419 return PRVM_SetEngineString(t);
2422 int PRVM_AllocString(size_t bufferlength, char **pointer)
2427 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2428 if (!prog->knownstrings[i])
2430 if (i >= prog->numknownstrings)
2432 if (i >= prog->maxknownstrings)
2434 const char **oldstrings = prog->knownstrings;
2435 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2436 const char **oldstrings_origin = prog->knownstrings_origin;
2437 prog->maxknownstrings += 128;
2438 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2439 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2440 if(prog->leaktest_active)
2441 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2442 if (prog->numknownstrings)
2444 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2445 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2446 if(prog->leaktest_active)
2447 memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
2449 // TODO why not Mem_Free the old ones?
2451 prog->numknownstrings++;
2453 prog->firstfreeknownstring = i + 1;
2454 prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2455 prog->knownstrings_freeable[i] = true;
2456 if(prog->leaktest_active)
2457 prog->knownstrings_origin[i] = PRVM_AllocationOrigin();
2459 *pointer = (char *)(prog->knownstrings[i]);
2463 void PRVM_FreeString(int num)
2466 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2467 else if (num >= 0 && num < prog->stringssize)
2468 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2469 else if (num < 0 && num >= -prog->numknownstrings)
2472 if (!prog->knownstrings[num])
2473 PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2474 if (!prog->knownstrings_freeable[num])
2475 PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2476 PRVM_Free((char *)prog->knownstrings[num]);
2477 if(prog->leaktest_active)
2478 if(prog->knownstrings_origin[num])
2479 PRVM_Free((char *)prog->knownstrings_origin[num]);
2480 prog->knownstrings[num] = NULL;
2481 prog->knownstrings_freeable[num] = false;
2482 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2485 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);
2488 static qboolean PRVM_IsStringReferenced(string_t string)
2492 for (i = 0;i < prog->progs->numglobaldefs;i++)
2494 ddef_t *d = &prog->globaldefs[i];
2495 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
2497 if(string == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->string)
2501 for(j = 0; j < prog->num_edicts; ++j)
2503 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2504 if (ed->priv.required->free)
2506 for (i=0; i<prog->progs->numfielddefs; ++i)
2508 ddef_t *d = &prog->fielddefs[i];
2509 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
2511 if(string == ((prvm_eval_t *) &((float*)ed->fields.vp)[d->ofs])->string)
2519 static qboolean PRVM_IsEdictRelevant(prvm_edict_t *edict)
2521 if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts)
2522 return true; // world or clients
2523 switch(prog - prog_list)
2525 case PRVM_SERVERPROG:
2527 entvars_t *ev = edict->fields.server;
2528 if(ev->solid) // can block other stuff, or is a trigger?
2530 if(ev->modelindex) // visible ent?
2532 if(ev->effects) // particle effect?
2534 if(ev->think) // has a think function?
2535 if(ev->nextthink > 0) // that actually will eventually run?
2539 if(*prvm_leaktest_ignore_classnames.string)
2541 if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(ev->classname))))
2546 case PRVM_CLIENTPROG:
2548 // TODO someone add more stuff here
2549 cl_entvars_t *ev = edict->fields.client;
2550 if(ev->entnum) // csqc networked
2552 if(ev->modelindex) // visible ent?
2554 if(ev->effects) // particle effect?
2556 if(ev->think) // has a think function?
2557 if(ev->nextthink > 0) // that actually will eventually run?
2559 if(*prvm_leaktest_ignore_classnames.string)
2561 if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(ev->classname))))
2567 // menu prog does not have classnames
2573 static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
2576 int edictnum = PRVM_NUM_FOR_EDICT(edict);
2577 const char *targetname = NULL;
2579 switch(prog - prog_list)
2581 case PRVM_SERVERPROG:
2582 targetname = PRVM_GetString(edict->fields.server->targetname);
2587 if(!*targetname) // ""
2590 for (i = 0;i < prog->progs->numglobaldefs;i++)
2592 ddef_t *d = &prog->globaldefs[i];
2593 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
2595 if(edictnum == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->edict)
2599 for(j = 0; j < prog->num_edicts; ++j)
2601 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2602 if (ed->priv.required->mark < mark)
2608 const char *target = PRVM_GetString(ed->fields.server->target);
2610 if(!strcmp(target, targetname))
2613 for (i=0; i<prog->progs->numfielddefs; ++i)
2615 ddef_t *d = &prog->fielddefs[i];
2616 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
2618 if(edictnum == ((prvm_eval_t *) &((float*)ed->fields.vp)[d->ofs])->edict)
2626 static void PRVM_MarkReferencedEdicts()
2632 for(j = 0; j < prog->num_edicts; ++j)
2634 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2635 if(ed->priv.required->free)
2637 ed->priv.required->mark = PRVM_IsEdictRelevant(ed) ? 1 : 0;
2644 for(j = 0; j < prog->num_edicts; ++j)
2646 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2647 if(ed->priv.required->free)
2649 if(ed->priv.required->mark)
2651 if(PRVM_IsEdictReferenced(ed, stage))
2653 ed->priv.required->mark = stage + 1;
2660 Con_DPrintf("leak check used %d stages to find all references\n", stage);
2663 void PRVM_LeakTest()
2666 qboolean leaked = false;
2668 if(!prog->leaktest_active)
2672 for (i = 0; i < prog->numknownstrings; ++i)
2674 if(prog->knownstrings[i])
2675 if(prog->knownstrings_freeable[i])
2676 if(prog->knownstrings_origin[i])
2677 if(!PRVM_IsStringReferenced(-1 - i))
2679 Con_Printf("Unreferenced string found!\n Value: %s\n Origin: %s\n", prog->knownstrings[i], prog->knownstrings_origin[i]);
2685 PRVM_MarkReferencedEdicts();
2686 for(j = 0; j < prog->num_edicts; ++j)
2688 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2689 if(ed->priv.required->free)
2691 if(!ed->priv.required->mark)
2692 if(ed->priv.required->allocation_origin)
2694 Con_Printf("Unreferenced edict found!\n Allocated at: %s\n", ed->priv.required->allocation_origin);
2695 PRVM_ED_Print(ed, NULL);
2701 for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i)
2703 prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
2705 if(stringbuffer->origin)
2707 Con_Printf("Open string buffer handle found!\n Allocated at: %s\n", stringbuffer->origin);
2712 for(i = 0; i < PRVM_MAX_OPENFILES; ++i)
2714 if(prog->openfiles[i])
2715 if(prog->openfiles_origin[i])
2717 Con_Printf("Open file handle found!\n Allocated at: %s\n", prog->openfiles_origin[i]);
2722 for(i = 0; i < PRVM_MAX_OPENSEARCHES; ++i)
2724 if(prog->opensearches[i])
2725 if(prog->opensearches_origin[i])
2727 Con_Printf("Open search handle found!\n Allocated at: %s\n", prog->opensearches_origin[i]);
2733 Con_Printf("Congratulations. No leaks found.\n");