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.disableclientprediction = PRVM_ED_FindFieldOffset("disableclientprediction");
1275 prog->fieldoffsets.dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1276 prog->fieldoffsets.drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
1277 prog->fieldoffsets.exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1278 prog->fieldoffsets.fatness = PRVM_ED_FindFieldOffset("fatness");
1279 prog->fieldoffsets.forceshader = PRVM_ED_FindFieldOffset("forceshader");
1280 prog->fieldoffsets.frame = PRVM_ED_FindFieldOffset("frame");
1281 prog->fieldoffsets.frame1time = PRVM_ED_FindFieldOffset("frame1time");
1282 prog->fieldoffsets.frame2 = PRVM_ED_FindFieldOffset("frame2");
1283 prog->fieldoffsets.frame2time = PRVM_ED_FindFieldOffset("frame2time");
1284 prog->fieldoffsets.fullbright = PRVM_ED_FindFieldOffset("fullbright");
1285 prog->fieldoffsets.glow_color = PRVM_ED_FindFieldOffset("glow_color");
1286 prog->fieldoffsets.glow_size = PRVM_ED_FindFieldOffset("glow_size");
1287 prog->fieldoffsets.glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
1288 prog->fieldoffsets.gravity = PRVM_ED_FindFieldOffset("gravity");
1289 prog->fieldoffsets.groundentity = PRVM_ED_FindFieldOffset("groundentity");
1290 prog->fieldoffsets.hull = PRVM_ED_FindFieldOffset("hull");
1291 prog->fieldoffsets.ideal_yaw = PRVM_ED_FindFieldOffset("ideal_yaw");
1292 prog->fieldoffsets.idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
1293 prog->fieldoffsets.items2 = PRVM_ED_FindFieldOffset("items2");
1294 prog->fieldoffsets.lerpfrac = PRVM_ED_FindFieldOffset("lerpfrac");
1295 prog->fieldoffsets.light_lev = PRVM_ED_FindFieldOffset("light_lev");
1296 prog->fieldoffsets.movement = PRVM_ED_FindFieldOffset("movement");
1297 prog->fieldoffsets.nextthink = PRVM_ED_FindFieldOffset("nextthink");
1298 prog->fieldoffsets.nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
1299 prog->fieldoffsets.pflags = PRVM_ED_FindFieldOffset("pflags");
1300 prog->fieldoffsets.ping = PRVM_ED_FindFieldOffset("ping");
1301 prog->fieldoffsets.pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
1302 prog->fieldoffsets.playermodel = PRVM_ED_FindFieldOffset("playermodel");
1303 prog->fieldoffsets.playerskin = PRVM_ED_FindFieldOffset("playerskin");
1304 prog->fieldoffsets.pmodel = PRVM_ED_FindFieldOffset("pmodel");
1305 prog->fieldoffsets.punchvector = PRVM_ED_FindFieldOffset("punchvector");
1306 prog->fieldoffsets.renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1307 prog->fieldoffsets.renderflags = PRVM_ED_FindFieldOffset("renderflags");
1308 prog->fieldoffsets.rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1309 prog->fieldoffsets.scale = PRVM_ED_FindFieldOffset("scale");
1310 prog->fieldoffsets.style = PRVM_ED_FindFieldOffset("style");
1311 prog->fieldoffsets.tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
1312 prog->fieldoffsets.tag_index = PRVM_ED_FindFieldOffset("tag_index");
1313 prog->fieldoffsets.think = PRVM_ED_FindFieldOffset("think");
1314 prog->fieldoffsets.viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
1315 prog->fieldoffsets.viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
1316 prog->fieldoffsets.yaw_speed = PRVM_ED_FindFieldOffset("yaw_speed");
1317 prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1318 prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1319 prog->funcoffsets.CSQC_Ent_Update = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1320 prog->funcoffsets.CSQC_Event = PRVM_ED_FindFunctionOffset("CSQC_Event");
1321 prog->funcoffsets.CSQC_Init = PRVM_ED_FindFunctionOffset("CSQC_Init");
1322 prog->funcoffsets.CSQC_InputEvent = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1323 prog->funcoffsets.CSQC_Parse_CenterPrint = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1324 prog->funcoffsets.CSQC_Parse_Print = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1325 prog->funcoffsets.CSQC_Parse_StuffCmd = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1326 prog->funcoffsets.CSQC_Parse_TempEntity = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1327 prog->funcoffsets.CSQC_Shutdown = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1328 prog->funcoffsets.CSQC_UpdateView = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1329 prog->funcoffsets.EndFrame = PRVM_ED_FindFunctionOffset("EndFrame");
1330 prog->funcoffsets.RestoreGame = PRVM_ED_FindFunctionOffset("RestoreGame");
1331 prog->funcoffsets.SV_ChangeTeam = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1332 prog->funcoffsets.SV_ParseClientCommand = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1333 prog->funcoffsets.SV_PlayerPhysics = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1334 prog->globaloffsets.SV_InitCmd = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1335 prog->globaloffsets.self = PRVM_ED_FindGlobalOffset("self");
1336 prog->globaloffsets.time = PRVM_ED_FindGlobalOffset("time");
1337 prog->globaloffsets.v_forward = PRVM_ED_FindGlobalOffset("v_forward");
1338 prog->globaloffsets.v_right = PRVM_ED_FindGlobalOffset("v_right");
1339 prog->globaloffsets.v_up = PRVM_ED_FindGlobalOffset("v_up");
1340 prog->globaloffsets.trace_allsolid = PRVM_ED_FindGlobalOffset("trace_allsolid");
1341 prog->globaloffsets.trace_startsolid = PRVM_ED_FindGlobalOffset("trace_startsolid");
1342 prog->globaloffsets.trace_fraction = PRVM_ED_FindGlobalOffset("trace_fraction");
1343 prog->globaloffsets.trace_inwater = PRVM_ED_FindGlobalOffset("trace_inwater");
1344 prog->globaloffsets.trace_inopen = PRVM_ED_FindGlobalOffset("trace_inopen");
1345 prog->globaloffsets.trace_endpos = PRVM_ED_FindGlobalOffset("trace_endpos");
1346 prog->globaloffsets.trace_plane_normal = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1347 prog->globaloffsets.trace_plane_dist = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1348 prog->globaloffsets.trace_ent = PRVM_ED_FindGlobalOffset("trace_ent");
1349 prog->globaloffsets.trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1350 prog->globaloffsets.trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1351 prog->globaloffsets.trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1352 prog->globaloffsets.trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1354 // menu qc only uses some functions, nothing else
1355 prog->funcoffsets.m_display = PRVM_ED_FindFunctionOffset("m_display");
1356 prog->funcoffsets.m_draw = PRVM_ED_FindFunctionOffset("m_draw");
1357 prog->funcoffsets.m_hide = PRVM_ED_FindFunctionOffset("m_hide");
1358 prog->funcoffsets.m_init = PRVM_ED_FindFunctionOffset("m_init");
1359 prog->funcoffsets.m_keydown = PRVM_ED_FindFunctionOffset("m_keydown");
1360 prog->funcoffsets.m_keyup = PRVM_ED_FindFunctionOffset("m_keyup");
1361 prog->funcoffsets.m_shutdown = PRVM_ED_FindFunctionOffset("m_shutdown");
1362 prog->funcoffsets.m_toggle = PRVM_ED_FindFunctionOffset("m_toggle");
1367 typedef struct dpfield_s
1374 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1376 dpfield_t dpfields[] =
1387 void PRVM_ResetProg()
1389 PRVM_GCALL(reset_cmd)();
1390 Mem_FreePool(&prog->progs_mempool);
1391 memset(prog,0,sizeof(prvm_prog_t));
1399 void PRVM_LoadLNO( const char *progname ) {
1400 fs_offset_t filesize;
1402 unsigned int *header;
1405 FS_StripExtension( progname, filename, sizeof( filename ) );
1406 strlcat( filename, ".lno", sizeof( filename ) );
1408 lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1414 <Spike> SafeWrite (h, &lnotype, sizeof(int));
1415 <Spike> SafeWrite (h, &version, sizeof(int));
1416 <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
1417 <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
1418 <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
1419 <Spike> SafeWrite (h, &numstatements, sizeof(int));
1420 <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1422 if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1427 header = (unsigned int *) lno;
1428 if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1429 LittleLong( header[ 1 ] ) == 1 &&
1430 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1431 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1432 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1433 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1435 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1436 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1446 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1450 ddef_t *infielddefs;
1451 dfunction_t *dfunctions;
1452 fs_offset_t filesize;
1454 if( prog->loaded ) {
1455 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1458 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1459 if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1460 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1462 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1464 prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1466 // byte swap the header
1467 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1468 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1470 if (prog->progs->version != PROG_VERSION)
1471 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1472 if (prog->progs->crc != prog->headercrc)
1473 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1475 //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1476 dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1478 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1479 prog->stringssize = 0;
1480 for (i = 0;i < prog->progs->numstrings;i++)
1482 if (prog->progs->ofs_strings + prog->stringssize >= (int)filesize)
1483 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1484 prog->stringssize += (int)strlen (prog->strings + prog->stringssize) + 1;
1486 prog->numknownstrings = 0;
1487 prog->maxknownstrings = 0;
1488 prog->knownstrings = NULL;
1489 prog->knownstrings_freeable = NULL;
1491 prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1493 // we need to expand the fielddefs list to include all the engine fields,
1494 // so allocate a new place for it
1495 infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1497 prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1499 prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1501 prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1503 // moved edict_size calculation down below field adding code
1505 //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1506 prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1508 // byte swap the lumps
1509 for (i=0 ; i<prog->progs->numstatements ; i++)
1511 prog->statements[i].op = LittleShort(prog->statements[i].op);
1512 prog->statements[i].a = LittleShort(prog->statements[i].a);
1513 prog->statements[i].b = LittleShort(prog->statements[i].b);
1514 prog->statements[i].c = LittleShort(prog->statements[i].c);
1517 prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1518 for (i = 0;i < prog->progs->numfunctions;i++)
1520 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1521 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1522 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1523 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1524 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1525 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1526 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1529 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1531 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1532 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1533 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1536 // copy the progs fields to the new fields list
1537 for (i = 0;i < prog->progs->numfielddefs;i++)
1539 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1540 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1541 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1542 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1543 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1546 // append the required fields
1547 for (i = 0;i < (int) numrequiredfields;i++)
1549 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1550 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1551 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1552 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1553 prog->progs->entityfields += 3;
1555 prog->progs->entityfields++;
1556 prog->progs->numfielddefs++;
1559 // check required functions
1560 for(i=0 ; i < numrequiredfunc ; i++)
1561 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1562 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1564 // check required globals
1565 for(i=0 ; i < numrequiredglobals ; i++)
1566 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1567 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1569 for (i=0 ; i<prog->progs->numglobals ; i++)
1570 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1572 // moved edict_size calculation down here, below field adding code
1573 // LordHavoc: this no longer includes the prvm_edict_t header
1574 prog->edict_size = prog->progs->entityfields * 4;
1575 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1577 // LordHavoc: bounds check anything static
1578 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1584 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1585 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1588 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1589 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1591 // global global global
1626 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1627 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1629 // global none global
1635 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1636 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1652 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1653 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1667 if ((unsigned short) st->a >= prog->progs->numglobals)
1668 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1671 Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1676 PRVM_LoadLNO(filename);
1680 prog->loaded = TRUE;
1682 // set flags & ddef_ts in prog
1688 PRVM_GCALL(init_cmd)();
1695 void PRVM_Fields_f (void)
1697 int i, j, ednum, used, usedamount;
1699 char tempstring[MAX_INPUTLINE], tempstring2[260];
1709 Con_Print("no progs loaded\n");
1716 Con_Print("prvm_fields <program name>\n");
1721 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1724 counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1725 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1727 ed = PRVM_EDICT_NUM(ednum);
1728 if (ed->priv.required->free)
1730 for (i = 1;i < prog->progs->numfielddefs;i++)
1732 d = &prog->fielddefs[i];
1733 name = PRVM_GetString(d->s_name);
1734 if (name[strlen(name)-2] == '_')
1735 continue; // skip _x, _y, _z vars
1736 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1737 // if the value is still all 0, skip the field
1738 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1751 for (i = 0;i < prog->progs->numfielddefs;i++)
1753 d = &prog->fielddefs[i];
1754 name = PRVM_GetString(d->s_name);
1755 if (name[strlen(name)-2] == '_')
1756 continue; // skip _x, _y, _z vars
1757 switch(d->type & ~DEF_SAVEGLOBAL)
1760 strlcat(tempstring, "string ", sizeof(tempstring));
1763 strlcat(tempstring, "entity ", sizeof(tempstring));
1766 strlcat(tempstring, "function ", sizeof(tempstring));
1769 strlcat(tempstring, "field ", sizeof(tempstring));
1772 strlcat(tempstring, "void ", sizeof(tempstring));
1775 strlcat(tempstring, "float ", sizeof(tempstring));
1778 strlcat(tempstring, "vector ", sizeof(tempstring));
1781 strlcat(tempstring, "pointer ", sizeof(tempstring));
1784 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1785 strlcat(tempstring, tempstring2, sizeof(tempstring));
1788 if (strlen(name) > sizeof(tempstring2)-4)
1790 memcpy (tempstring2, name, sizeof(tempstring2)-4);
1791 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1792 tempstring2[sizeof(tempstring2)-1] = 0;
1795 strlcat(tempstring, name, sizeof(tempstring));
1796 for (j = (int)strlen(name);j < 25;j++)
1797 strlcat(tempstring, " ", sizeof(tempstring));
1798 sprintf(tempstring2, "%5d", counts[i]);
1799 strlcat(tempstring, tempstring2, sizeof(tempstring));
1800 strlcat(tempstring, "\n", sizeof(tempstring));
1801 if (strlen(tempstring) >= sizeof(tempstring)/2)
1803 Con_Print(tempstring);
1809 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1813 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);
1818 void PRVM_Globals_f (void)
1824 Con_Print("no progs loaded\n");
1827 if(Cmd_Argc () != 2)
1829 Con_Print("prvm_globals <program name>\n");
1834 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1837 Con_Printf("%s :", PRVM_NAME);
1839 for (i = 0;i < prog->progs->numglobaldefs;i++)
1840 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1841 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1851 void PRVM_Global_f(void)
1854 if( Cmd_Argc() != 3 ) {
1855 Con_Printf( "prvm_global <program name> <global name>\n" );
1860 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1863 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1865 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1867 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1876 void PRVM_GlobalSet_f(void)
1879 if( Cmd_Argc() != 4 ) {
1880 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1885 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1888 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1890 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1892 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1901 void PRVM_Init (void)
1903 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
1904 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "set a property on an entity number in the selected VM (server, client, menu)");
1905 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
1906 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
1907 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)");
1908 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
1909 Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
1910 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
1911 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)");
1912 Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
1913 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1914 Cvar_RegisterVariable (&prvm_boundscheck);
1915 Cvar_RegisterVariable (&prvm_traceqc);
1916 Cvar_RegisterVariable (&prvm_statementprofiling);
1926 void PRVM_InitProg(int prognr)
1928 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1929 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
1931 prog = &prog_list[prognr];
1936 memset(prog, 0, sizeof(prvm_prog_t));
1938 prog->error_cmd = Host_Error;
1941 int PRVM_GetProgNr()
1943 return prog - prog_list;
1946 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1948 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1951 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1953 _Mem_Free(buffer, filename, fileline);
1956 void _PRVM_FreeAll(const char *filename, int fileline)
1959 prog->fielddefs = NULL;
1960 prog->functions = NULL;
1961 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1964 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1965 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1967 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1972 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1974 PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1978 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1981 n = e - prog->edicts;
1982 if ((unsigned int)n >= prog->limit_edicts)
1983 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1987 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1989 // return e - prog->edicts;
1992 //#define PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
1993 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1994 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1997 n = e - prog->edicts;
1998 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1999 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2000 return n;// EXPERIMENTAL
2001 //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2003 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2005 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2006 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2007 return prog->edicts + n; // EXPERIMENTAL
2008 //return prog->edicts + ((n) / (progs->entityfields * 4));
2013 sizebuf_t vm_tempstringsbuf;
2015 const char *PRVM_GetString(int num)
2019 if (num < prog->stringssize)
2020 return prog->strings + num;
2023 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2025 num -= prog->stringssize;
2026 if (num < vm_tempstringsbuf.cursize)
2027 return (char *)vm_tempstringsbuf.data + num;
2030 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2037 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
2047 // special range reserved for tempstrings
2049 if (num < vm_tempstringsbuf.cursize)
2050 return (char *)vm_tempstringsbuf.data + num;
2053 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2059 if (num < prog->numknownstrings)
2061 if (!prog->knownstrings[num])
2062 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
2063 return prog->knownstrings[num];
2067 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
2073 int PRVM_SetEngineString(const char *s)
2078 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2079 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2080 // if it's in the tempstrings area, use a reserved range
2081 // (otherwise we'd get millions of useless string offsets cluttering the database)
2082 if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2084 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2086 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2088 // see if it's a known string address
2089 for (i = 0;i < prog->numknownstrings;i++)
2090 if (prog->knownstrings[i] == s)
2092 // new unknown engine string
2093 if (developer.integer >= 200)
2094 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2095 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2096 if (!prog->knownstrings[i])
2098 if (i >= prog->numknownstrings)
2100 if (i >= prog->maxknownstrings)
2102 const char **oldstrings = prog->knownstrings;
2103 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2104 prog->maxknownstrings += 128;
2105 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2106 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2107 if (prog->numknownstrings)
2109 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2110 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2113 prog->numknownstrings++;
2115 prog->firstfreeknownstring = i + 1;
2116 prog->knownstrings[i] = s;
2120 // temp string handling
2122 // all tempstrings go into this buffer consecutively, and it is reset
2123 // whenever PRVM_ExecuteProgram returns to the engine
2124 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2125 // restores it on return, so multiple recursive calls can share the same
2127 // the buffer size is automatically grown as needed
2129 int PRVM_SetTempString(const char *s)
2135 size = (int)strlen(s) + 1;
2136 if (developer.integer >= 300)
2137 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2138 if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2140 sizebuf_t old = vm_tempstringsbuf;
2141 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2142 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);
2143 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2144 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2145 vm_tempstringsbuf.maxsize *= 2;
2146 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2148 if (developer.integer >= 100)
2149 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2150 vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2152 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2157 t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2159 vm_tempstringsbuf.cursize += size;
2160 return PRVM_SetEngineString(t);
2163 int PRVM_AllocString(size_t bufferlength, char **pointer)
2168 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2169 if (!prog->knownstrings[i])
2171 if (i >= prog->numknownstrings)
2173 if (i >= prog->maxknownstrings)
2175 const char **oldstrings = prog->knownstrings;
2176 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2177 prog->maxknownstrings += 128;
2178 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2179 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2180 if (prog->numknownstrings)
2182 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2183 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2186 prog->numknownstrings++;
2188 prog->firstfreeknownstring = i + 1;
2189 prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2190 prog->knownstrings_freeable[i] = true;
2192 *pointer = (char *)(prog->knownstrings[i]);
2196 void PRVM_FreeString(int num)
2199 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2200 else if (num >= 0 && num < prog->stringssize)
2201 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2202 else if (num < 0 && num >= -prog->numknownstrings)
2205 if (!prog->knownstrings[num])
2206 PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2207 if (!prog->knownstrings[num])
2208 PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2209 PRVM_Free((char *)prog->knownstrings[num]);
2210 prog->knownstrings[num] = NULL;
2211 prog->knownstrings_freeable[num] = false;
2212 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2215 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);