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);
34 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
35 cvar_t prvm_boundscheck = {0, "prvm_boundscheck", "1", "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)"};
36 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
37 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
38 // LordHavoc: counts usage of each QuakeC statement
39 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)"};
41 //============================================================================
49 void PRVM_MEM_Alloc(void)
53 // reserve space for the null entity aka world
54 // check bound of max_edicts
55 prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
56 prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
58 // edictprivate_size has to be min as big prvm_edict_private_t
59 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
62 prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
64 // alloc edict private space
65 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
68 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
71 for(i = 0; i < prog->max_edicts; i++)
73 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
74 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
80 PRVM_MEM_IncreaseEdicts
83 void PRVM_MEM_IncreaseEdicts(void)
86 int oldmaxedicts = prog->max_edicts;
87 void *oldedictsfields = prog->edictsfields;
88 void *oldedictprivate = prog->edictprivate;
90 if(prog->max_edicts >= prog->limit_edicts)
93 PRVM_GCALL(begin_increase_edicts)();
96 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
98 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
99 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
101 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
102 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
104 //set e and v pointers
105 for(i = 0; i < prog->max_edicts; i++)
107 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
108 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
111 PRVM_GCALL(end_increase_edicts)();
113 Mem_Free(oldedictsfields);
114 Mem_Free(oldedictprivate);
117 //============================================================================
120 int PRVM_ED_FindFieldOffset(const char *field)
123 d = PRVM_ED_FindField(field);
129 int PRVM_ED_FindGlobalOffset(const char *global)
132 d = PRVM_ED_FindGlobal(global);
138 func_t PRVM_ED_FindFunctionOffset(const char *function)
141 f = PRVM_ED_FindFunction(function);
144 return (func_t)(f - prog->functions);
147 qboolean PRVM_ProgLoaded(int prognr)
149 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
152 return (prog_list[prognr].loaded ? TRUE : FALSE);
157 PRVM_SetProgFromString
160 // perhaps add a return value when the str doesnt exist
161 qboolean PRVM_SetProgFromString(const char *str)
164 for(; i < PRVM_MAXPROGS ; i++)
165 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
167 if(prog_list[i].loaded)
169 prog = &prog_list[i];
174 Con_Printf("%s not loaded !\n",PRVM_NAME);
179 Con_Printf("Invalid program name %s !\n", str);
188 void PRVM_SetProg(int prognr)
190 if(0 <= prognr && prognr < PRVM_MAXPROGS)
192 if(prog_list[prognr].loaded)
193 prog = &prog_list[prognr];
195 PRVM_ERROR("%i not loaded !", prognr);
198 PRVM_ERROR("Invalid program number %i", prognr);
205 Sets everything to NULL
208 void PRVM_ED_ClearEdict (prvm_edict_t *e)
210 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
211 e->priv.required->free = false;
213 // AK: Let the init_edict function determine if something needs to be initialized
214 PRVM_GCALL(init_edict)(e);
221 Either finds a free edict, or allocates a new one.
222 Try to avoid reusing an entity that was recently freed, because it
223 can cause the client to think the entity morphed into something else
224 instead of being removed and recreated, which can cause interpolated
225 angles and bad trails.
228 prvm_edict_t *PRVM_ED_Alloc (void)
233 // the client qc dont need maxclients
234 // thus it doesnt need to use svs.maxclients
235 // AK: changed i=svs.maxclients+1
236 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
237 // although the menu/client has no world
238 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
240 e = PRVM_EDICT_NUM(i);
241 // the first couple seconds of server time can involve a lot of
242 // freeing and allocating, so relax the replacement policy
243 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 ) )
245 PRVM_ED_ClearEdict (e);
250 if (i == prog->limit_edicts)
251 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
254 if (prog->num_edicts >= prog->max_edicts)
255 PRVM_MEM_IncreaseEdicts();
257 e = PRVM_EDICT_NUM(i);
258 PRVM_ED_ClearEdict (e);
267 Marks the edict as free
268 FIXME: walk all entities and NULL out references to this entity
271 void PRVM_ED_Free (prvm_edict_t *ed)
273 // dont delete the null entity (world) or reserved edicts
274 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
277 PRVM_GCALL(free_edict)(ed);
279 ed->priv.required->free = true;
280 ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0;
283 //===========================================================================
290 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
295 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
297 def = &prog->globaldefs[i];
309 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
314 for (i=0 ; i<prog->progs->numfielddefs ; i++)
316 def = &prog->fielddefs[i];
328 ddef_t *PRVM_ED_FindField (const char *name)
333 for (i=0 ; i<prog->progs->numfielddefs ; i++)
335 def = &prog->fielddefs[i];
336 if (!strcmp(PRVM_GetString(def->s_name), name))
347 ddef_t *PRVM_ED_FindGlobal (const char *name)
352 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
354 def = &prog->globaldefs[i];
355 if (!strcmp(PRVM_GetString(def->s_name), name))
367 mfunction_t *PRVM_ED_FindFunction (const char *name)
372 for (i=0 ; i<prog->progs->numfunctions ; i++)
374 func = &prog->functions[i];
375 if (!strcmp(PRVM_GetString(func->s_name), name))
386 Returns a string describing *data in a type specific manner
389 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
391 static char line[MAX_INPUTLINE];
396 type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
401 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
405 if (n < 0 || n >= prog->limit_edicts)
406 sprintf (line, "entity %i (invalid!)", n);
408 sprintf (line, "entity %i", n);
411 f = prog->functions + val->function;
412 sprintf (line, "%s()", PRVM_GetString(f->s_name));
415 def = PRVM_ED_FieldAtOfs ( val->_int );
416 sprintf (line, ".%s", PRVM_GetString(def->s_name));
419 sprintf (line, "void");
422 // LordHavoc: changed from %5.1f to %10.4f
423 sprintf (line, "%10.4f", val->_float);
426 // LordHavoc: changed from %5.1f to %10.4f
427 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
430 sprintf (line, "pointer");
433 sprintf (line, "bad type %i", (int) type);
444 Returns a string describing *data in a type specific manner
445 Easier to parse than PR_ValueString
448 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
450 static char line[MAX_INPUTLINE];
456 type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
461 // Parse the string a bit to turn special characters
462 // (like newline, specifically) into escape codes,
463 // this fixes saving games from various mods
464 s = PRVM_GetString (val->string);
465 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
484 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
487 f = prog->functions + val->function;
488 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
491 def = PRVM_ED_FieldAtOfs ( val->_int );
492 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
495 dpsnprintf (line, sizeof (line), "void");
498 dpsnprintf (line, sizeof (line), "%f", val->_float);
501 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
504 dpsnprintf (line, sizeof (line), "bad type %i", type);
515 Returns a string with a description and the contents of a global,
516 padded to 20 field width
519 char *PRVM_GlobalString (int ofs)
525 static char line[128];
527 val = (void *)&prog->globals.generic[ofs];
528 def = PRVM_ED_GlobalAtOfs(ofs);
530 sprintf (line,"GLOBAL%i", ofs);
533 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
534 sprintf (line,"%s (=%s)", PRVM_GetString(def->s_name), s);
538 //for ( ; i<20 ; i++)
539 // strcat (line," ");
545 char *PRVM_GlobalStringNoContents (int ofs)
549 static char line[128];
551 def = PRVM_ED_GlobalAtOfs(ofs);
553 sprintf (line,"GLOBAL%i", ofs);
555 sprintf (line,"%s", PRVM_GetString(def->s_name));
558 //for ( ; i<20 ; i++)
559 // strcat (line," ");
573 // LordHavoc: optimized this to print out much more quickly (tempstring)
574 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
575 void PRVM_ED_Print(prvm_edict_t *ed)
583 char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
585 if (ed->priv.required->free)
587 Con_Printf("%s: FREE\n",PRVM_NAME);
592 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
593 for (i=1 ; i<prog->progs->numfielddefs ; i++)
595 d = &prog->fielddefs[i];
596 name = PRVM_GetString(d->s_name);
597 if (name[strlen(name)-2] == '_')
598 continue; // skip _x, _y, _z vars
600 v = (int *)((char *)ed->fields.vp + d->ofs*4);
602 // if the value is still all 0, skip the field
603 type = d->type & ~DEF_SAVEGLOBAL;
605 for (j=0 ; j<prvm_type_size[type] ; j++)
608 if (j == prvm_type_size[type])
611 if (strlen(name) > sizeof(tempstring2)-4)
613 memcpy (tempstring2, name, sizeof(tempstring2)-4);
614 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
615 tempstring2[sizeof(tempstring2)-1] = 0;
618 strlcat(tempstring, name, sizeof(tempstring));
619 for (l = strlen(name);l < 14;l++)
620 strlcat(tempstring, " ", sizeof(tempstring));
621 strlcat(tempstring, " ", sizeof(tempstring));
623 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
624 if (strlen(name) > sizeof(tempstring2)-4)
626 memcpy (tempstring2, name, sizeof(tempstring2)-4);
627 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
628 tempstring2[sizeof(tempstring2)-1] = 0;
631 strlcat(tempstring, name, sizeof(tempstring));
632 strlcat(tempstring, "\n", sizeof(tempstring));
633 if (strlen(tempstring) >= sizeof(tempstring)/2)
635 Con_Print(tempstring);
640 Con_Print(tempstring);
650 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
660 if (ed->priv.required->free)
666 for (i=1 ; i<prog->progs->numfielddefs ; i++)
668 d = &prog->fielddefs[i];
669 name = PRVM_GetString(d->s_name);
670 if (name[strlen(name)-2] == '_')
671 continue; // skip _x, _y, _z vars
673 v = (int *)((char *)ed->fields.vp + d->ofs*4);
675 // if the value is still all 0, skip the field
676 type = d->type & ~DEF_SAVEGLOBAL;
677 for (j=0 ; j<prvm_type_size[type] ; j++)
680 if (j == prvm_type_size[type])
683 FS_Printf(f,"\"%s\" ",name);
684 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
690 void PRVM_ED_PrintNum (int ent)
692 PRVM_ED_Print(PRVM_EDICT_NUM(ent));
697 PRVM_ED_PrintEdicts_f
699 For debugging, prints all the entities in the current server
702 void PRVM_ED_PrintEdicts_f (void)
708 Con_Print("prvm_edicts <program name>\n");
713 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
716 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
717 for (i=0 ; i<prog->num_edicts ; i++)
718 PRVM_ED_PrintNum (i);
727 For debugging, prints a single edict
730 void PRVM_ED_PrintEdict_f (void)
736 Con_Print("prvm_edict <program name> <edict number>\n");
741 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
744 i = atoi (Cmd_Argv(2));
745 if (i >= prog->num_edicts)
747 Con_Print("Bad edict number\n");
751 PRVM_ED_PrintNum (i);
763 // 2 possibilities : 1. just displaying the active edict count
764 // 2. making a function pointer [x]
765 void PRVM_ED_Count_f (void)
773 Con_Print("prvm_count <program name>\n");
778 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
781 if(prog->count_edicts)
782 prog->count_edicts();
786 for (i=0 ; i<prog->num_edicts ; i++)
788 ent = PRVM_EDICT_NUM(i);
789 if (ent->priv.required->free)
794 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
795 Con_Printf("active :%3i\n", active);
802 ==============================================================================
806 FIXME: need to tag constants, doesn't really work
807 ==============================================================================
815 void PRVM_ED_WriteGlobals (qfile_t *f)
823 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
825 def = &prog->globaldefs[i];
827 if ( !(def->type & DEF_SAVEGLOBAL) )
829 type &= ~DEF_SAVEGLOBAL;
831 if (type != ev_string && type != ev_float && type != ev_entity)
834 name = PRVM_GetString(def->s_name);
835 FS_Printf(f,"\"%s\" ", name);
836 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
846 void PRVM_ED_ParseGlobals (const char *data)
848 char keyname[MAX_INPUTLINE];
854 if (!COM_ParseTokenConsole(&data))
855 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
856 if (com_token[0] == '}')
859 strlcpy (keyname, com_token, sizeof(keyname));
862 if (!COM_ParseTokenConsole(&data))
863 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
865 if (com_token[0] == '}')
866 PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
868 key = PRVM_ED_FindGlobal (keyname);
871 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
875 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
876 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
880 //============================================================================
887 Can parse either fields or globals
888 returns false if error
891 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
900 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
902 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
903 switch (key->type & ~DEF_SAVEGLOBAL)
906 l = (int)strlen(s) + 1;
907 val->string = PRVM_AllocString(l, &new_p);
908 for (i = 0;i < l;i++)
910 if (s[i] == '\\' && i < l-1)
915 else if (s[i] == 'r')
926 while (*s && *s <= ' ')
928 val->_float = atof(s);
932 for (i = 0;i < 3;i++)
934 while (*s && *s <= ' ')
938 val->vector[i] = atof(s);
947 while (*s && *s <= ' ')
950 if (i >= prog->limit_edicts)
951 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);
952 while (i >= prog->max_edicts)
953 PRVM_MEM_IncreaseEdicts();
954 //SV_IncreaseEdicts();
955 // if SV_IncreaseEdicts was called the base pointer needs to be updated
957 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
958 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
962 def = PRVM_ED_FindField(s);
965 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
968 val->_int = def->ofs;
972 func = PRVM_ED_FindFunction(s);
975 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
978 val->function = func - prog->functions;
982 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
992 Console command to set a field of a specified edict
995 void PRVM_ED_EdictSet_f(void)
1002 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1007 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1009 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1013 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1015 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1016 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1018 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1024 ====================
1027 Parses an edict out of the given string, returning the new position
1028 ed should be a properly initialized empty edict.
1029 Used for initial level load and for savegames.
1030 ====================
1032 extern cvar_t developer_entityparsing;
1033 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1043 // go through all the dictionary pairs
1047 if (!COM_ParseTokenConsole(&data))
1048 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1049 if (developer_entityparsing.integer)
1050 Con_Printf("Key: \"%s\"", com_token);
1051 if (com_token[0] == '}')
1054 // anglehack is to allow QuakeEd to write single scalar angles
1055 // and allow them to be turned into vectors. (FIXME...)
1056 if (!strcmp(com_token, "angle"))
1058 strlcpy (com_token, "angles", sizeof(com_token));
1064 // FIXME: change light to _light to get rid of this hack
1065 if (!strcmp(com_token, "light"))
1066 strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def
1068 strlcpy (keyname, com_token, sizeof(keyname));
1070 // another hack to fix keynames with trailing spaces
1071 n = strlen(keyname);
1072 while (n && keyname[n-1] == ' ')
1079 if (!COM_ParseTokenConsole(&data))
1080 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1081 if (developer_entityparsing.integer)
1082 Con_Printf(" \"%s\"\n", com_token);
1084 if (com_token[0] == '}')
1085 PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1089 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1093 // keynames with a leading underscore are used for utility comments,
1094 // and are immediately discarded by quake
1095 if (keyname[0] == '_')
1098 key = PRVM_ED_FindField (keyname);
1101 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1108 strlcpy (temp, com_token, sizeof(temp));
1109 sprintf (com_token, "0 %s 0", temp);
1112 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1113 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1117 ent->priv.required->free = true;
1125 PRVM_ED_LoadFromFile
1127 The entities are directly placed in the array, rather than allocated with
1128 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1129 number references out of order.
1131 Creates a server's entity / program execution context by
1132 parsing textual entity definitions out of an ent file.
1134 Used for both fresh maps and savegame loads. A fresh map would also need
1135 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1138 void PRVM_ED_LoadFromFile (const char *data)
1141 int parsed, inhibited, spawned, died;
1153 // parse the opening brace
1154 if (!COM_ParseTokenConsole(&data))
1156 if (com_token[0] != '{')
1157 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1159 // CHANGED: this is not conform to PR_LoadFromFile
1160 if(prog->loadintoworld)
1162 prog->loadintoworld = false;
1163 ent = PRVM_EDICT_NUM(0);
1166 ent = PRVM_ED_Alloc();
1169 if (ent != prog->edicts) // hack
1170 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1172 data = PRVM_ED_ParseEdict (data, ent);
1175 // remove the entity ?
1176 if(prog->load_edict && !prog->load_edict(ent))
1184 // immediately call spawn function, but only if there is a self global and a classname
1186 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1188 string_t handle = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1191 Con_Print("No classname for:\n");
1197 // look for the spawn function
1198 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1202 if (developer.integer) // don't confuse non-developers with errors
1204 Con_Print("No spawn function for:\n");
1212 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1213 PRVM_ExecuteProgram (func - prog->functions, "");
1217 if (ent->priv.required->free)
1221 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);
1224 void PRVM_FindOffsets(void)
1226 // field and global searches use -1 for NULL
1227 memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1228 memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1229 // functions use 0 for NULL
1230 memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1232 // server and client qc use a lot of similar fields, so this is combined
1233 prog->fieldoffsets.SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
1234 prog->fieldoffsets.Version = PRVM_ED_FindFieldOffset("Version");
1235 prog->fieldoffsets.alpha = PRVM_ED_FindFieldOffset("alpha");
1236 prog->fieldoffsets.ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
1237 prog->fieldoffsets.ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1238 prog->fieldoffsets.ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1239 prog->fieldoffsets.ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
1240 prog->fieldoffsets.ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
1241 prog->fieldoffsets.ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
1242 prog->fieldoffsets.ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
1243 prog->fieldoffsets.angles = PRVM_ED_FindFieldOffset("angles");
1244 prog->fieldoffsets.button3 = PRVM_ED_FindFieldOffset("button3");
1245 prog->fieldoffsets.button4 = PRVM_ED_FindFieldOffset("button4");
1246 prog->fieldoffsets.button5 = PRVM_ED_FindFieldOffset("button5");
1247 prog->fieldoffsets.button6 = PRVM_ED_FindFieldOffset("button6");
1248 prog->fieldoffsets.button7 = PRVM_ED_FindFieldOffset("button7");
1249 prog->fieldoffsets.button8 = PRVM_ED_FindFieldOffset("button8");
1250 prog->fieldoffsets.button9 = PRVM_ED_FindFieldOffset("button9");
1251 prog->fieldoffsets.button10 = PRVM_ED_FindFieldOffset("button10");
1252 prog->fieldoffsets.button11 = PRVM_ED_FindFieldOffset("button11");
1253 prog->fieldoffsets.button12 = PRVM_ED_FindFieldOffset("button12");
1254 prog->fieldoffsets.button13 = PRVM_ED_FindFieldOffset("button13");
1255 prog->fieldoffsets.button14 = PRVM_ED_FindFieldOffset("button14");
1256 prog->fieldoffsets.button15 = PRVM_ED_FindFieldOffset("button15");
1257 prog->fieldoffsets.button16 = PRVM_ED_FindFieldOffset("button16");
1258 prog->fieldoffsets.buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
1259 prog->fieldoffsets.buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
1260 prog->fieldoffsets.chain = PRVM_ED_FindFieldOffset("chain");
1261 prog->fieldoffsets.classname = PRVM_ED_FindFieldOffset("classname");
1262 prog->fieldoffsets.clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
1263 prog->fieldoffsets.color = PRVM_ED_FindFieldOffset("color");
1264 prog->fieldoffsets.colormod = PRVM_ED_FindFieldOffset("colormod");
1265 prog->fieldoffsets.contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
1266 prog->fieldoffsets.cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
1267 prog->fieldoffsets.cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
1268 prog->fieldoffsets.cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1269 prog->fieldoffsets.cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1270 prog->fieldoffsets.cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
1271 prog->fieldoffsets.customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
1272 prog->fieldoffsets.dimension_hit = PRVM_ED_FindFieldOffset("dimension_hit");
1273 prog->fieldoffsets.dimension_solid = PRVM_ED_FindFieldOffset("dimension_solid");
1274 prog->fieldoffsets.dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1275 prog->fieldoffsets.drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
1276 prog->fieldoffsets.exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1277 prog->fieldoffsets.fatness = PRVM_ED_FindFieldOffset("fatness");
1278 prog->fieldoffsets.forceshader = PRVM_ED_FindFieldOffset("forceshader");
1279 prog->fieldoffsets.frame = PRVM_ED_FindFieldOffset("frame");
1280 prog->fieldoffsets.frame1time = PRVM_ED_FindFieldOffset("frame1time");
1281 prog->fieldoffsets.frame2 = PRVM_ED_FindFieldOffset("frame2");
1282 prog->fieldoffsets.frame2time = PRVM_ED_FindFieldOffset("frame2time");
1283 prog->fieldoffsets.fullbright = PRVM_ED_FindFieldOffset("fullbright");
1284 prog->fieldoffsets.glow_color = PRVM_ED_FindFieldOffset("glow_color");
1285 prog->fieldoffsets.glow_size = PRVM_ED_FindFieldOffset("glow_size");
1286 prog->fieldoffsets.glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
1287 prog->fieldoffsets.gravity = PRVM_ED_FindFieldOffset("gravity");
1288 prog->fieldoffsets.groundentity = PRVM_ED_FindFieldOffset("groundentity");
1289 prog->fieldoffsets.hull = PRVM_ED_FindFieldOffset("hull");
1290 prog->fieldoffsets.ideal_yaw = PRVM_ED_FindFieldOffset("ideal_yaw");
1291 prog->fieldoffsets.idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
1292 prog->fieldoffsets.items2 = PRVM_ED_FindFieldOffset("items2");
1293 prog->fieldoffsets.lerpfrac = PRVM_ED_FindFieldOffset("lerpfrac");
1294 prog->fieldoffsets.light_lev = PRVM_ED_FindFieldOffset("light_lev");
1295 prog->fieldoffsets.movement = PRVM_ED_FindFieldOffset("movement");
1296 prog->fieldoffsets.nextthink = PRVM_ED_FindFieldOffset("nextthink");
1297 prog->fieldoffsets.nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
1298 prog->fieldoffsets.pflags = PRVM_ED_FindFieldOffset("pflags");
1299 prog->fieldoffsets.ping = PRVM_ED_FindFieldOffset("ping");
1300 prog->fieldoffsets.pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
1301 prog->fieldoffsets.playermodel = PRVM_ED_FindFieldOffset("playermodel");
1302 prog->fieldoffsets.playerskin = PRVM_ED_FindFieldOffset("playerskin");
1303 prog->fieldoffsets.pmodel = PRVM_ED_FindFieldOffset("pmodel");
1304 prog->fieldoffsets.punchvector = PRVM_ED_FindFieldOffset("punchvector");
1305 prog->fieldoffsets.renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1306 prog->fieldoffsets.renderflags = PRVM_ED_FindFieldOffset("renderflags");
1307 prog->fieldoffsets.rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1308 prog->fieldoffsets.scale = PRVM_ED_FindFieldOffset("scale");
1309 prog->fieldoffsets.style = PRVM_ED_FindFieldOffset("style");
1310 prog->fieldoffsets.tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
1311 prog->fieldoffsets.tag_index = PRVM_ED_FindFieldOffset("tag_index");
1312 prog->fieldoffsets.think = PRVM_ED_FindFieldOffset("think");
1313 prog->fieldoffsets.viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
1314 prog->fieldoffsets.viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
1315 prog->fieldoffsets.yaw_speed = PRVM_ED_FindFieldOffset("yaw_speed");
1316 prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1317 prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1318 prog->funcoffsets.CSQC_Ent_Update = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1319 prog->funcoffsets.CSQC_Event = PRVM_ED_FindFunctionOffset("CSQC_Event");
1320 prog->funcoffsets.CSQC_Init = PRVM_ED_FindFunctionOffset("CSQC_Init");
1321 prog->funcoffsets.CSQC_InputEvent = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1322 prog->funcoffsets.CSQC_Parse_CenterPrint = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1323 prog->funcoffsets.CSQC_Parse_Print = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1324 prog->funcoffsets.CSQC_Parse_StuffCmd = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1325 prog->funcoffsets.CSQC_Parse_TempEntity = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1326 prog->funcoffsets.CSQC_Shutdown = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1327 prog->funcoffsets.CSQC_UpdateView = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1328 prog->funcoffsets.EndFrame = PRVM_ED_FindFunctionOffset("EndFrame");
1329 prog->funcoffsets.RestoreGame = PRVM_ED_FindFunctionOffset("RestoreGame");
1330 prog->funcoffsets.SV_ChangeTeam = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1331 prog->funcoffsets.SV_ParseClientCommand = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1332 prog->funcoffsets.SV_PlayerPhysics = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1333 prog->globaloffsets.SV_InitCmd = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1334 prog->globaloffsets.self = PRVM_ED_FindGlobalOffset("self");
1335 prog->globaloffsets.time = PRVM_ED_FindGlobalOffset("time");
1336 prog->globaloffsets.v_forward = PRVM_ED_FindGlobalOffset("v_forward");
1337 prog->globaloffsets.v_right = PRVM_ED_FindGlobalOffset("v_right");
1338 prog->globaloffsets.v_up = PRVM_ED_FindGlobalOffset("v_up");
1339 prog->globaloffsets.trace_allsolid = PRVM_ED_FindGlobalOffset("trace_allsolid");
1340 prog->globaloffsets.trace_startsolid = PRVM_ED_FindGlobalOffset("trace_startsolid");
1341 prog->globaloffsets.trace_fraction = PRVM_ED_FindGlobalOffset("trace_fraction");
1342 prog->globaloffsets.trace_inwater = PRVM_ED_FindGlobalOffset("trace_inwater");
1343 prog->globaloffsets.trace_inopen = PRVM_ED_FindGlobalOffset("trace_inopen");
1344 prog->globaloffsets.trace_endpos = PRVM_ED_FindGlobalOffset("trace_endpos");
1345 prog->globaloffsets.trace_plane_normal = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1346 prog->globaloffsets.trace_plane_dist = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1347 prog->globaloffsets.trace_ent = PRVM_ED_FindGlobalOffset("trace_ent");
1348 prog->globaloffsets.trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1349 prog->globaloffsets.trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1350 prog->globaloffsets.trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1351 prog->globaloffsets.trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1353 // menu qc only uses some functions, nothing else
1354 prog->funcoffsets.m_display = PRVM_ED_FindFunctionOffset("m_display");
1355 prog->funcoffsets.m_draw = PRVM_ED_FindFunctionOffset("m_draw");
1356 prog->funcoffsets.m_hide = PRVM_ED_FindFunctionOffset("m_hide");
1357 prog->funcoffsets.m_init = PRVM_ED_FindFunctionOffset("m_init");
1358 prog->funcoffsets.m_keydown = PRVM_ED_FindFunctionOffset("m_keydown");
1359 prog->funcoffsets.m_keyup = PRVM_ED_FindFunctionOffset("m_keyup");
1360 prog->funcoffsets.m_shutdown = PRVM_ED_FindFunctionOffset("m_shutdown");
1361 prog->funcoffsets.m_toggle = PRVM_ED_FindFunctionOffset("m_toggle");
1366 typedef struct dpfield_s
1373 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1375 dpfield_t dpfields[] =
1386 void PRVM_ResetProg()
1388 PRVM_GCALL(reset_cmd)();
1389 Mem_FreePool(&prog->progs_mempool);
1390 memset(prog,0,sizeof(prvm_prog_t));
1398 void PRVM_LoadLNO( const char *progname ) {
1399 fs_offset_t filesize;
1401 unsigned int *header;
1404 FS_StripExtension( progname, filename, sizeof( filename ) );
1405 strlcat( filename, ".lno", sizeof( filename ) );
1407 lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1413 <Spike> SafeWrite (h, &lnotype, sizeof(int));
1414 <Spike> SafeWrite (h, &version, sizeof(int));
1415 <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
1416 <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
1417 <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
1418 <Spike> SafeWrite (h, &numstatements, sizeof(int));
1419 <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1421 if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1426 header = (unsigned int *) lno;
1427 if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1428 LittleLong( header[ 1 ] ) == 1 &&
1429 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1430 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1431 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1432 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1434 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1435 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1445 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1449 ddef_t *infielddefs;
1450 dfunction_t *dfunctions;
1451 fs_offset_t filesize;
1453 if( prog->loaded ) {
1454 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1457 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1458 if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1459 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1461 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1463 prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1465 // byte swap the header
1466 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1467 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1469 if (prog->progs->version != PROG_VERSION)
1470 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1471 if (prog->progs->crc != prog->headercrc)
1472 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1474 //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1475 dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1477 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1478 prog->stringssize = 0;
1479 for (i = 0;i < prog->progs->numstrings;i++)
1481 if (prog->progs->ofs_strings + prog->stringssize >= (int)filesize)
1482 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1483 prog->stringssize += (int)strlen (prog->strings + prog->stringssize) + 1;
1485 prog->numknownstrings = 0;
1486 prog->maxknownstrings = 0;
1487 prog->knownstrings = NULL;
1488 prog->knownstrings_freeable = NULL;
1490 prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1492 // we need to expand the fielddefs list to include all the engine fields,
1493 // so allocate a new place for it
1494 infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1496 prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1498 prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1500 prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1502 // moved edict_size calculation down below field adding code
1504 //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1505 prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1507 // byte swap the lumps
1508 for (i=0 ; i<prog->progs->numstatements ; i++)
1510 prog->statements[i].op = LittleShort(prog->statements[i].op);
1511 prog->statements[i].a = LittleShort(prog->statements[i].a);
1512 prog->statements[i].b = LittleShort(prog->statements[i].b);
1513 prog->statements[i].c = LittleShort(prog->statements[i].c);
1516 prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1517 for (i = 0;i < prog->progs->numfunctions;i++)
1519 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1520 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1521 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1522 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1523 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1524 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1525 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1528 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1530 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1531 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1532 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1535 // copy the progs fields to the new fields list
1536 for (i = 0;i < prog->progs->numfielddefs;i++)
1538 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1539 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1540 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1541 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1542 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1545 // append the required fields
1546 for (i = 0;i < (int) numrequiredfields;i++)
1548 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1549 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1550 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1551 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1552 prog->progs->entityfields += 3;
1554 prog->progs->entityfields++;
1555 prog->progs->numfielddefs++;
1558 // check required functions
1559 for(i=0 ; i < numrequiredfunc ; i++)
1560 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1561 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1563 // check required globals
1564 for(i=0 ; i < numrequiredglobals ; i++)
1565 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1566 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1568 for (i=0 ; i<prog->progs->numglobals ; i++)
1569 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1571 // moved edict_size calculation down here, below field adding code
1572 // LordHavoc: this no longer includes the prvm_edict_t header
1573 prog->edict_size = prog->progs->entityfields * 4;
1574 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1576 // LordHavoc: bounds check anything static
1577 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1583 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1584 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1587 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1588 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1590 // global global global
1625 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1626 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1628 // global none global
1634 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1635 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1651 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1652 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1666 if ((unsigned short) st->a >= prog->progs->numglobals)
1667 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1670 Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1675 PRVM_LoadLNO(filename);
1679 prog->loaded = TRUE;
1681 // set flags & ddef_ts in prog
1687 PRVM_GCALL(init_cmd)();
1694 void PRVM_Fields_f (void)
1696 int i, j, ednum, used, usedamount;
1698 char tempstring[MAX_INPUTLINE], tempstring2[260];
1708 Con_Print("no progs loaded\n");
1715 Con_Print("prvm_fields <program name>\n");
1720 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1723 counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1724 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1726 ed = PRVM_EDICT_NUM(ednum);
1727 if (ed->priv.required->free)
1729 for (i = 1;i < prog->progs->numfielddefs;i++)
1731 d = &prog->fielddefs[i];
1732 name = PRVM_GetString(d->s_name);
1733 if (name[strlen(name)-2] == '_')
1734 continue; // skip _x, _y, _z vars
1735 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1736 // if the value is still all 0, skip the field
1737 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1750 for (i = 0;i < prog->progs->numfielddefs;i++)
1752 d = &prog->fielddefs[i];
1753 name = PRVM_GetString(d->s_name);
1754 if (name[strlen(name)-2] == '_')
1755 continue; // skip _x, _y, _z vars
1756 switch(d->type & ~DEF_SAVEGLOBAL)
1759 strlcat(tempstring, "string ", sizeof(tempstring));
1762 strlcat(tempstring, "entity ", sizeof(tempstring));
1765 strlcat(tempstring, "function ", sizeof(tempstring));
1768 strlcat(tempstring, "field ", sizeof(tempstring));
1771 strlcat(tempstring, "void ", sizeof(tempstring));
1774 strlcat(tempstring, "float ", sizeof(tempstring));
1777 strlcat(tempstring, "vector ", sizeof(tempstring));
1780 strlcat(tempstring, "pointer ", sizeof(tempstring));
1783 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1784 strlcat(tempstring, tempstring2, sizeof(tempstring));
1787 if (strlen(name) > sizeof(tempstring2)-4)
1789 memcpy (tempstring2, name, sizeof(tempstring2)-4);
1790 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1791 tempstring2[sizeof(tempstring2)-1] = 0;
1794 strlcat(tempstring, name, sizeof(tempstring));
1795 for (j = (int)strlen(name);j < 25;j++)
1796 strlcat(tempstring, " ", sizeof(tempstring));
1797 sprintf(tempstring2, "%5d", counts[i]);
1798 strlcat(tempstring, tempstring2, sizeof(tempstring));
1799 strlcat(tempstring, "\n", sizeof(tempstring));
1800 if (strlen(tempstring) >= sizeof(tempstring)/2)
1802 Con_Print(tempstring);
1808 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1812 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);
1817 void PRVM_Globals_f (void)
1823 Con_Print("no progs loaded\n");
1826 if(Cmd_Argc () != 2)
1828 Con_Print("prvm_globals <program name>\n");
1833 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1836 Con_Printf("%s :", PRVM_NAME);
1838 for (i = 0;i < prog->progs->numglobaldefs;i++)
1839 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1840 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1850 void PRVM_Global_f(void)
1853 if( Cmd_Argc() != 3 ) {
1854 Con_Printf( "prvm_global <program name> <global name>\n" );
1859 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1862 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1864 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1866 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1875 void PRVM_GlobalSet_f(void)
1878 if( Cmd_Argc() != 4 ) {
1879 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1884 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1887 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1889 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1891 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1900 void PRVM_Init (void)
1902 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
1903 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "set a property on an entity number in the selected VM (server, client, menu)");
1904 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
1905 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
1906 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)");
1907 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
1908 Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
1909 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
1910 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)");
1911 Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
1912 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1913 Cvar_RegisterVariable (&prvm_boundscheck);
1914 Cvar_RegisterVariable (&prvm_traceqc);
1915 Cvar_RegisterVariable (&prvm_statementprofiling);
1925 void PRVM_InitProg(int prognr)
1927 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1928 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
1930 prog = &prog_list[prognr];
1935 memset(prog, 0, sizeof(prvm_prog_t));
1937 prog->error_cmd = Host_Error;
1940 int PRVM_GetProgNr()
1942 return prog - prog_list;
1945 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1947 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1950 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1952 _Mem_Free(buffer, filename, fileline);
1955 void _PRVM_FreeAll(const char *filename, int fileline)
1958 prog->fielddefs = NULL;
1959 prog->functions = NULL;
1960 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1963 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1964 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1966 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1971 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1973 PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1977 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1980 n = e - prog->edicts;
1981 if ((unsigned int)n >= prog->limit_edicts)
1982 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1986 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1988 // return e - prog->edicts;
1991 //#define PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
1992 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1993 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1996 n = e - prog->edicts;
1997 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1998 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
1999 return n;// EXPERIMENTAL
2000 //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2002 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2004 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2005 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2006 return prog->edicts + n; // EXPERIMENTAL
2007 //return prog->edicts + ((n) / (progs->entityfields * 4));
2012 sizebuf_t vm_tempstringsbuf;
2014 const char *PRVM_GetString(int num)
2018 if (num < prog->stringssize)
2019 return prog->strings + num;
2022 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2024 num -= prog->stringssize;
2025 if (num < vm_tempstringsbuf.cursize)
2026 return (char *)vm_tempstringsbuf.data + num;
2029 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2036 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
2046 // special range reserved for tempstrings
2048 if (num < vm_tempstringsbuf.cursize)
2049 return (char *)vm_tempstringsbuf.data + num;
2052 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2058 if (num < prog->numknownstrings)
2060 if (!prog->knownstrings[num])
2061 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
2062 return prog->knownstrings[num];
2066 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
2072 int PRVM_SetEngineString(const char *s)
2077 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2078 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2079 // if it's in the tempstrings area, use a reserved range
2080 // (otherwise we'd get millions of useless string offsets cluttering the database)
2081 if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2083 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2085 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2087 // see if it's a known string address
2088 for (i = 0;i < prog->numknownstrings;i++)
2089 if (prog->knownstrings[i] == s)
2091 // new unknown engine string
2092 if (developer.integer >= 100)
2093 Con_Printf("new engine string %p\n", s);
2094 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2095 if (!prog->knownstrings[i])
2097 if (i >= prog->numknownstrings)
2099 if (i >= prog->maxknownstrings)
2101 const char **oldstrings = prog->knownstrings;
2102 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2103 prog->maxknownstrings += 128;
2104 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2105 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2106 if (prog->numknownstrings)
2108 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2109 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2112 prog->numknownstrings++;
2114 prog->firstfreeknownstring = i + 1;
2115 prog->knownstrings[i] = s;
2119 // temp string handling
2121 // all tempstrings go into this buffer consecutively, and it is reset
2122 // whenever PRVM_ExecuteProgram returns to the engine
2123 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2124 // restores it on return, so multiple recursive calls can share the same
2126 // the buffer size is automatically grown as needed
2128 int PRVM_SetTempString(const char *s)
2134 size = (int)strlen(s) + 1;
2135 if (developer.integer >= 300)
2136 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2137 if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2139 sizebuf_t old = vm_tempstringsbuf;
2140 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2141 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);
2142 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2143 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2144 vm_tempstringsbuf.maxsize *= 2;
2145 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2147 if (developer.integer >= 100)
2148 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2149 vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2151 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2156 t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2158 vm_tempstringsbuf.cursize += size;
2159 return PRVM_SetEngineString(t);
2162 int PRVM_AllocString(size_t bufferlength, char **pointer)
2167 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2168 if (!prog->knownstrings[i])
2170 if (i >= prog->numknownstrings)
2172 if (i >= prog->maxknownstrings)
2174 const char **oldstrings = prog->knownstrings;
2175 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2176 prog->maxknownstrings += 128;
2177 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2178 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2179 if (prog->numknownstrings)
2181 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2182 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2185 prog->numknownstrings++;
2187 prog->firstfreeknownstring = i + 1;
2188 prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2189 prog->knownstrings_freeable[i] = true;
2191 *pointer = (char *)(prog->knownstrings[i]);
2195 void PRVM_FreeString(int num)
2198 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2199 else if (num >= 0 && num < prog->stringssize)
2200 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2201 else if (num < 0 && num >= -prog->numknownstrings)
2204 if (!prog->knownstrings[num])
2205 PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2206 if (!prog->knownstrings[num])
2207 PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2208 PRVM_Free((char *)prog->knownstrings[num]);
2209 prog->knownstrings[num] = NULL;
2210 prog->knownstrings_freeable[num] = false;
2211 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2214 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);