2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 static prvm_prog_t prog_list[PRVM_MAXPROGS];
29 int prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
31 ddef_t *PRVM_ED_FieldAtOfs(int ofs);
32 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s);
34 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
35 cvar_t prvm_boundscheck = {0, "prvm_boundscheck", "1"};
36 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
37 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0"};
39 //============================================================================
47 void PRVM_MEM_Alloc(void)
51 // reserve space for the null entity aka world
52 // check bound of max_edicts
53 prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
54 prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_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->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
62 // alloc edict private space
63 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
66 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
69 for(i = 0; i < prog->max_edicts; i++)
71 prog->edicts[i].priv.required = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
72 prog->edicts[i].fields.vp = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
78 PRVM_MEM_IncreaseEdicts
81 void PRVM_MEM_IncreaseEdicts(void)
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->progs_mempool, prog->max_edicts * prog->edict_size);
97 prog->edictprivate = Mem_Alloc(prog->progs_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].priv.required = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
106 prog->edicts[i].fields.vp = (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(0 <= prognr && prognr < PRVM_MAXPROGS)
172 if(prog_list[prognr].loaded)
173 prog = &prog_list[prognr];
175 PRVM_ERROR("%i not loaded !\n", prognr);
178 PRVM_ERROR("Invalid program number %i\n", prognr);
185 Sets everything to NULL
188 void PRVM_ED_ClearEdict (prvm_edict_t *e)
190 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
191 e->priv.required->free = false;
193 // AK: Let the init_edict function determine if something needs to be initialized
194 PRVM_GCALL(init_edict)(e);
201 Either finds a free edict, or allocates a new one.
202 Try to avoid reusing an entity that was recently freed, because it
203 can cause the client to think the entity morphed into something else
204 instead of being removed and recreated, which can cause interpolated
205 angles and bad trails.
208 prvm_edict_t *PRVM_ED_Alloc (void)
213 // the client qc dont need maxclients
214 // thus it doesnt need to use svs.maxclients
215 // AK: changed i=svs.maxclients+1
216 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
217 // although the menu/client has no world
218 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
220 e = PRVM_EDICT_NUM(i);
221 // the first couple seconds of server time can involve a lot of
222 // freeing and allocating, so relax the replacement policy
223 if (e->priv.required->free && ( e->priv.required->freetime < 2 || (*prog->time - e->priv.required->freetime) > 0.5 ) )
225 PRVM_ED_ClearEdict (e);
230 if (i == prog->limit_edicts)
231 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
234 if (prog->num_edicts >= prog->max_edicts)
235 PRVM_MEM_IncreaseEdicts();
237 e = PRVM_EDICT_NUM(i);
238 PRVM_ED_ClearEdict (e);
247 Marks the edict as free
248 FIXME: walk all entities and NULL out references to this entity
251 void PRVM_ED_Free (prvm_edict_t *ed)
253 // dont delete the null entity (world) or reserved edicts
254 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
257 PRVM_GCALL(free_edict)(ed);
259 ed->priv.required->free = true;
260 ed->priv.required->freetime = *prog->time;
263 //===========================================================================
270 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
275 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
277 def = &prog->globaldefs[i];
289 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
294 for (i=0 ; i<prog->progs->numfielddefs ; i++)
296 def = &prog->fielddefs[i];
308 ddef_t *PRVM_ED_FindField (const char *name)
313 for (i=0 ; i<prog->progs->numfielddefs ; i++)
315 def = &prog->fielddefs[i];
316 if (!strcmp(PRVM_GetString(def->s_name), name))
327 ddef_t *PRVM_ED_FindGlobal (const char *name)
332 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
334 def = &prog->globaldefs[i];
335 if (!strcmp(PRVM_GetString(def->s_name), name))
347 mfunction_t *PRVM_ED_FindFunction (const char *name)
352 for (i=0 ; i<prog->progs->numfunctions ; i++)
354 func = &prog->functions[i];
355 if (!strcmp(PRVM_GetString(func->s_name), name))
366 Returns a string describing *data in a type specific manner
369 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
371 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
376 type &= ~DEF_SAVEGLOBAL;
381 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
385 if (n < 0 || n >= prog->limit_edicts)
386 sprintf (line, "entity %i (invalid!)", n);
388 sprintf (line, "entity %i", n);
391 f = prog->functions + val->function;
392 sprintf (line, "%s()", PRVM_GetString(f->s_name));
395 def = PRVM_ED_FieldAtOfs ( val->_int );
396 sprintf (line, ".%s", PRVM_GetString(def->s_name));
399 sprintf (line, "void");
402 // LordHavoc: changed from %5.1f to %10.4f
403 sprintf (line, "%10.4f", val->_float);
406 // LordHavoc: changed from %5.1f to %10.4f
407 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
410 sprintf (line, "pointer");
413 sprintf (line, "bad type %i", type);
424 Returns a string describing *data in a type specific manner
425 Easier to parse than PR_ValueString
428 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
430 static char line[4096];
436 type &= ~DEF_SAVEGLOBAL;
441 // Parse the string a bit to turn special characters
442 // (like newline, specifically) into escape codes,
443 // this fixes saving games from various mods
444 s = PRVM_GetString (val->string);
445 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
464 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
467 f = prog->functions + val->function;
468 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
471 def = PRVM_ED_FieldAtOfs ( val->_int );
472 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
475 dpsnprintf (line, sizeof (line), "void");
478 dpsnprintf (line, sizeof (line), "%f", val->_float);
481 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
484 dpsnprintf (line, sizeof (line), "bad type %i", type);
495 Returns a string with a description and the contents of a global,
496 padded to 20 field width
499 char *PRVM_GlobalString (int ofs)
505 static char line[128];
507 val = (void *)&prog->globals.generic[ofs];
508 def = PRVM_ED_GlobalAtOfs(ofs);
510 sprintf (line,"%i(?)", ofs);
513 s = PRVM_ValueString (def->type, val);
514 sprintf (line,"%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
525 char *PRVM_GlobalStringNoContents (int ofs)
529 static char line[128];
531 def = PRVM_ED_GlobalAtOfs(ofs);
533 sprintf (line,"%i(?)", ofs);
535 sprintf (line,"%i(%s)", ofs, PRVM_GetString(def->s_name));
553 // LordHavoc: optimized this to print out much more quickly (tempstring)
554 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
555 void PRVM_ED_Print(prvm_edict_t *ed)
563 char tempstring[8192], tempstring2[260]; // temporary string buffers
565 if (ed->priv.required->free)
567 Con_Printf("%s: FREE\n",PRVM_NAME);
572 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
573 for (i=1 ; i<prog->progs->numfielddefs ; i++)
575 d = &prog->fielddefs[i];
576 name = PRVM_GetString(d->s_name);
577 if (name[strlen(name)-2] == '_')
578 continue; // skip _x, _y, _z vars
580 v = (int *)((char *)ed->fields.vp + d->ofs*4);
582 // if the value is still all 0, skip the field
583 type = d->type & ~DEF_SAVEGLOBAL;
585 for (j=0 ; j<prvm_type_size[type] ; j++)
588 if (j == prvm_type_size[type])
591 if (strlen(name) > 256)
593 memcpy (tempstring2, name, 256);
594 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
595 tempstring2[259] = 0;
598 strcat(tempstring, name);
599 for (l = strlen(name);l < 14;l++)
600 strcat(tempstring, " ");
601 strcat(tempstring, " ");
603 name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
604 if (strlen(name) > 256)
606 memcpy (tempstring2, name, 256);
607 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
608 tempstring2[259] = 0;
611 strcat(tempstring, name);
612 strcat(tempstring, "\n");
613 if (strlen(tempstring) >= 4096)
615 Con_Print(tempstring);
620 Con_Print(tempstring);
630 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
640 if (ed->priv.required->free)
646 for (i=1 ; i<prog->progs->numfielddefs ; i++)
648 d = &prog->fielddefs[i];
649 name = PRVM_GetString(d->s_name);
650 if (name[strlen(name)-2] == '_')
651 continue; // skip _x, _y, _z vars
653 v = (int *)((char *)ed->fields.vp + d->ofs*4);
655 // if the value is still all 0, skip the field
656 type = d->type & ~DEF_SAVEGLOBAL;
657 for (j=0 ; j<prvm_type_size[type] ; j++)
660 if (j == prvm_type_size[type])
663 FS_Printf(f,"\"%s\" ",name);
664 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(d->type, (prvm_eval_t *)v));
670 void PRVM_ED_PrintNum (int ent)
672 PRVM_ED_Print(PRVM_EDICT_NUM(ent));
677 PRVM_ED_PrintEdicts_f
679 For debugging, prints all the entities in the current server
682 void PRVM_ED_PrintEdicts_f (void)
688 Con_Print("prvm_edicts <program name>\n");
693 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
696 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
697 for (i=0 ; i<prog->num_edicts ; i++)
698 PRVM_ED_PrintNum (i);
707 For debugging, prints a single edict
710 void PRVM_ED_PrintEdict_f (void)
716 Con_Print("prvm_edict <program name> <edict number>\n");
721 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
724 i = atoi (Cmd_Argv(2));
725 if (i >= prog->num_edicts)
727 Con_Print("Bad edict number\n");
731 PRVM_ED_PrintNum (i);
743 // 2 possibilities : 1. just displaying the active edict count
744 // 2. making a function pointer [x]
745 void PRVM_ED_Count_f (void)
753 Con_Print("prvm_count <program name>\n");
758 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
761 if(prog->count_edicts)
762 prog->count_edicts();
766 for (i=0 ; i<prog->num_edicts ; i++)
768 ent = PRVM_EDICT_NUM(i);
769 if (ent->priv.required->free)
774 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
775 Con_Printf("active :%3i\n", active);
782 ==============================================================================
786 FIXME: need to tag constants, doesn't really work
787 ==============================================================================
795 void PRVM_ED_WriteGlobals (qfile_t *f)
803 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
805 def = &prog->globaldefs[i];
807 if ( !(def->type & DEF_SAVEGLOBAL) )
809 type &= ~DEF_SAVEGLOBAL;
811 if (type != ev_string && type != ev_float && type != ev_entity)
814 name = PRVM_GetString(def->s_name);
815 FS_Printf(f,"\"%s\" ", name);
816 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
826 void PRVM_ED_ParseGlobals (const char *data)
828 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
834 if (!COM_ParseToken(&data, false))
835 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
836 if (com_token[0] == '}')
839 strcpy (keyname, com_token);
842 if (!COM_ParseToken(&data, false))
843 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
845 if (com_token[0] == '}')
846 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
848 key = PRVM_ED_FindGlobal (keyname);
851 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
855 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
856 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
860 //============================================================================
867 Can parse either fields or globals
868 returns false if error
871 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
880 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
882 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
883 switch (key->type & ~DEF_SAVEGLOBAL)
887 new_p = PRVM_AllocString(l);
888 val->string = PRVM_SetQCString(new_p);
889 for (i = 0;i < l;i++)
891 if (s[i] == '\\' && i < l-1)
896 else if (s[i] == 'r')
907 while (*s && *s <= ' ')
909 val->_float = atof(s);
913 for (i = 0;i < 3;i++)
915 while (*s && *s <= ' ')
919 val->vector[i] = atof(s);
928 while (*s && *s <= ' ')
931 if (i < 0 || i >= prog->limit_edicts)
932 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i) on %s\n", i, MAX_EDICTS, PRVM_NAME);
933 while (i >= prog->max_edicts)
934 PRVM_MEM_IncreaseEdicts();
935 //SV_IncreaseEdicts();
936 // if SV_IncreaseEdicts was called the base pointer needs to be updated
938 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
939 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(i));
943 def = PRVM_ED_FindField(s);
946 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
949 val->_int = def->ofs;
953 func = PRVM_ED_FindFunction(s);
956 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
959 val->function = func - prog->functions;
963 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
973 Console command to set a field of a specified edict
976 void PRVM_ED_EdictSet_f(void)
983 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
988 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
990 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
994 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
996 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
997 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
999 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1005 ====================
1008 Parses an edict out of the given string, returning the new position
1009 ed should be a properly initialized empty edict.
1010 Used for initial level load and for savegames.
1011 ====================
1013 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1023 // go through all the dictionary pairs
1027 if (!COM_ParseToken(&data, false))
1028 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1029 if (com_token[0] == '}')
1032 // anglehack is to allow QuakeEd to write single scalar angles
1033 // and allow them to be turned into vectors. (FIXME...)
1034 if (!strcmp(com_token, "angle"))
1036 strcpy (com_token, "angles");
1042 // FIXME: change light to _light to get rid of this hack
1043 if (!strcmp(com_token, "light"))
1044 strcpy (com_token, "light_lev"); // hack for single light def
1046 strcpy (keyname, com_token);
1048 // another hack to fix keynames with trailing spaces
1049 n = strlen(keyname);
1050 while (n && keyname[n-1] == ' ')
1057 if (!COM_ParseToken(&data, false))
1058 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1060 if (com_token[0] == '}')
1061 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
1065 // keynames with a leading underscore are used for utility comments,
1066 // and are immediately discarded by quake
1067 if (keyname[0] == '_')
1070 key = PRVM_ED_FindField (keyname);
1073 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1080 strcpy (temp, com_token);
1081 sprintf (com_token, "0 %s 0", temp);
1084 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1085 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1089 ent->priv.required->free = true;
1097 PRVM_ED_LoadFromFile
1099 The entities are directly placed in the array, rather than allocated with
1100 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1101 number references out of order.
1103 Creates a server's entity / program execution context by
1104 parsing textual entity definitions out of an ent file.
1106 Used for both fresh maps and savegame loads. A fresh map would also need
1107 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1110 void PRVM_ED_LoadFromFile (const char *data)
1113 int parsed, inhibited, spawned, died;
1125 // parse the opening brace
1126 if (!COM_ParseToken(&data, false))
1128 if (com_token[0] != '{')
1129 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1131 // CHANGED: this is not conform to PR_LoadFromFile
1132 if(prog->loadintoworld)
1134 prog->loadintoworld = false;
1135 ent = PRVM_EDICT_NUM(0);
1138 ent = PRVM_ED_Alloc();
1141 if (ent != prog->edicts) // hack
1142 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1144 data = PRVM_ED_ParseEdict (data, ent);
1147 // remove the entity ?
1148 if(prog->load_edict && !prog->load_edict(ent))
1156 // immediately call spawn function, but only if there is a self global and a classname
1158 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1160 string_t handle = *(string_t*)&((qbyte*)ent->fields.vp)[PRVM_ED_FindFieldOffset("classname")];
1163 Con_Print("No classname for:\n");
1169 // look for the spawn function
1170 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1174 if (developer.integer) // don't confuse non-developers with errors
1176 Con_Print("No spawn function for:\n");
1184 PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1185 PRVM_ExecuteProgram (func - prog->functions, "");
1189 if (ent->priv.required->free)
1193 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);
1198 typedef struct dpfield_s
1205 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1207 dpfield_t dpfields[] =
1218 void PRVM_ResetProg()
1220 PRVM_GCALL(reset_cmd)();
1221 Mem_FreePool(&prog->progs_mempool);
1222 memset(prog,0,sizeof(prvm_prog_t));
1230 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field)
1234 ddef_t *infielddefs;
1235 dfunction_t *dfunctions;
1237 if( prog->loaded ) {
1238 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!\n", PRVM_NAME );
1241 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false);
1242 if (prog->progs == NULL)
1243 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1245 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, fs_filesize/1024);
1247 prog->filecrc = CRC_Block((qbyte *)prog->progs, fs_filesize);
1249 // byte swap the header
1250 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1251 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1253 if (prog->progs->version != PROG_VERSION)
1254 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1255 if (prog->progs->crc != prog->headercrc)
1256 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1258 //prog->functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1259 dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
1261 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1262 prog->stringssize = 0;
1263 for (i = 0;i < prog->progs->numstrings;i++)
1265 if (prog->progs->ofs_strings + prog->stringssize >= fs_filesize)
1266 PRVM_ERROR ("%s: %s strings go past end of file\n", PRVM_NAME, filename);
1267 prog->stringssize += strlen (prog->strings + prog->stringssize) + 1;
1269 prog->numknownstrings = 0;
1270 prog->maxknownstrings = 0;
1271 prog->knownstrings = NULL;
1273 prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
1275 // we need to expand the fielddefs list to include all the engine fields,
1276 // so allocate a new place for it
1277 infielddefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_fielddefs);
1279 prog->fielddefs = Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1281 prog->statements = (dstatement_t *)((qbyte *)prog->progs + prog->progs->ofs_statements);
1283 // moved edict_size calculation down below field adding code
1285 //pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1286 prog->globals.generic = (float *)((qbyte *)prog->progs + prog->progs->ofs_globals);
1288 // byte swap the lumps
1289 for (i=0 ; i<prog->progs->numstatements ; i++)
1291 prog->statements[i].op = LittleShort(prog->statements[i].op);
1292 prog->statements[i].a = LittleShort(prog->statements[i].a);
1293 prog->statements[i].b = LittleShort(prog->statements[i].b);
1294 prog->statements[i].c = LittleShort(prog->statements[i].c);
1297 prog->functions = Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1298 for (i = 0;i < prog->progs->numfunctions;i++)
1300 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1301 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1302 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1303 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1304 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1305 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1306 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1309 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1311 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1312 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1313 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1316 // copy the progs fields to the new fields list
1317 for (i = 0;i < prog->progs->numfielddefs;i++)
1319 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1320 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1321 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1322 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1323 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1326 // append the required fields
1327 for (i = 0;i < (int) numrequiredfields;i++)
1329 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1330 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1331 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1332 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1333 prog->progs->entityfields += 3;
1335 prog->progs->entityfields++;
1336 prog->progs->numfielddefs++;
1339 // check required functions
1340 for(i=0 ; i < numrequiredfunc ; i++)
1341 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1342 PRVM_ERROR("%s: %s not found in %s\n",PRVM_NAME, required_func[i], filename);
1344 for (i=0 ; i<prog->progs->numglobals ; i++)
1345 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1347 // moved edict_size calculation down here, below field adding code
1348 // LordHavoc: this no longer includes the prvm_edict_t header
1349 prog->edict_size = prog->progs->entityfields * 4;
1350 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1352 // LordHavoc: bounds check anything static
1353 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1359 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1360 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s\n", i, PRVM_NAME);
1363 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1364 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s\n", i, PRVM_NAME);
1366 // global global global
1401 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1402 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n", i);
1404 // global none global
1410 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1411 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1427 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1428 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n in %s", i, PRVM_NAME);
1442 if ((unsigned short) st->a >= prog->progs->numglobals)
1443 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1446 PRVM_ERROR("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1453 prog->loaded = TRUE;
1455 // set flags & ddef_ts in prog
1459 prog->self = PRVM_ED_FindGlobal("self");
1461 if( PRVM_ED_FindGlobal("time") && PRVM_ED_FindGlobal("time")->type & ev_float )
1462 prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs);
1464 if(PRVM_ED_FindField ("chain"))
1465 prog->flag |= PRVM_FE_CHAIN;
1467 if(PRVM_ED_FindField ("classname"))
1468 prog->flag |= PRVM_FE_CLASSNAME;
1470 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1471 && prog->flag && prog->self)
1472 prog->flag |= PRVM_OP_STATE;
1474 PRVM_GCALL(init_cmd)();
1481 void PRVM_Fields_f (void)
1483 int i, j, ednum, used, usedamount;
1485 char tempstring[5000], tempstring2[260];
1495 Con_Print("no progs loaded\n");
1502 Con_Print("prvm_fields <program name>\n");
1507 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1510 counts = Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1511 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1513 ed = PRVM_EDICT_NUM(ednum);
1514 if (ed->priv.required->free)
1516 for (i = 1;i < prog->progs->numfielddefs;i++)
1518 d = &prog->fielddefs[i];
1519 name = PRVM_GetString(d->s_name);
1520 if (name[strlen(name)-2] == '_')
1521 continue; // skip _x, _y, _z vars
1522 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1523 // if the value is still all 0, skip the field
1524 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1537 for (i = 0;i < prog->progs->numfielddefs;i++)
1539 d = &prog->fielddefs[i];
1540 name = PRVM_GetString(d->s_name);
1541 if (name[strlen(name)-2] == '_')
1542 continue; // skip _x, _y, _z vars
1543 switch(d->type & ~DEF_SAVEGLOBAL)
1546 strcat(tempstring, "string ");
1549 strcat(tempstring, "entity ");
1552 strcat(tempstring, "function ");
1555 strcat(tempstring, "field ");
1558 strcat(tempstring, "void ");
1561 strcat(tempstring, "float ");
1564 strcat(tempstring, "vector ");
1567 strcat(tempstring, "pointer ");
1570 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1571 strcat(tempstring, tempstring2);
1574 if (strlen(name) > 256)
1576 memcpy (tempstring2, name, 256);
1577 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1578 tempstring2[259] = 0;
1581 strcat(tempstring, name);
1582 for (j = strlen(name);j < 25;j++)
1583 strcat(tempstring, " ");
1584 sprintf(tempstring2, "%5d", counts[i]);
1585 strcat(tempstring, tempstring2);
1586 strcat(tempstring, "\n");
1587 if (strlen(tempstring) >= 4096)
1589 Con_Print(tempstring);
1595 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1599 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);
1604 void PRVM_Globals_f (void)
1610 Con_Print("no progs loaded\n");
1613 if(Cmd_Argc () != 2)
1615 Con_Print("prvm_globals <program name>\n");
1620 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1623 Con_Printf("%s :", PRVM_NAME);
1625 for (i = 0;i < prog->progs->numglobaldefs;i++)
1626 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1627 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1637 void PRVM_Global_f(void)
1640 if( Cmd_Argc() != 3 ) {
1641 Con_Printf( "prvm_global <program name> <global name>\n" );
1646 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1649 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1651 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1653 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1662 void PRVM_GlobalSet_f(void)
1665 if( Cmd_Argc() != 4 ) {
1666 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1671 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1674 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1676 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1678 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1687 void PRVM_Init (void)
1689 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f);
1690 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f);
1691 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f);
1692 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
1693 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
1694 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
1695 Cmd_AddCommand ("prvm_global", PRVM_Global_f);
1696 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f);
1697 Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f);
1698 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1699 Cvar_RegisterVariable (&prvm_boundscheck);
1700 Cvar_RegisterVariable (&prvm_traceqc);
1710 void PRVM_InitProg(int prognr)
1712 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1713 Sys_Error("PRVM_InitProg: Invalid program number %i\n",prognr);
1715 prog = &prog_list[prognr];
1720 memset(prog, 0, sizeof(prvm_prog_t));
1722 prog->time = &prog->_time;
1723 prog->error_cmd = Host_Error;
1726 int PRVM_GetProgNr()
1728 return prog - prog_list;
1731 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1733 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1736 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1738 _Mem_Free(buffer, filename, fileline);
1741 void _PRVM_FreeAll(const char *filename, int fileline)
1744 prog->fielddefs = NULL;
1745 prog->functions = NULL;
1746 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1749 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1750 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1752 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1757 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1759 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1763 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1766 n = e - prog->edicts;
1767 if ((unsigned int)n >= prog->limit_edicts)
1768 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1772 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1774 // return e - prog->edicts;
1777 //#define PRVM_EDICT_TO_PROG(e) ((qbyte *)(((prvm_edict_t *)e)->v) - (qbyte *)(prog->edictsfields))
1778 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1779 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1782 n = e - prog->edicts;
1783 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1784 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, prog->edicts);
1785 return n;// EXPERIMENTAL
1786 //return (qbyte *)e->v - (qbyte *)prog->edictsfields;
1788 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
1790 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1791 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i\n", n);
1792 return prog->edicts + n; // EXPERIMENTAL
1793 //return prog->edicts + ((n) / (progs->entityfields * 4));
1798 const char *PRVM_GetString(int num)
1800 if (num >= 0 && num < prog->stringssize)
1801 return prog->strings + num;
1802 else if (num < 0 && num >= -prog->numknownstrings)
1805 if (!prog->knownstrings[num])
1806 Host_Error("PRVM_GetString: attempt to get string that is already freed\n");
1807 return prog->knownstrings[num];
1811 Host_Error("PRVM_GetString: invalid string offset %i\n", num);
1816 int PRVM_SetQCString(const char *s)
1821 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1822 return s - prog->strings;
1823 for (i = 0;i < prog->numknownstrings;i++)
1824 if (prog->knownstrings[i] == s)
1826 Host_Error("PRVM_SetQCString: unknown string\n");
1830 int PRVM_SetEngineString(const char *s)
1835 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1836 Host_Error("PRVM_SetEngineString: s in prog->strings area\n");
1837 for (i = 0;i < prog->numknownstrings;i++)
1838 if (prog->knownstrings[i] == s)
1840 // new unknown engine string
1841 if (developer.integer >= 3)
1842 Con_Printf("new engine string %p\n", s);
1843 for (i = 0;i < prog->numknownstrings;i++)
1844 if (!prog->knownstrings[i])
1846 if (i >= prog->numknownstrings)
1848 if (i >= prog->maxknownstrings)
1850 const char **oldstrings = prog->knownstrings;
1851 prog->maxknownstrings += 128;
1852 prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
1853 if (prog->numknownstrings)
1854 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
1856 prog->numknownstrings++;
1858 prog->knownstrings[i] = s;
1862 char *PRVM_AllocString(int bufferlength)
1867 for (i = 0;i < prog->numknownstrings;i++)
1868 if (!prog->knownstrings[i])
1870 if (i >= prog->numknownstrings)
1872 if (i >= prog->maxknownstrings)
1874 const char **oldstrings = prog->knownstrings;
1875 prog->maxknownstrings += 128;
1876 prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
1877 if (prog->numknownstrings)
1878 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
1880 prog->numknownstrings++;
1882 return (char *)(prog->knownstrings[i] = PRVM_Alloc(bufferlength));
1885 void PRVM_FreeString(char *s)
1889 Host_Error("PRVM_FreeString: attempt to free a NULL string\n");
1890 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1891 Host_Error("PRVM_FreeString: attempt to free a constant string\n");
1892 for (i = 0;i < prog->numknownstrings;i++)
1893 if (prog->knownstrings[i] == s)
1895 if (i == prog->numknownstrings)
1896 Host_Error("PRVM_FreeString: attempt to free a non-existent or already freed string\n");
1897 PRVM_Free((char *)prog->knownstrings[i]);
1898 prog->knownstrings[i] = NULL;