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 // dont delete the null entity (world)
259 if(PRVM_NUM_FOR_EDICT(ed) == 0)
262 PRVM_GCALL(free_edict)(ed);
265 ed->e->freetime = *prog->time;
268 //===========================================================================
275 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
280 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
282 def = &prog->globaldefs[i];
294 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
299 for (i=0 ; i<prog->progs->numfielddefs ; i++)
301 def = &prog->fielddefs[i];
313 ddef_t *PRVM_ED_FindField (const char *name)
318 for (i=0 ; i<prog->progs->numfielddefs ; i++)
320 def = &prog->fielddefs[i];
321 if (!strcmp(PRVM_GetString(def->s_name), name))
332 ddef_t *PRVM_ED_FindGlobal (const char *name)
337 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
339 def = &prog->globaldefs[i];
340 if (!strcmp(PRVM_GetString(def->s_name), name))
352 mfunction_t *PRVM_ED_FindFunction (const char *name)
357 for (i=0 ; i<prog->progs->numfunctions ; i++)
359 func = &prog->functions[i];
360 if (!strcmp(PRVM_GetString(func->s_name), name))
371 Returns a string describing *data in a type specific manner
374 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
376 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
381 type &= ~DEF_SAVEGLOBAL;
386 strncpy(line, PRVM_GetString(val->string), sizeof(line));
390 if (n < 0 || n >= MAX_EDICTS)
391 sprintf (line, "entity %i (invalid!)", n);
393 sprintf (line, "entity %i", n);
396 f = prog->functions + val->function;
397 sprintf (line, "%s()", PRVM_GetString(f->s_name));
400 def = PRVM_ED_FieldAtOfs ( val->_int );
401 sprintf (line, ".%s", PRVM_GetString(def->s_name));
404 sprintf (line, "void");
407 // LordHavoc: changed from %5.1f to %10.4f
408 sprintf (line, "%10.4f", val->_float);
411 // LordHavoc: changed from %5.1f to %10.4f
412 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
415 sprintf (line, "pointer");
418 sprintf (line, "bad type %i", type);
429 Returns a string describing *data in a type specific manner
430 Easier to parse than PR_ValueString
433 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
435 static char line[4096];
441 type &= ~DEF_SAVEGLOBAL;
446 // Parse the string a bit to turn special characters
447 // (like newline, specifically) into escape codes,
448 // this fixes saving games from various mods
449 s = PRVM_GetString (val->string);
450 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
469 snprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
472 f = pr_functions + val->function;
473 strncpy(line, PRVM_GetString(f->s_name), sizeof(line));
476 def = PRVM_ED_FieldAtOfs ( val->_int );
477 snprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
480 snprintf (line, sizeof (line), "void");
483 snprintf (line, sizeof (line), "%f", val->_float);
486 snprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
489 snprintf (line, sizeof (line), "bad type %i", type);
500 Returns a string with a description and the contents of a global,
501 padded to 20 field width
504 char *PRVM_GlobalString (int ofs)
510 static char line[128];
512 val = (void *)&prog->globals[ofs];
513 def = PRVM_ED_GlobalAtOfs(ofs);
515 sprintf (line,"%i(?)", ofs);
518 s = PRVM_ValueString (def->type, val);
519 sprintf (line,"%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
530 char *PRVM_GlobalStringNoContents (int ofs)
534 static char line[128];
536 def = PRVM_ED_GlobalAtOfs(ofs);
538 sprintf (line,"%i(?)", ofs);
540 sprintf (line,"%i(%s)", ofs, PRVM_GetString(def->s_name));
558 // LordHavoc: optimized this to print out much more quickly (tempstring)
559 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
560 void PRVM_ED_Print(prvm_edict_t *ed)
568 char tempstring[8192], tempstring2[260]; // temporary string buffers
572 Con_Printf("%s: FREE\n",PRVM_NAME);
577 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
578 for (i=1 ; i<prog->progs->numfielddefs ; i++)
580 d = &prog->fielddefs[i];
581 name = PRVM_GetString(d->s_name);
582 if (name[strlen(name)-2] == '_')
583 continue; // skip _x, _y, _z vars
585 v = (int *)((char *)ed->v + d->ofs*4);
587 // if the value is still all 0, skip the field
588 type = d->type & ~DEF_SAVEGLOBAL;
590 for (j=0 ; j<prvm_type_size[type] ; j++)
593 if (j == prvm_type_size[type])
596 if (strlen(name) > 256)
598 strncpy(tempstring2, name, 256);
599 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
600 tempstring2[259] = 0;
603 strcat(tempstring, name);
604 for (l = strlen(name);l < 14;l++)
605 strcat(tempstring, " ");
606 strcat(tempstring, " ");
608 name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
609 if (strlen(name) > 256)
611 strncpy(tempstring2, name, 256);
612 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
613 tempstring2[259] = 0;
616 strcat(tempstring, name);
617 strcat(tempstring, "\n");
618 if (strlen(tempstring) >= 4096)
620 Con_Print(tempstring);
625 Con_Print(tempstring);
635 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
651 for (i=1 ; i<prog->progs->numfielddefs ; i++)
653 d = &prog->fielddefs[i];
654 name = PRVM_GetString(d->s_name);
655 if (name[strlen(name)-2] == '_')
656 continue; // skip _x, _y, _z vars
658 v = (int *)((char *)ed->v + d->ofs*4);
660 // if the value is still all 0, skip the field
661 type = d->type & ~DEF_SAVEGLOBAL;
662 for (j=0 ; j<prvm_type_size[type] ; j++)
665 if (j == prvm_type_size[type])
668 FS_Printf(f,"\"%s\" ",name);
669 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(d->type, (prvm_eval_t *)v));
675 void PRVM_ED_PrintNum (int ent)
677 PRVM_ED_Print(PRVM_EDICT_NUM(ent));
682 PRVM_ED_PrintEdicts_f
684 For debugging, prints all the entities in the current server
687 void PRVM_ED_PrintEdicts_f (void)
693 Con_Print("prvm_edicts <program name>\n");
698 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
701 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
702 for (i=0 ; i<prog->num_edicts ; i++)
703 PRVM_ED_PrintNum (i);
712 For debugging, prints a single edict
715 void PRVM_ED_PrintEdict_f (void)
721 Con_Print("prvm_edict <program name> <edict number>\n");
726 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
729 i = atoi (Cmd_Argv(2));
730 if (i >= prog->num_edicts)
732 Con_Print("Bad edict number\n");
736 PRVM_ED_PrintNum (i);
748 // 2 possibilities : 1. just displaying the active edict count
749 // 2. making a function pointer [x]
750 void PRVM_ED_Count_f (void)
758 Con_Print("prvm_count <program name>\n");
763 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
766 if(prog->count_edicts)
767 prog->count_edicts();
771 for (i=0 ; i<prog->num_edicts ; i++)
773 ent = PRVM_EDICT_NUM(i);
779 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
780 Con_Printf("active :%3i\n", active);
787 ==============================================================================
791 FIXME: need to tag constants, doesn't really work
792 ==============================================================================
800 void PRVM_ED_WriteGlobals (qfile_t *f)
808 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
810 def = &prog->globaldefs[i];
812 if ( !(def->type & DEF_SAVEGLOBAL) )
814 type &= ~DEF_SAVEGLOBAL;
816 if (type != ev_string && type != ev_float && type != ev_entity)
819 name = PRVM_GetString(def->s_name);
820 FS_Printf(f,"\"%s\" ", name);
821 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(type, (prvm_eval_t *)&prog->globals[def->ofs]));
831 void PRVM_ED_ParseGlobals (const char *data)
833 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
839 if (!COM_ParseToken(&data, false))
840 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
841 if (com_token[0] == '}')
844 strcpy (keyname, com_token);
847 if (!COM_ParseToken(&data, false))
848 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
850 if (com_token[0] == '}')
851 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
853 key = PRVM_ED_FindGlobal (keyname);
856 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
860 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
861 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
865 //============================================================================
873 char *PRVM_ED_NewString (const char *string)
878 l = strlen(string) + 1;
879 new = Mem_Alloc(prog->edictstring_mempool, l);
882 for (i=0 ; i< l ; i++)
884 if (string[i] == '\\' && i < l-1)
887 if (string[i] == 'n')
893 *new_p++ = string[i];
903 Can parse either fields or globals
904 returns false if error
907 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
915 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
917 val = (prvm_eval_t *)((int *)pr_globals + key->ofs);
918 switch (key->type & ~DEF_SAVEGLOBAL)
921 val->string = PRVM_SetString(PRVM_ED_NewString(s));
925 while (*s && *s <= ' ')
927 val->_float = atof(s);
931 for (i = 0;i < 3;i++)
933 while (*s && *s <= ' ')
937 val->vector[i] = atof(s);
946 while (*s && *s <= ' ')
949 if (i < 0 || i >= MAX_EDICTS)
950 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i) on %s\n", i, MAX_EDICTS, PRVM_NAME);
951 while (i >= prog->max_edicts)
952 PRVM_MEM_IncreaseEdicts();
953 //SV_IncreaseEdicts();
954 // if SV_IncreaseEdicts was called the base pointer needs to be updated
956 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
957 val->edict = PRVM_EDICT_TO_PROG(EDICT_NUM(i));
961 def = PRVM_ED_FindField(s);
964 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
967 val->_int = PRVM_G_INT(def->ofs);
971 func = PRVM_ED_FindFunction(s);
974 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
977 val->function = func - prog->functions;
981 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PR_GetString(key->s_name), PRVM_NAME);
991 Console command to set a field of a specified edict
994 void PRVM_ED_EdictSet_f(void)
1001 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1006 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1008 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1012 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1014 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1016 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1020 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1026 ====================
1029 Parses an edict out of the given string, returning the new position
1030 ed should be a properly initialized empty edict.
1031 Used for initial level load and for savegames.
1032 ====================
1034 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1045 if (ent != prog->edicts) // hack
1046 memset (ent->v, 0, prog->progs->entityfields * 4);
1048 // go through all the dictionary pairs
1052 if (!COM_ParseToken(&data, false))
1053 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1054 if (com_token[0] == '}')
1057 // anglehack is to allow QuakeEd to write single scalar angles
1058 // and allow them to be turned into vectors. (FIXME...)
1059 if (!strcmp(com_token, "angle"))
1061 strcpy (com_token, "angles");
1067 // FIXME: change light to _light to get rid of this hack
1068 if (!strcmp(com_token, "light"))
1069 strcpy (com_token, "light_lev"); // hack for single light def
1071 strcpy (keyname, com_token);
1073 // another hack to fix keynames with trailing spaces
1074 n = strlen(keyname);
1075 while (n && keyname[n-1] == ' ')
1082 if (!COM_ParseToken(&data, false))
1083 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1085 if (com_token[0] == '}')
1086 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
1090 // keynames with a leading underscore are used for utility comments,
1091 // and are immediately discarded by quake
1092 if (keyname[0] == '_')
1095 key = PRVM_ED_FindField (keyname);
1098 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1105 strcpy (temp, com_token);
1106 sprintf (com_token, "0 %s 0", temp);
1109 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1110 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1114 ent->e->free = true;
1122 PRVM_ED_LoadFromFile
1124 The entities are directly placed in the array, rather than allocated with
1125 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1126 number references out of order.
1128 Creates a server's entity / program execution context by
1129 parsing textual entity definitions out of an ent file.
1131 Used for both fresh maps and savegame loads. A fresh map would also need
1132 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1135 void PRVM_ED_LoadFromFile (const char *data)
1138 int parsed, inhibited, spawned, died;
1150 // parse the opening brace
1151 if (!COM_ParseToken(&data, false))
1153 if (com_token[0] != '{')
1154 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1156 // CHANGED: this is not conform to ED_LoadFromFile
1157 if(!prog->num_edicts)
1158 ent = PRVM_EDICT_NUM(0);
1160 ent = PRVM_ED_Alloc();
1162 data = PRVM_ED_ParseEdict (data, ent);
1165 // remove the entity ?
1166 if(prog->load_edict && !prog->load_edict(ent))
1174 // immediately call spawn function, but only if there is a self global and a classname
1176 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1178 string_t handle = *(string_t*)&((float*)ent->v)[PRVM_ED_FindFieldOffset("classname")];
1181 Con_Print("No classname for:\n");
1187 // look for the spawn function
1188 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1192 if (developer.integer) // don't confuse non-developers with errors
1194 Con_Print("No spawn function for:\n");
1202 PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1203 PRVM_ExecuteProgram (func - prog->functions, "");
1211 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);
1216 typedef struct dpfield_s
1223 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1225 dpfield_t dpfields[] =
1236 void PRVM_ResetProg()
1238 /*mempool_t *t1, *t2, *t3;
1240 t1 = prog->progs_mempool;
1241 t2 = prog->edictstring_mempool;
1242 t3 = prog->edicts_mempool;
1244 Mem_EmptyPool(prog->progs_mempool);
1245 Mem_EmptyPool(prog->edictstring_mempool);
1246 Mem_EmptyPool(prog->edicts_mempool);*/
1247 Mem_FreePool(&prog->progs_mempool);
1248 Mem_FreePool(&prog->edictstring_mempool);
1249 Mem_FreePool(&prog->edicts_mempool);
1251 memset(prog,0,sizeof(prvm_prog_t));
1253 /*prog->time = &prog->_time;
1255 prog->progs_mempool = t1;
1256 prog->edictstring_mempool = t2;
1257 prog->edicts_mempool = t3;*/
1259 PRVM_GCALL(reset_cmd)();
1267 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func)
1271 ddef_t *infielddefs;
1272 dfunction_t *dfunctions;
1274 Mem_EmptyPool(prog->progs_mempool);
1275 Mem_EmptyPool(prog->edictstring_mempool);
1277 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false);
1278 if (prog->progs == NULL)
1279 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1281 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, fs_filesize/1024);
1283 pr_crc = CRC_Block((qbyte *)prog->progs, fs_filesize);
1285 // byte swap the header
1286 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1287 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1289 if (prog->progs->version != PROG_VERSION)
1290 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1291 if (prog->progs->crc != prog->crc)
1292 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1294 //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1295 dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
1296 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1297 prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
1299 // we need to expand the fielddefs list to include all the engine fields,
1300 // so allocate a new place for it
1301 infielddefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_fielddefs);
1303 prog->fielddefs = Mem_Alloc(prog->progs_mempool, prog->progs->numfielddefs * sizeof(ddef_t));
1305 prog->statements = (dstatement_t *)((qbyte *)prog->progs + prog->progs->ofs_statements);
1307 // moved edict_size calculation down below field adding code
1309 //pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1310 prog->globals = (float *)((qbyte *)prog->progs + prog->progs->ofs_globals);
1312 // byte swap the lumps
1313 for (i=0 ; i<prog->progs->numstatements ; i++)
1315 prog->statements[i].op = LittleShort(prog->statements[i].op);
1316 prog->statements[i].a = LittleShort(prog->statements[i].a);
1317 prog->statements[i].b = LittleShort(prog->statements[i].b);
1318 prog->statements[i].c = LittleShort(prog->statements[i].c);
1321 prog->functions = Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1322 for (i = 0;i < prog->progs->numfunctions;i++)
1324 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1325 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1326 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1327 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1328 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1329 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1330 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1333 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1335 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1336 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1337 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1340 // copy the progs fields to the new fields list
1341 for (i = 0;i < prog->progs->numfielddefs;i++)
1343 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1344 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1345 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1346 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1347 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1350 /* // append the darkplaces fields
1351 for (i = 0;i < (int) DPFIELDS;i++)
1353 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1354 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1355 pr_fielddefs[progs->numfielddefs].s_name = PR_SetString(dpfields[i].string);
1356 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1357 progs->entityfields += 3;
1359 progs->entityfields++;
1360 progs->numfielddefs++;
1363 // check required functions
1364 for(i=0 ; i < numrequiredfunc ; i++)
1365 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1366 PRVM_ERROR("%s: %s not found in %s\n",PRVM_NAME, required_func[i], filename);
1368 for (i=0 ; i<prog->progs->numglobals ; i++)
1369 ((int *)prog->globals)[i] = LittleLong (((int *)prog->globals)[i]);
1371 // moved edict_size calculation down here, below field adding code
1372 // LordHavoc: this no longer includes the edict_t header
1373 prog->edict_size = prog->progs->entityfields * 4;
1374 prog->edictareasize = prog->edict_size * MAX_EDICTS;
1376 // LordHavoc: bounds check anything static
1377 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1383 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1384 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s\n", i, PRVM_NAME);
1387 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1388 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s\n", i, PRVM_NAME);
1390 // global global global
1425 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1426 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n", i);
1428 // global none global
1434 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1435 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1451 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1452 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n in %s", i, PRVM_NAME);
1466 if ((unsigned short) st->a >= prog->progs->numglobals)
1467 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1470 PRVM_ERROR("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1477 prog->loaded = TRUE;
1479 // set flags & ddef_ts in prog
1483 prog->self = PRVM_ED_FindGlobal("self");
1485 if(PRVM_ED_FindGlobal("time"))
1486 prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs);
1488 if(PRVM_ED_FindField ("chain"))
1489 prog->flag |= PRVM_FE_CHAIN;
1491 if(PRVM_ED_FindField ("classname"))
1492 prog->flag |= PRVM_FE_CLASSNAME;
1494 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1495 && prog->flag && prog->self)
1496 prog->flag |= PRVM_OP_STATE;
1498 PRVM_GCALL(reset_cmd)();
1499 PRVM_GCALL(init_cmd)();
1506 void PRVM_Fields_f (void)
1508 int i, j, ednum, used, usedamount;
1510 char tempstring[5000], tempstring2[260], *name;
1519 Con_Print("no progs loaded\n");
1526 Con_Print("prvm_fields <program name>\n");
1531 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1534 counts = Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1535 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1537 ed = PRVM_EDICT_NUM(ednum);
1540 for (i = 1;i < prog->progs->numfielddefs;i++)
1542 d = &prog->fielddefs[i];
1543 name = PRVM_GetString(d->s_name);
1544 if (name[strlen(name)-2] == '_')
1545 continue; // skip _x, _y, _z vars
1546 v = (int *)((char *)ed->v + d->ofs*4);
1547 // if the value is still all 0, skip the field
1548 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1561 for (i = 0;i < prog->progs->numfielddefs;i++)
1563 d = &prog->fielddefs[i];
1564 name = PRVM_GetString(d->s_name);
1565 if (name[strlen(name)-2] == '_')
1566 continue; // skip _x, _y, _z vars
1567 switch(d->type & ~DEF_SAVEGLOBAL)
1570 strcat(tempstring, "string ");
1573 strcat(tempstring, "entity ");
1576 strcat(tempstring, "function ");
1579 strcat(tempstring, "field ");
1582 strcat(tempstring, "void ");
1585 strcat(tempstring, "float ");
1588 strcat(tempstring, "vector ");
1591 strcat(tempstring, "pointer ");
1594 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1595 strcat(tempstring, tempstring2);
1598 if (strlen(name) > 256)
1600 strncpy(tempstring2, name, 256);
1601 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1602 tempstring2[259] = 0;
1605 strcat(tempstring, name);
1606 for (j = strlen(name);j < 25;j++)
1607 strcat(tempstring, " ");
1608 sprintf(tempstring2, "%5d", counts[i]);
1609 strcat(tempstring, tempstring2);
1610 strcat(tempstring, "\n");
1611 if (strlen(tempstring) >= 4096)
1613 Con_Print(tempstring);
1619 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1623 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);
1628 void PRVM_Globals_f (void)
1634 Con_Print("no progs loaded\n");
1637 if(Cmd_Argc () != 2)
1639 Con_Print("prvm_globals <program name>\n");
1644 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1647 Con_Printf("%s :", PRVM_NAME);
1649 for (i = 0;i < prog->progs->numglobaldefs;i++)
1650 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1651 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1661 void PRVM_Init (void)
1663 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f);
1664 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f);
1665 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f);
1666 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
1667 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
1668 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
1669 Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f);
1670 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1671 Cvar_RegisterVariable (&prvm_boundscheck);
1672 Cvar_RegisterVariable (&prvm_traceqc);
1682 void PRVM_InitProg(int prognr)
1684 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1685 Sys_Error("PRVM_InitProg: Invalid program number %i\n",prognr);
1687 prog = &prog_list[prognr];
1692 memset(prog, 0, sizeof(prvm_prog_t));
1694 prog->time = &prog->_time;
1697 int PRVM_GetProgNr()
1699 return prog - prog_list;
1702 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1703 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1705 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1709 void PRVM_ProcessError(void)
1712 PRVM_GCALL(error_cmd)();
1716 int NUM_FOR_EDICT_ERROR(edict_t *e)
1718 Host_Error ("NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, sv.edicts, e - sv.edicts);
1722 int NUM_FOR_EDICT(edict_t *e)
1726 if ((unsigned int)n >= MAX_EDICTS)
1727 Host_Error ("NUM_FOR_EDICT: bad pointer");
1731 //int NoCrash_NUM_FOR_EDICT(edict_t *e)
1733 // return e - sv.edicts;
1736 //#define EDICT_TO_PROG(e) ((qbyte *)(((edict_t *)e)->v) - (qbyte *)(sv.edictsfields))
1737 //#define PROG_TO_EDICT(e) (sv.edicts + ((e) / (progs->entityfields * 4)))
1738 int EDICT_TO_PROG(edict_t *e)
1742 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1743 Host_Error("EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, sv.edicts);
1744 return n;// EXPERIMENTAL
1745 //return (qbyte *)e->v - (qbyte *)sv.edictsfields;
1747 edict_t *PROG_TO_EDICT(int n)
1749 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1750 Host_Error("PROG_TO_EDICT: invalid edict number %i\n", n);
1751 return sv.edicts + n; // EXPERIMENTAL
1752 //return sv.edicts + ((n) / (progs->entityfields * 4));