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 // check bound of max_edicts
54 prog->max_edicts = min(prog->max_edicts,prog->limit_edicts);
56 // edictprivate_size has to be min as big prvm_edict_private_t
57 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
60 prog->edicts = Mem_Alloc(prog->edicts_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
62 // alloc edict private space
63 prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
66 prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
69 for(i = 0; i < prog->max_edicts; i++)
71 prog->edicts[i].e = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
72 prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
78 PRVM_MEM_IncreaseEdicts
81 void PRVM_MEM_IncreaseEdicts()
84 int oldmaxedicts = prog->max_edicts;
85 void *oldedictsfields = prog->edictsfields;
86 void *oldedictprivate = prog->edictprivate;
88 if(prog->max_edicts >= prog->limit_edicts)
91 PRVM_GCALL(begin_increase_edicts)();
94 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
96 prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
97 prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
99 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
100 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
102 //set e and v pointers
103 for(i = 0; i < prog->max_edicts; i++)
105 prog->edicts[i].e = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
106 prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
109 PRVM_GCALL(end_increase_edicts)();
111 Mem_Free(oldedictsfields);
112 Mem_Free(oldedictprivate);
115 //============================================================================
118 int PRVM_ED_FindFieldOffset(const char *field)
121 d = PRVM_ED_FindField(field);
127 qboolean PRVM_ProgLoaded(int prognr)
129 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
132 return (prog_list[prognr].loaded ? TRUE : FALSE);
137 PRVM_SetProgFromString
140 // perhaps add a return value when the str doesnt exist
141 qboolean PRVM_SetProgFromString(const char *str)
144 for(; i < PRVM_MAXPROGS ; i++)
145 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
147 if(prog_list[i].loaded)
149 prog = &prog_list[i];
154 Con_Printf("%s not loaded !\n",PRVM_NAME);
159 Con_Printf("Invalid program name %s !\n", str);
168 void PRVM_SetProg(int prognr)
170 if(prognr && prognr < PRVM_MAXPROGS)
172 if(prog_list[prognr].loaded)
173 prog = &prog_list[prognr];
175 PRVM_ERROR("%i(%s) not loaded !\n", prognr, PRVM_NAME);
178 PRVM_ERROR("Invalid program number %i\n", prognr);
185 Sets everything to NULL
188 void PRVM_ED_ClearEdict (prvm_edict_t *e)
191 memset (e->v, 0, prog->progs->entityfields * 4);
193 // LordHavoc: for consistency set these here
194 num = PRVM_NUM_FOR_EDICT(e) - 1;
196 // AK: Let the init_edict function determine if something needs to be initialized
197 PRVM_GCALL(init_edict)(num);
204 Either finds a free edict, or allocates a new one.
205 Try to avoid reusing an entity that was recently freed, because it
206 can cause the client to think the entity morphed into something else
207 instead of being removed and recreated, which can cause interpolated
208 angles and bad trails.
211 prvm_edict_t *PRVM_ED_Alloc (void)
216 // the client qc dont need maxclients
217 // thus it doesnt need to use svs.maxclients
218 // AK: changed i=svs.maxclients+1
219 // AK: changed so the edict 0 wont spawned -> used as reserved/world entity
220 // although the menu/client has no world
221 for (i = 1;i < prog->num_edicts;i++)
223 e = PRVM_EDICT_NUM(i);
224 // the first couple seconds of server time can involve a lot of
225 // freeing and allocating, so relax the replacement policy
226 if (e->e->free && ( e->e->freetime < 2 || prog->time - e->e->freetime > 0.5 ) )
228 PRVM_ED_ClearEdict (e);
234 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
237 if (prog->num_edicts >= prog->max_edicts)
238 PRVM_MEM_IncreaseEdicts();
240 e = PRVM_EDICT_NUM(i);
241 PRVM_ED_ClearEdict (e);
250 Marks the edict as free
251 FIXME: walk all entities and NULL out references to this entity
254 void PRVM_ED_Free (prvm_edict_t *ed)
256 PRVM_GCALL(free_edict)(ed);
259 ed->e->freetime = prog->time;
262 //===========================================================================
269 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
274 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
276 def = &prog->globaldefs[i];
288 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
293 for (i=0 ; i<prog->progs->numfielddefs ; i++)
295 def = &prog->fielddefs[i];
307 ddef_t *PRVM_ED_FindField (const char *name)
312 for (i=0 ; i<prog->progs->numfielddefs ; i++)
314 def = &prog->fielddefs[i];
315 if (!strcmp(PRVM_GetString(def->s_name), name))
326 ddef_t *PRVM_ED_FindGlobal (const char *name)
331 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
333 def = &prog->globaldefs[i];
334 if (!strcmp(PRVM_GetString(def->s_name), name))
346 mfunction_t *PRVM_ED_FindFunction (const char *name)
351 for (i=0 ; i<prog->progs->numfunctions ; i++)
353 func = &prog->functions[i];
354 if (!strcmp(PRVM_GetString(func->s_name), name))
365 Returns a string describing *data in a type specific manner
368 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
370 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
375 type &= ~DEF_SAVEGLOBAL;
380 sprintf (line, "%s", PRVM_GetString(val->string));
384 if (n < 0 || n >= MAX_EDICTS)
385 sprintf (line, "entity %i (invalid!)", n);
387 sprintf (line, "entity %i", n);
390 f = prog->functions + val->function;
391 sprintf (line, "%s()", PRVM_GetString(f->s_name));
394 def = PRVM_ED_FieldAtOfs ( val->_int );
395 sprintf (line, ".%s", PRVM_GetString(def->s_name));
398 sprintf (line, "void");
401 // LordHavoc: changed from %5.1f to %10.4f
402 sprintf (line, "%10.4f", val->_float);
405 // LordHavoc: changed from %5.1f to %10.4f
406 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
409 sprintf (line, "pointer");
412 sprintf (line, "bad type %i", type);
423 Returns a string describing *data in a type specific manner
424 Easier to parse than PR_ValueString
427 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
429 static char line[4096];
435 type &= ~DEF_SAVEGLOBAL;
440 // Parse the string a bit to turn special characters
441 // (like newline, specifically) into escape codes,
442 // this fixes saving games from various mods
443 s = PRVM_GetString (val->string);
444 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
463 snprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
466 f = pr_functions + val->function;
467 snprintf (line, sizeof (line), "%s", PRVM_GetString(f->s_name));
470 def = PRVM_ED_FieldAtOfs ( val->_int );
471 snprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
474 snprintf (line, sizeof (line), "void");
477 snprintf (line, sizeof (line), "%f", val->_float);
480 snprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
483 snprintf (line, sizeof (line), "bad type %i", type);
494 Returns a string with a description and the contents of a global,
495 padded to 20 field width
498 char *PRVM_GlobalString (int ofs)
504 static char line[128];
506 val = (void *)&prog->globals[ofs];
507 def = PRVM_ED_GlobalAtOfs(ofs);
509 sprintf (line,"%i(?)", ofs);
512 s = PRVM_ValueString (def->type, val);
513 sprintf (line,"%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
524 char *PRVM_GlobalStringNoContents (int ofs)
528 static char line[128];
530 def = PRVM_ED_GlobalAtOfs(ofs);
532 sprintf (line,"%i(?)", ofs);
534 sprintf (line,"%i(%s)", ofs, PRVM_GetString(def->s_name));
552 // LordHavoc: optimized this to print out much more quickly (tempstring)
553 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
554 void PRVM_ED_Print (prvm_edict_t *ed)
562 char tempstring[8192], tempstring2[260]; // temporary string buffers
566 Con_Printf ("%s: FREE\n",PRVM_NAME);
571 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
572 for (i=1 ; i<prog->progs->numfielddefs ; i++)
574 d = &prog->fielddefs[i];
575 name = PRVM_GetString(d->s_name);
576 if (name[strlen(name)-2] == '_')
577 continue; // skip _x, _y, _z vars
579 v = (int *)((char *)ed->v + d->ofs*4);
581 // if the value is still all 0, skip the field
582 type = d->type & ~DEF_SAVEGLOBAL;
584 for (j=0 ; j<prvm_type_size[type] ; j++)
587 if (j == prvm_type_size[type])
590 if (strlen(name) > 256)
592 strncpy(tempstring2, name, 256);
593 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
594 tempstring2[259] = 0;
597 strcat(tempstring, name);
598 for (l = strlen(name);l < 14;l++)
599 strcat(tempstring, " ");
600 strcat(tempstring, " ");
602 name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
603 if (strlen(name) > 256)
605 strncpy(tempstring2, name, 256);
606 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
607 tempstring2[259] = 0;
610 strcat(tempstring, name);
611 strcat(tempstring, "\n");
612 if (strlen(tempstring) >= 4096)
614 Con_Printf("%s", tempstring);
619 Con_Printf("%s", tempstring);
629 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
637 FS_Printf (f, "{\n");
641 FS_Printf (f, "}\n");
645 for (i=1 ; i<prog->progs->numfielddefs ; i++)
647 d = &prog->fielddefs[i];
648 name = PRVM_GetString(d->s_name);
649 if (name[strlen(name)-2] == '_')
650 continue; // skip _x, _y, _z vars
652 v = (int *)((char *)ed->v + d->ofs*4);
654 // if the value is still all 0, skip the field
655 type = d->type & ~DEF_SAVEGLOBAL;
656 for (j=0 ; j<prvm_type_size[type] ; j++)
659 if (j == prvm_type_size[type])
662 FS_Printf (f,"\"%s\" ",name);
663 FS_Printf (f,"\"%s\"\n", PRVM_UglyValueString(d->type, (prvm_eval_t *)v));
666 FS_Printf (f, "}\n");
669 void PRVM_ED_PrintNum (int ent)
671 PRVM_ED_Print (PRVM_EDICT_NUM(ent));
676 PRVM_ED_PrintEdicts_f
678 For debugging, prints all the entities in the current server
681 void PRVM_ED_PrintEdicts_f (void)
687 Con_Print("prvm_edicts <program name>\n");
692 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
695 Con_Printf ("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
696 for (i=0 ; i<prog->num_edicts ; i++)
697 PRVM_ED_PrintNum (i);
706 For debugging, prints a single edict
709 void PRVM_ED_PrintEdict_f (void)
715 Con_Print("prvm_edict <program name> <edict number>\n");
720 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
723 i = atoi (Cmd_Argv(2));
724 if (i >= prog->num_edicts)
726 Con_Printf("Bad edict number\n");
730 PRVM_ED_PrintNum (i);
742 // 2 possibilities : 1. just displaying the active edict count
743 // 2. making a function pointer [x]
744 void PRVM_ED_Count_f (void)
752 Con_Print("prvm_count <program name>\n");
757 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
760 if(prog->count_edicts)
761 prog->count_edicts();
765 for (i=0 ; i<prog->num_edicts ; i++)
767 ent = PRVM_EDICT_NUM(i);
773 Con_Printf ("num_edicts:%3i\n", sv.num_edicts);
774 Con_Printf ("active :%3i\n", active);
781 ==============================================================================
785 FIXME: need to tag constants, doesn't really work
786 ==============================================================================
794 void PRVM_ED_WriteGlobals (qfile_t *f)
802 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
804 def = &prog->globaldefs[i];
806 if ( !(def->type & DEF_SAVEGLOBAL) )
808 type &= ~DEF_SAVEGLOBAL;
810 if (type != ev_string && type != ev_float && type != ev_entity)
813 name = PRVM_GetString(def->s_name);
814 FS_Printf (f,"\"%s\" ", name);
815 FS_Printf (f,"\"%s\"\n", PRVM_UglyValueString(type, (prvm_eval_t *)&prog->globals[def->ofs]));
825 void PRVM_ED_ParseGlobals (const char *data)
827 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
833 if (!COM_ParseToken(&data, false))
834 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
835 if (com_token[0] == '}')
838 strcpy (keyname, com_token);
841 if (!COM_ParseToken(&data, false))
842 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
844 if (com_token[0] == '}')
845 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
847 key = PRVM_ED_FindGlobal (keyname);
850 Con_DPrintf ("'%s' is not a global on %s\n", keyname, PRVM_NAME);
854 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
855 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
859 //============================================================================
867 char *PRVM_ED_NewString (const char *string)
872 l = strlen(string) + 1;
873 new = Mem_Alloc(prog->edictstring_mempool, l);
876 for (i=0 ; i< l ; i++)
878 if (string[i] == '\\' && i < l-1)
881 if (string[i] == 'n')
887 *new_p++ = string[i];
898 Can parse either fields or globals
899 returns false if error
902 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
910 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
912 val = (prvm_eval_t *)((int *)pr_globals + key->ofs);
913 switch (key->type & ~DEF_SAVEGLOBAL)
916 val->string = PRVM_SetString(ED_NewString(s));
920 while (*s && *s <= ' ')
922 val->_float = atof(s);
926 for (i = 0;i < 3;i++)
928 while (*s && *s <= ' ')
932 val->vector[i] = atof(s);
941 while (*s && *s <= ' ')
944 if (i < 0 || i >= MAX_EDICTS)
945 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i) on %s\n", i, MAX_EDICTS, PRVM_NAME);
946 while (i >= prog->max_edicts)
947 PRVM_MEM_IncreaseEdicts();
948 //SV_IncreaseEdicts();
949 // if SV_IncreaseEdicts was called the base pointer needs to be updated
951 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
952 val->edict = PRVM_EDICT_TO_PROG(EDICT_NUM(i));
956 def = PRVM_ED_FindField(s);
959 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s on %s\n", s, PRVM_NAME);
962 val->_int = PRVM_G_INT(def->ofs);
966 func = PRVM_ED_FindFunction(s);
969 Con_Printf ("PRVM_ED_ParseEpair: Can't find function %s on %s\n", s, PRVM_NAME);
972 val->function = func - prog->functions;
976 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PR_GetString(key->s_name), PRVM_NAME);
986 Parses an edict out of the given string, returning the new position
987 ed should be a properly initialized empty edict.
988 Used for initial level load and for savegames.
991 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1002 if (ent != prog->edicts) // hack
1003 memset (ent->v, 0, prog->progs->entityfields * 4);
1005 // go through all the dictionary pairs
1009 if (!COM_ParseToken(&data, false))
1010 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1011 if (com_token[0] == '}')
1014 // anglehack is to allow QuakeEd to write single scalar angles
1015 // and allow them to be turned into vectors. (FIXME...)
1016 if (!strcmp(com_token, "angle"))
1018 strcpy (com_token, "angles");
1024 // FIXME: change light to _light to get rid of this hack
1025 if (!strcmp(com_token, "light"))
1026 strcpy (com_token, "light_lev"); // hack for single light def
1028 strcpy (keyname, com_token);
1030 // another hack to fix heynames with trailing spaces
1031 n = strlen(keyname);
1032 while (n && keyname[n-1] == ' ')
1039 if (!COM_ParseToken(&data, false))
1040 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1042 if (com_token[0] == '}')
1043 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
1047 // keynames with a leading underscore are used for utility comments,
1048 // and are immediately discarded by quake
1049 if (keyname[0] == '_')
1052 key = PRVM_ED_FindField (keyname);
1055 Con_DPrintf ("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1062 strcpy (temp, com_token);
1063 sprintf (com_token, "0 %s 0", temp);
1066 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1067 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1071 ent->e->free = true;
1079 PRVM_ED_LoadFromFile
1081 The entities are directly placed in the array, rather than allocated with
1082 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1083 number references out of order.
1085 Creates a server's entity / program execution context by
1086 parsing textual entity definitions out of an ent file.
1088 Used for both fresh maps and savegame loads. A fresh map would also need
1089 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1092 void PRVM_ED_LoadFromFile (const char *data)
1095 int parsed, inhibited, spawned, died;
1105 if(prog->flag & PRVM_GE_TIME)
1106 PRVM_G_FLOAT(PRVM_ED_FindFieldOffset("time")) = prog->time;
1111 // parse the opening brace
1112 if (!COM_ParseToken(&data, false))
1114 if (com_token[0] != '{')
1115 PRVM_ERROR ("PRVM_ED_LoadFromFile: found %s when expecting (%s) {",com_token, PRVM_NAME);
1118 ent = PRVM_EDICT_NUM(0);
1120 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 entities parsed, %i inhibited, %i spawned (%i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, 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));
1210 prog->progs_mempool = t1;
1211 prog->edictstring_mempool = t2;
1212 prog->edicts_mempool = t3;
1214 PRVM_GCALL(reset_cmd)();
1222 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func)
1226 ddef_t *infielddefs;
1228 dfunction_t *dfunctions;
1230 Mem_EmptyPool(prog->progs_mempool);
1231 Mem_EmptyPool(prog->edictstring_mempool);
1233 temp = FS_LoadFile (filename, false);
1235 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1237 prog->progs = (dprograms_t *)Mem_Alloc(prog->progs_mempool, fs_filesize);
1239 memcpy(prog->progs, temp, fs_filesize);
1242 Con_DPrintf ("%s programs occupy %iK.\n", PRVM_NAME, fs_filesize/1024);
1244 pr_crc = CRC_Block((qbyte *)prog->progs, fs_filesize);
1246 // byte swap the header
1247 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1248 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1250 if (prog->progs->version != PROG_VERSION)
1251 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1252 if (prog->progs->crc != prog->crc)
1253 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1255 //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1256 dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
1257 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1258 prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
1260 // we need to expand the fielddefs list to include all the engine fields,
1261 // so allocate a new place for it
1262 infielddefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_fielddefs);
1264 prog->fielddefs = Mem_Alloc(prog->progs_mempool, prog->progs->numfielddefs * sizeof(ddef_t));
1266 prog->statements = (dstatement_t *)((qbyte *)prog->progs + prog->progs->ofs_statements);
1268 // moved edict_size calculation down below field adding code
1270 //pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1271 prog->globals = (float *)((qbyte *)prog->progs + prog->progs->ofs_globals);
1273 // byte swap the lumps
1274 for (i=0 ; i<prog->progs->numstatements ; i++)
1276 prog->statements[i].op = LittleShort(prog->statements[i].op);
1277 prog->statements[i].a = LittleShort(prog->statements[i].a);
1278 prog->statements[i].b = LittleShort(prog->statements[i].b);
1279 prog->statements[i].c = LittleShort(prog->statements[i].c);
1282 prog->functions = Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1283 for (i = 0;i < prog->progs->numfunctions;i++)
1285 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1286 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1287 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1288 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1289 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1290 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1291 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1294 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1296 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1297 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1298 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1301 // copy the progs fields to the new fields list
1302 for (i = 0;i < prog->progs->numfielddefs;i++)
1304 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1305 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1306 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1307 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1308 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1311 /* // append the darkplaces fields
1312 for (i = 0;i < (int) DPFIELDS;i++)
1314 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1315 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1316 pr_fielddefs[progs->numfielddefs].s_name = PR_SetString(dpfields[i].string);
1317 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1318 progs->entityfields += 3;
1320 progs->entityfields++;
1321 progs->numfielddefs++;
1324 // check required functions
1325 for(i=0 ; i < numrequiredfunc ; i++)
1326 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1327 PRVM_ERROR("%s: %s not found in %s\n",PRVM_NAME, required_func[i], filename);
1329 for (i=0 ; i<prog->progs->numglobals ; i++)
1330 ((int *)prog->globals)[i] = LittleLong (((int *)prog->globals)[i]);
1332 // moved edict_size calculation down here, below field adding code
1333 // LordHavoc: this no longer includes the edict_t header
1334 prog->edict_size = prog->progs->entityfields * 4;
1335 prog->edictareasize = prog->edict_size * MAX_EDICTS;
1337 // LordHavoc: bounds check anything static
1338 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1344 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1345 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s\n", i, PRVM_NAME);
1348 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1349 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s\n", i, PRVM_NAME);
1351 // global global global
1386 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1387 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n", i);
1389 // global none global
1395 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1396 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1412 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1413 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n in %s", i, PRVM_NAME);
1427 if ((unsigned short) st->a >= prog->progs->numglobals)
1428 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1431 PRVM_ERROR("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1438 prog->loaded = TRUE;
1440 // set flags & ddef_ts in prog
1444 prog->self = PRVM_ED_FindGlobal("self");
1446 if(PRVM_ED_FindGlobal("time"))
1447 prog->flag |= PRVM_GE_TIME;
1449 if(PRVM_ED_FindField ("chain"))
1450 prog->flag |= PRVM_FE_CHAIN;
1452 if(PRVM_ED_FindField ("classname"))
1453 prog->flag |= PRVM_FE_CLASSNAME;
1455 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1456 && prog->flag & PRVM_GE_TIME && prog->self)
1457 prog->flag |= PRVM_OP_STATE;
1459 PRVM_GCALL(reset_cmd)();
1466 void PRVM_Fields_f (void)
1468 int i, j, ednum, used, usedamount;
1470 char tempstring[5000], tempstring2[260], *name;
1479 Con_Printf("no progs loaded\n");
1486 Con_Print("prvm_fields <program name>\n");
1491 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1494 counts = Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1495 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1497 ed = PRVM_EDICT_NUM(ednum);
1500 for (i = 1;i < prog->progs->numfielddefs;i++)
1502 d = &prog->fielddefs[i];
1503 name = PRVM_GetString(d->s_name);
1504 if (name[strlen(name)-2] == '_')
1505 continue; // skip _x, _y, _z vars
1506 v = (int *)((char *)ed->v + d->ofs*4);
1507 // if the value is still all 0, skip the field
1508 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1521 for (i = 0;i < prog->progs->numfielddefs;i++)
1523 d = &prog->fielddefs[i];
1524 name = PRVM_GetString(d->s_name);
1525 if (name[strlen(name)-2] == '_')
1526 continue; // skip _x, _y, _z vars
1527 switch(d->type & ~DEF_SAVEGLOBAL)
1530 strcat(tempstring, "string ");
1533 strcat(tempstring, "entity ");
1536 strcat(tempstring, "function ");
1539 strcat(tempstring, "field ");
1542 strcat(tempstring, "void ");
1545 strcat(tempstring, "float ");
1548 strcat(tempstring, "vector ");
1551 strcat(tempstring, "pointer ");
1554 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1555 strcat(tempstring, tempstring2);
1558 if (strlen(name) > 256)
1560 strncpy(tempstring2, name, 256);
1561 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1562 tempstring2[259] = 0;
1565 strcat(tempstring, name);
1566 for (j = strlen(name);j < 25;j++)
1567 strcat(tempstring, " ");
1568 sprintf(tempstring2, "%5d", counts[i]);
1569 strcat(tempstring, tempstring2);
1570 strcat(tempstring, "\n");
1571 if (strlen(tempstring) >= 4096)
1573 Con_Printf("%s", tempstring);
1579 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1583 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);
1588 void PRVM_Globals_f (void)
1594 Con_Printf("no progs loaded\n");
1597 if(Cmd_Argc () != 2)
1599 Con_Print ("prvm_globals <program name>\n");
1604 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1607 Con_Printf("%s :", PRVM_NAME);
1609 for (i = 0;i < prog->progs->numglobaldefs;i++)
1610 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1611 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1621 void PRVM_Init (void)
1623 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f);
1624 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f);
1625 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f);
1626 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
1627 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
1628 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
1629 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1630 Cvar_RegisterVariable (&prvm_boundscheck);
1631 Cvar_RegisterVariable (&prvm_traceqc);
1641 void PRVM_InitProg(int prognr)
1643 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1644 Sys_Error("PRVM_InitProg: Invalid program number %i\n",prognr);
1646 prog = &prog_list[prognr];
1648 memset(prog, 0, sizeof(prvm_prog_t));
1650 PRVM_GCALL(init_cmd)();
1653 int PRVM_GetProgNr()
1655 return prog - prog_list;
1658 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1659 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1661 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1665 void PRVM_ProcessError(void)
1668 PRVM_GCALL(error_cmd)();
1672 int NUM_FOR_EDICT_ERROR(edict_t *e)
1674 Host_Error ("NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, sv.edicts, e - sv.edicts);
1678 int NUM_FOR_EDICT(edict_t *e)
1682 if ((unsigned int)n >= MAX_EDICTS)
1683 Host_Error ("NUM_FOR_EDICT: bad pointer");
1687 //int NoCrash_NUM_FOR_EDICT(edict_t *e)
1689 // return e - sv.edicts;
1692 //#define EDICT_TO_PROG(e) ((qbyte *)(((edict_t *)e)->v) - (qbyte *)(sv.edictsfields))
1693 //#define PROG_TO_EDICT(e) (sv.edicts + ((e) / (progs->entityfields * 4)))
1694 int EDICT_TO_PROG(edict_t *e)
1698 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1699 Host_Error("EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, sv.edicts);
1700 return n;// EXPERIMENTAL
1701 //return (qbyte *)e->v - (qbyte *)sv.edictsfields;
1703 edict_t *PROG_TO_EDICT(int n)
1705 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1706 Host_Error("PROG_TO_EDICT: invalid edict number %i\n", n);
1707 return sv.edicts + n; // EXPERIMENTAL
1708 //return sv.edicts + ((n) / (progs->entityfields * 4));