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.
26 static prvm_prog_t prog_list[PRVM_MAXPROGS];
28 int prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
30 ddef_t *PRVM_ED_FieldAtOfs(int ofs);
31 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s);
33 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
34 cvar_t prvm_boundscheck = {0, "prvm_boundscheck", "1"};
35 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
36 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0"};
38 ddef_t *PRVM_ED_FindField (const char *name);
39 mfunction_t *PRVM_ED_FindFunction (const char *name);
41 //============================================================================
53 // reserve space for the null entity aka world
54 // check bound of max_edicts
55 prog->max_edicts = bound(1, prog->max_edicts, prog->limit_edicts);
56 prog->num_edicts = bound(1, 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 = Mem_Alloc(prog->edicts_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
64 // alloc edict private space
65 prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
68 prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
71 for(i = 0; i < prog->max_edicts; i++)
73 prog->edicts[i].e = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
74 prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
80 PRVM_MEM_IncreaseEdicts
83 void PRVM_MEM_IncreaseEdicts()
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->edicts_mempool, prog->max_edicts * prog->edict_size);
99 prog->edictprivate = Mem_Alloc(prog->edicts_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].e = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
108 prog->edicts[i].v = (void*)((qbyte *)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 qboolean PRVM_ProgLoaded(int prognr)
131 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
134 return (prog_list[prognr].loaded ? TRUE : FALSE);
139 PRVM_SetProgFromString
142 // perhaps add a return value when the str doesnt exist
143 qboolean PRVM_SetProgFromString(const char *str)
146 for(; i < PRVM_MAXPROGS ; i++)
147 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
149 if(prog_list[i].loaded)
151 prog = &prog_list[i];
156 Con_Printf("%s not loaded !\n",PRVM_NAME);
161 Con_Printf("Invalid program name %s !\n", str);
170 void PRVM_SetProg(int prognr)
172 if(prognr && prognr < PRVM_MAXPROGS)
174 if(prog_list[prognr].loaded)
175 prog = &prog_list[prognr];
177 PRVM_ERROR("%i(%s) not loaded !\n", prognr, PRVM_NAME);
180 PRVM_ERROR("Invalid program number %i\n", prognr);
187 Sets everything to NULL
190 void PRVM_ED_ClearEdict (prvm_edict_t *e)
193 memset (e->v, 0, prog->progs->entityfields * 4);
195 // LordHavoc: for consistency set these here
196 num = PRVM_NUM_FOR_EDICT(e) - 1;
198 // AK: Let the init_edict function determine if something needs to be initialized
199 PRVM_GCALL(init_edict)(num);
206 Either finds a free edict, or allocates a new one.
207 Try to avoid reusing an entity that was recently freed, because it
208 can cause the client to think the entity morphed into something else
209 instead of being removed and recreated, which can cause interpolated
210 angles and bad trails.
213 prvm_edict_t *PRVM_ED_Alloc (void)
218 // the client qc dont need maxclients
219 // thus it doesnt need to use svs.maxclients
220 // AK: changed i=svs.maxclients+1
221 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
222 // although the menu/client has no world
223 for (i = 1;i < prog->num_edicts;i++)
225 e = PRVM_EDICT_NUM(i);
226 // the first couple seconds of server time can involve a lot of
227 // freeing and allocating, so relax the replacement policy
228 if (e->e->free && ( e->e->freetime < 2 || *prog->time - e->e->freetime > 0.5 ) )
230 PRVM_ED_ClearEdict (e);
236 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
239 if (prog->num_edicts >= prog->max_edicts)
240 PRVM_MEM_IncreaseEdicts();
242 e = PRVM_EDICT_NUM(i);
243 PRVM_ED_ClearEdict (e);
252 Marks the edict as free
253 FIXME: walk all entities and NULL out references to this entity
256 void PRVM_ED_Free (prvm_edict_t *ed)
258 PRVM_GCALL(free_edict)(ed);
261 ed->e->freetime = *prog->time;
264 //===========================================================================
271 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
276 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
278 def = &prog->globaldefs[i];
290 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
295 for (i=0 ; i<prog->progs->numfielddefs ; i++)
297 def = &prog->fielddefs[i];
309 ddef_t *PRVM_ED_FindField (const char *name)
314 for (i=0 ; i<prog->progs->numfielddefs ; i++)
316 def = &prog->fielddefs[i];
317 if (!strcmp(PRVM_GetString(def->s_name), name))
328 ddef_t *PRVM_ED_FindGlobal (const char *name)
333 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
335 def = &prog->globaldefs[i];
336 if (!strcmp(PRVM_GetString(def->s_name), name))
348 mfunction_t *PRVM_ED_FindFunction (const char *name)
353 for (i=0 ; i<prog->progs->numfunctions ; i++)
355 func = &prog->functions[i];
356 if (!strcmp(PRVM_GetString(func->s_name), name))
367 Returns a string describing *data in a type specific manner
370 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
372 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
377 type &= ~DEF_SAVEGLOBAL;
382 sprintf (line, "%s", PRVM_GetString(val->string));
386 if (n < 0 || n >= MAX_EDICTS)
387 sprintf (line, "entity %i (invalid!)", n);
389 sprintf (line, "entity %i", n);
392 f = prog->functions + val->function;
393 sprintf (line, "%s()", PRVM_GetString(f->s_name));
396 def = PRVM_ED_FieldAtOfs ( val->_int );
397 sprintf (line, ".%s", PRVM_GetString(def->s_name));
400 sprintf (line, "void");
403 // LordHavoc: changed from %5.1f to %10.4f
404 sprintf (line, "%10.4f", val->_float);
407 // LordHavoc: changed from %5.1f to %10.4f
408 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
411 sprintf (line, "pointer");
414 sprintf (line, "bad type %i", type);
425 Returns a string describing *data in a type specific manner
426 Easier to parse than PR_ValueString
429 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
431 static char line[4096];
437 type &= ~DEF_SAVEGLOBAL;
442 // Parse the string a bit to turn special characters
443 // (like newline, specifically) into escape codes,
444 // this fixes saving games from various mods
445 s = PRVM_GetString (val->string);
446 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
465 snprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
468 f = pr_functions + val->function;
469 snprintf (line, sizeof (line), "%s", PRVM_GetString(f->s_name));
472 def = PRVM_ED_FieldAtOfs ( val->_int );
473 snprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
476 snprintf (line, sizeof (line), "void");
479 snprintf (line, sizeof (line), "%f", val->_float);
482 snprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
485 snprintf (line, sizeof (line), "bad type %i", type);
496 Returns a string with a description and the contents of a global,
497 padded to 20 field width
500 char *PRVM_GlobalString (int ofs)
506 static char line[128];
508 val = (void *)&prog->globals[ofs];
509 def = PRVM_ED_GlobalAtOfs(ofs);
511 sprintf (line,"%i(?)", ofs);
514 s = PRVM_ValueString (def->type, val);
515 sprintf (line,"%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
526 char *PRVM_GlobalStringNoContents (int ofs)
530 static char line[128];
532 def = PRVM_ED_GlobalAtOfs(ofs);
534 sprintf (line,"%i(?)", ofs);
536 sprintf (line,"%i(%s)", ofs, PRVM_GetString(def->s_name));
554 // LordHavoc: optimized this to print out much more quickly (tempstring)
555 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
556 void PRVM_ED_Print (prvm_edict_t *ed)
564 char tempstring[8192], tempstring2[260]; // temporary string buffers
568 Con_Printf ("%s: FREE\n",PRVM_NAME);
573 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
574 for (i=1 ; i<prog->progs->numfielddefs ; i++)
576 d = &prog->fielddefs[i];
577 name = PRVM_GetString(d->s_name);
578 if (name[strlen(name)-2] == '_')
579 continue; // skip _x, _y, _z vars
581 v = (int *)((char *)ed->v + d->ofs*4);
583 // if the value is still all 0, skip the field
584 type = d->type & ~DEF_SAVEGLOBAL;
586 for (j=0 ; j<prvm_type_size[type] ; j++)
589 if (j == prvm_type_size[type])
592 if (strlen(name) > 256)
594 strncpy(tempstring2, name, 256);
595 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
596 tempstring2[259] = 0;
599 strcat(tempstring, name);
600 for (l = strlen(name);l < 14;l++)
601 strcat(tempstring, " ");
602 strcat(tempstring, " ");
604 name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
605 if (strlen(name) > 256)
607 strncpy(tempstring2, name, 256);
608 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
609 tempstring2[259] = 0;
612 strcat(tempstring, name);
613 strcat(tempstring, "\n");
614 if (strlen(tempstring) >= 4096)
616 Con_Printf("%s", tempstring);
621 Con_Printf("%s", tempstring);
631 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
639 FS_Printf (f, "{\n");
643 FS_Printf (f, "}\n");
647 for (i=1 ; i<prog->progs->numfielddefs ; i++)
649 d = &prog->fielddefs[i];
650 name = PRVM_GetString(d->s_name);
651 if (name[strlen(name)-2] == '_')
652 continue; // skip _x, _y, _z vars
654 v = (int *)((char *)ed->v + d->ofs*4);
656 // if the value is still all 0, skip the field
657 type = d->type & ~DEF_SAVEGLOBAL;
658 for (j=0 ; j<prvm_type_size[type] ; j++)
661 if (j == prvm_type_size[type])
664 FS_Printf (f,"\"%s\" ",name);
665 FS_Printf (f,"\"%s\"\n", PRVM_UglyValueString(d->type, (prvm_eval_t *)v));
668 FS_Printf (f, "}\n");
671 void PRVM_ED_PrintNum (int ent)
673 PRVM_ED_Print (PRVM_EDICT_NUM(ent));
678 PRVM_ED_PrintEdicts_f
680 For debugging, prints all the entities in the current server
683 void PRVM_ED_PrintEdicts_f (void)
689 Con_Print("prvm_edicts <program name>\n");
694 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
697 Con_Printf ("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
698 for (i=0 ; i<prog->num_edicts ; i++)
699 PRVM_ED_PrintNum (i);
708 For debugging, prints a single edict
711 void PRVM_ED_PrintEdict_f (void)
717 Con_Print("prvm_edict <program name> <edict number>\n");
722 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
725 i = atoi (Cmd_Argv(2));
726 if (i >= prog->num_edicts)
728 Con_Printf("Bad edict number\n");
732 PRVM_ED_PrintNum (i);
744 // 2 possibilities : 1. just displaying the active edict count
745 // 2. making a function pointer [x]
746 void PRVM_ED_Count_f (void)
754 Con_Print("prvm_count <program name>\n");
759 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
762 if(prog->count_edicts)
763 prog->count_edicts();
767 for (i=0 ; i<prog->num_edicts ; i++)
769 ent = PRVM_EDICT_NUM(i);
775 Con_Printf ("num_edicts:%3i\n", prog->num_edicts);
776 Con_Printf ("active :%3i\n", active);
783 ==============================================================================
787 FIXME: need to tag constants, doesn't really work
788 ==============================================================================
796 void PRVM_ED_WriteGlobals (qfile_t *f)
804 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
806 def = &prog->globaldefs[i];
808 if ( !(def->type & DEF_SAVEGLOBAL) )
810 type &= ~DEF_SAVEGLOBAL;
812 if (type != ev_string && type != ev_float && type != ev_entity)
815 name = PRVM_GetString(def->s_name);
816 FS_Printf (f,"\"%s\" ", name);
817 FS_Printf (f,"\"%s\"\n", PRVM_UglyValueString(type, (prvm_eval_t *)&prog->globals[def->ofs]));
827 void PRVM_ED_ParseGlobals (const char *data)
829 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
835 if (!COM_ParseToken(&data, false))
836 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
837 if (com_token[0] == '}')
840 strcpy (keyname, com_token);
843 if (!COM_ParseToken(&data, false))
844 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
846 if (com_token[0] == '}')
847 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
849 key = PRVM_ED_FindGlobal (keyname);
852 Con_DPrintf ("'%s' is not a global on %s\n", keyname, PRVM_NAME);
856 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
857 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
861 //============================================================================
869 char *PRVM_ED_NewString (const char *string)
874 l = strlen(string) + 1;
875 new = Mem_Alloc(prog->edictstring_mempool, l);
878 for (i=0 ; i< l ; i++)
880 if (string[i] == '\\' && i < l-1)
883 if (string[i] == 'n')
889 *new_p++ = string[i];
900 Can parse either fields or globals
901 returns false if error
904 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
912 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
914 val = (prvm_eval_t *)((int *)pr_globals + key->ofs);
915 switch (key->type & ~DEF_SAVEGLOBAL)
918 val->string = PRVM_SetString(PRVM_ED_NewString(s));
922 while (*s && *s <= ' ')
924 val->_float = atof(s);
928 for (i = 0;i < 3;i++)
930 while (*s && *s <= ' ')
934 val->vector[i] = atof(s);
943 while (*s && *s <= ' ')
946 if (i < 0 || i >= MAX_EDICTS)
947 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i) on %s\n", i, MAX_EDICTS, PRVM_NAME);
948 while (i >= prog->max_edicts)
949 PRVM_MEM_IncreaseEdicts();
950 //SV_IncreaseEdicts();
951 // if SV_IncreaseEdicts was called the base pointer needs to be updated
953 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
954 val->edict = PRVM_EDICT_TO_PROG(EDICT_NUM(i));
958 def = PRVM_ED_FindField(s);
961 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s on %s\n", s, PRVM_NAME);
964 val->_int = PRVM_G_INT(def->ofs);
968 func = PRVM_ED_FindFunction(s);
971 Con_Printf ("PRVM_ED_ParseEpair: Can't find function %s on %s\n", s, PRVM_NAME);
974 val->function = func - prog->functions;
978 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PR_GetString(key->s_name), PRVM_NAME);
988 Parses an edict out of the given string, returning the new position
989 ed should be a properly initialized empty edict.
990 Used for initial level load and for savegames.
993 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1004 if (ent != prog->edicts) // hack
1005 memset (ent->v, 0, prog->progs->entityfields * 4);
1007 // go through all the dictionary pairs
1011 if (!COM_ParseToken(&data, false))
1012 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1013 if (com_token[0] == '}')
1016 // anglehack is to allow QuakeEd to write single scalar angles
1017 // and allow them to be turned into vectors. (FIXME...)
1018 if (!strcmp(com_token, "angle"))
1020 strcpy (com_token, "angles");
1026 // FIXME: change light to _light to get rid of this hack
1027 if (!strcmp(com_token, "light"))
1028 strcpy (com_token, "light_lev"); // hack for single light def
1030 strcpy (keyname, com_token);
1032 // another hack to fix keynames with trailing spaces
1033 n = strlen(keyname);
1034 while (n && keyname[n-1] == ' ')
1041 if (!COM_ParseToken(&data, false))
1042 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1044 if (com_token[0] == '}')
1045 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
1049 // keynames with a leading underscore are used for utility comments,
1050 // and are immediately discarded by quake
1051 if (keyname[0] == '_')
1054 key = PRVM_ED_FindField (keyname);
1057 Con_DPrintf ("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1064 strcpy (temp, com_token);
1065 sprintf (com_token, "0 %s 0", temp);
1068 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1069 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1073 ent->e->free = true;
1081 PRVM_ED_LoadFromFile
1083 The entities are directly placed in the array, rather than allocated with
1084 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1085 number references out of order.
1087 Creates a server's entity / program execution context by
1088 parsing textual entity definitions out of an ent file.
1090 Used for both fresh maps and savegame loads. A fresh map would also need
1091 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1094 void PRVM_ED_LoadFromFile (const char *data)
1097 int parsed, inhibited, spawned, died;
1109 // parse the opening brace
1110 if (!COM_ParseToken(&data, false))
1112 if (com_token[0] != '{')
1113 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1115 // CHANGED: this is not conform to ED_LoadFromFile
1116 if(!prog->num_edicts)
1117 ent = PRVM_EDICT_NUM(0);
1119 ent = PRVM_ED_Alloc();
1121 data = PRVM_ED_ParseEdict (data, ent);
1124 // remove the entity ?
1125 if(prog->load_edict && !prog->load_edict(ent))
1133 // immediately call spawn function, but only if there is a self global
1135 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1137 string_t handle = *(string_t*)&((float*)ent->v)[PRVM_ED_FindFieldOffset("classname")];
1140 Con_Printf ("No classname for:\n");
1141 PRVM_ED_Print (ent);
1146 // look for the spawn function
1147 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1151 if (developer.integer) // don't confuse non-developers with errors
1153 Con_Printf ("No spawn function for:\n");
1154 PRVM_ED_Print (ent);
1161 PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1162 PRVM_ExecuteProgram (func - prog->functions, "");
1170 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);
1175 typedef struct dpfield_s
1182 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1184 dpfield_t dpfields[] =
1195 void PRVM_ResetProg()
1197 mempool_t *t1, *t2, *t3;
1199 t1 = prog->progs_mempool;
1200 t2 = prog->edictstring_mempool;
1201 t3 = prog->edicts_mempool;
1203 Mem_EmptyPool(prog->progs_mempool);
1204 Mem_EmptyPool(prog->edictstring_mempool);
1205 Mem_EmptyPool(prog->edicts_mempool);
1207 memset(prog,0,sizeof(prvm_prog_t));
1209 prog->time = &prog->_time;
1211 prog->progs_mempool = t1;
1212 prog->edictstring_mempool = t2;
1213 prog->edicts_mempool = t3;
1215 PRVM_GCALL(reset_cmd)();
1223 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func)
1227 ddef_t *infielddefs;
1229 dfunction_t *dfunctions;
1231 Mem_EmptyPool(prog->progs_mempool);
1232 Mem_EmptyPool(prog->edictstring_mempool);
1234 temp = FS_LoadFile (filename, false);
1236 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1238 prog->progs = (dprograms_t *)Mem_Alloc(prog->progs_mempool, fs_filesize);
1240 memcpy(prog->progs, temp, fs_filesize);
1243 Con_DPrintf ("%s programs occupy %iK.\n", PRVM_NAME, fs_filesize/1024);
1245 pr_crc = CRC_Block((qbyte *)prog->progs, fs_filesize);
1247 // byte swap the header
1248 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1249 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1251 if (prog->progs->version != PROG_VERSION)
1252 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1253 if (prog->progs->crc != prog->crc)
1254 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1256 //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1257 dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
1258 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1259 prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
1261 // we need to expand the fielddefs list to include all the engine fields,
1262 // so allocate a new place for it
1263 infielddefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_fielddefs);
1265 prog->fielddefs = Mem_Alloc(prog->progs_mempool, prog->progs->numfielddefs * sizeof(ddef_t));
1267 prog->statements = (dstatement_t *)((qbyte *)prog->progs + prog->progs->ofs_statements);
1269 // moved edict_size calculation down below field adding code
1271 //pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1272 prog->globals = (float *)((qbyte *)prog->progs + prog->progs->ofs_globals);
1274 // byte swap the lumps
1275 for (i=0 ; i<prog->progs->numstatements ; i++)
1277 prog->statements[i].op = LittleShort(prog->statements[i].op);
1278 prog->statements[i].a = LittleShort(prog->statements[i].a);
1279 prog->statements[i].b = LittleShort(prog->statements[i].b);
1280 prog->statements[i].c = LittleShort(prog->statements[i].c);
1283 prog->functions = Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1284 for (i = 0;i < prog->progs->numfunctions;i++)
1286 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1287 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1288 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1289 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1290 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1291 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1292 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1295 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1297 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1298 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1299 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1302 // copy the progs fields to the new fields list
1303 for (i = 0;i < prog->progs->numfielddefs;i++)
1305 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1306 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1307 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1308 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1309 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1312 /* // append the darkplaces fields
1313 for (i = 0;i < (int) DPFIELDS;i++)
1315 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1316 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1317 pr_fielddefs[progs->numfielddefs].s_name = PR_SetString(dpfields[i].string);
1318 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1319 progs->entityfields += 3;
1321 progs->entityfields++;
1322 progs->numfielddefs++;
1325 // check required functions
1326 for(i=0 ; i < numrequiredfunc ; i++)
1327 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1328 PRVM_ERROR("%s: %s not found in %s\n",PRVM_NAME, required_func[i], filename);
1330 for (i=0 ; i<prog->progs->numglobals ; i++)
1331 ((int *)prog->globals)[i] = LittleLong (((int *)prog->globals)[i]);
1333 // moved edict_size calculation down here, below field adding code
1334 // LordHavoc: this no longer includes the edict_t header
1335 prog->edict_size = prog->progs->entityfields * 4;
1336 prog->edictareasize = prog->edict_size * MAX_EDICTS;
1338 // LordHavoc: bounds check anything static
1339 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1345 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1346 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s\n", i, PRVM_NAME);
1349 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1350 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s\n", i, PRVM_NAME);
1352 // global global global
1387 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1388 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n", i);
1390 // global none global
1396 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1397 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1413 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1414 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n in %s", i, PRVM_NAME);
1428 if ((unsigned short) st->a >= prog->progs->numglobals)
1429 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1432 PRVM_ERROR("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1439 prog->loaded = TRUE;
1441 // set flags & ddef_ts in prog
1445 prog->self = PRVM_ED_FindGlobal("self");
1447 if(PRVM_ED_FindGlobal("time"))
1448 prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs);
1450 if(PRVM_ED_FindField ("chain"))
1451 prog->flag |= PRVM_FE_CHAIN;
1453 if(PRVM_ED_FindField ("classname"))
1454 prog->flag |= PRVM_FE_CLASSNAME;
1456 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1457 && prog->flag && prog->self)
1458 prog->flag |= PRVM_OP_STATE;
1460 PRVM_GCALL(reset_cmd)();
1467 void PRVM_Fields_f (void)
1469 int i, j, ednum, used, usedamount;
1471 char tempstring[5000], tempstring2[260], *name;
1480 Con_Printf("no progs loaded\n");
1487 Con_Print("prvm_fields <program name>\n");
1492 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1495 counts = Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1496 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1498 ed = PRVM_EDICT_NUM(ednum);
1501 for (i = 1;i < prog->progs->numfielddefs;i++)
1503 d = &prog->fielddefs[i];
1504 name = PRVM_GetString(d->s_name);
1505 if (name[strlen(name)-2] == '_')
1506 continue; // skip _x, _y, _z vars
1507 v = (int *)((char *)ed->v + d->ofs*4);
1508 // if the value is still all 0, skip the field
1509 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1522 for (i = 0;i < prog->progs->numfielddefs;i++)
1524 d = &prog->fielddefs[i];
1525 name = PRVM_GetString(d->s_name);
1526 if (name[strlen(name)-2] == '_')
1527 continue; // skip _x, _y, _z vars
1528 switch(d->type & ~DEF_SAVEGLOBAL)
1531 strcat(tempstring, "string ");
1534 strcat(tempstring, "entity ");
1537 strcat(tempstring, "function ");
1540 strcat(tempstring, "field ");
1543 strcat(tempstring, "void ");
1546 strcat(tempstring, "float ");
1549 strcat(tempstring, "vector ");
1552 strcat(tempstring, "pointer ");
1555 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1556 strcat(tempstring, tempstring2);
1559 if (strlen(name) > 256)
1561 strncpy(tempstring2, name, 256);
1562 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1563 tempstring2[259] = 0;
1566 strcat(tempstring, name);
1567 for (j = strlen(name);j < 25;j++)
1568 strcat(tempstring, " ");
1569 sprintf(tempstring2, "%5d", counts[i]);
1570 strcat(tempstring, tempstring2);
1571 strcat(tempstring, "\n");
1572 if (strlen(tempstring) >= 4096)
1574 Con_Printf("%s", tempstring);
1580 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1584 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);
1589 void PRVM_Globals_f (void)
1595 Con_Printf("no progs loaded\n");
1598 if(Cmd_Argc () != 2)
1600 Con_Print ("prvm_globals <program name>\n");
1605 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1608 Con_Printf("%s :", PRVM_NAME);
1610 for (i = 0;i < prog->progs->numglobaldefs;i++)
1611 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1612 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1622 void PRVM_Init (void)
1624 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f);
1625 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f);
1626 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f);
1627 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
1628 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
1629 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
1630 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1631 Cvar_RegisterVariable (&prvm_boundscheck);
1632 Cvar_RegisterVariable (&prvm_traceqc);
1642 void PRVM_InitProg(int prognr)
1644 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1645 Sys_Error("PRVM_InitProg: Invalid program number %i\n",prognr);
1647 prog = &prog_list[prognr];
1649 memset(prog, 0, sizeof(prvm_prog_t));
1651 prog->time = &prog->_time;
1653 PRVM_GCALL(init_cmd)();
1656 int PRVM_GetProgNr()
1658 return prog - prog_list;
1661 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1662 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1664 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1668 void PRVM_ProcessError(void)
1671 PRVM_GCALL(error_cmd)();
1675 int NUM_FOR_EDICT_ERROR(edict_t *e)
1677 Host_Error ("NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, sv.edicts, e - sv.edicts);
1681 int NUM_FOR_EDICT(edict_t *e)
1685 if ((unsigned int)n >= MAX_EDICTS)
1686 Host_Error ("NUM_FOR_EDICT: bad pointer");
1690 //int NoCrash_NUM_FOR_EDICT(edict_t *e)
1692 // return e - sv.edicts;
1695 //#define EDICT_TO_PROG(e) ((qbyte *)(((edict_t *)e)->v) - (qbyte *)(sv.edictsfields))
1696 //#define PROG_TO_EDICT(e) (sv.edicts + ((e) / (progs->entityfields * 4)))
1697 int EDICT_TO_PROG(edict_t *e)
1701 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1702 Host_Error("EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, sv.edicts);
1703 return n;// EXPERIMENTAL
1704 //return (qbyte *)e->v - (qbyte *)sv.edictsfields;
1706 edict_t *PROG_TO_EDICT(int n)
1708 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1709 Host_Error("PROG_TO_EDICT: invalid edict number %i\n", n);
1710 return sv.edicts + n; // EXPERIMENTAL
1711 //return sv.edicts + ((n) / (progs->entityfields * 4));