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)
191 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
192 e->priv.required->free = false;
194 // AK: Let the init_edict function determine if something needs to be initialized
195 PRVM_GCALL(init_edict)(e);
202 Either finds a free edict, or allocates a new one.
203 Try to avoid reusing an entity that was recently freed, because it
204 can cause the client to think the entity morphed into something else
205 instead of being removed and recreated, which can cause interpolated
206 angles and bad trails.
209 prvm_edict_t *PRVM_ED_Alloc (void)
214 // the client qc dont need maxclients
215 // thus it doesnt need to use svs.maxclients
216 // AK: changed i=svs.maxclients+1
217 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
218 // although the menu/client has no world
219 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
221 e = PRVM_EDICT_NUM(i);
222 // the first couple seconds of server time can involve a lot of
223 // freeing and allocating, so relax the replacement policy
224 if (e->priv.required->free && ( e->priv.required->freetime < 2 || (*prog->time - e->priv.required->freetime) > 0.5 ) )
226 PRVM_ED_ClearEdict (e);
231 if (i == prog->limit_edicts)
232 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
235 if (prog->num_edicts >= prog->max_edicts)
236 PRVM_MEM_IncreaseEdicts();
238 e = PRVM_EDICT_NUM(i);
239 PRVM_ED_ClearEdict (e);
248 Marks the edict as free
249 FIXME: walk all entities and NULL out references to this entity
252 void PRVM_ED_Free (prvm_edict_t *ed)
254 // dont delete the null entity (world) or reserved edicts
255 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
258 PRVM_GCALL(free_edict)(ed);
260 ed->priv.required->free = true;
261 ed->priv.required->freetime = *prog->time;
264 //===========================================================================
271 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
276 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
278 def = &prog->globaldefs[i];
290 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
295 for (i=0 ; i<prog->progs->numfielddefs ; i++)
297 def = &prog->fielddefs[i];
309 ddef_t *PRVM_ED_FindField (const char *name)
314 for (i=0 ; i<prog->progs->numfielddefs ; i++)
316 def = &prog->fielddefs[i];
317 if (!strcmp(PRVM_GetString(def->s_name), name))
328 ddef_t *PRVM_ED_FindGlobal (const char *name)
333 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
335 def = &prog->globaldefs[i];
336 if (!strcmp(PRVM_GetString(def->s_name), name))
348 mfunction_t *PRVM_ED_FindFunction (const char *name)
353 for (i=0 ; i<prog->progs->numfunctions ; i++)
355 func = &prog->functions[i];
356 if (!strcmp(PRVM_GetString(func->s_name), name))
367 Returns a string describing *data in a type specific manner
370 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
372 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
377 type &= ~DEF_SAVEGLOBAL;
382 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
386 if (n < 0 || n >= prog->limit_edicts)
387 sprintf (line, "entity %i (invalid!)", n);
389 sprintf (line, "entity %i", n);
392 f = prog->functions + val->function;
393 sprintf (line, "%s()", PRVM_GetString(f->s_name));
396 def = PRVM_ED_FieldAtOfs ( val->_int );
397 sprintf (line, ".%s", PRVM_GetString(def->s_name));
400 sprintf (line, "void");
403 // LordHavoc: changed from %5.1f to %10.4f
404 sprintf (line, "%10.4f", val->_float);
407 // LordHavoc: changed from %5.1f to %10.4f
408 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
411 sprintf (line, "pointer");
414 sprintf (line, "bad type %i", type);
425 Returns a string describing *data in a type specific manner
426 Easier to parse than PR_ValueString
429 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
431 static char line[4096];
437 type &= ~DEF_SAVEGLOBAL;
442 // Parse the string a bit to turn special characters
443 // (like newline, specifically) into escape codes,
444 // this fixes saving games from various mods
445 s = PRVM_GetString (val->string);
446 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
465 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
468 f = prog->functions + val->function;
469 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
472 def = PRVM_ED_FieldAtOfs ( val->_int );
473 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
476 dpsnprintf (line, sizeof (line), "void");
479 dpsnprintf (line, sizeof (line), "%f", val->_float);
482 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
485 dpsnprintf (line, sizeof (line), "bad type %i", type);
496 Returns a string with a description and the contents of a global,
497 padded to 20 field width
500 char *PRVM_GlobalString (int ofs)
506 static char line[128];
508 val = (void *)&prog->globals.generic[ofs];
509 def = PRVM_ED_GlobalAtOfs(ofs);
511 sprintf (line,"%i(?)", ofs);
514 s = PRVM_ValueString (def->type, val);
515 sprintf (line,"%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
526 char *PRVM_GlobalStringNoContents (int ofs)
530 static char line[128];
532 def = PRVM_ED_GlobalAtOfs(ofs);
534 sprintf (line,"%i(?)", ofs);
536 sprintf (line,"%i(%s)", ofs, PRVM_GetString(def->s_name));
554 // LordHavoc: optimized this to print out much more quickly (tempstring)
555 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
556 void PRVM_ED_Print(prvm_edict_t *ed)
564 char tempstring[8192], tempstring2[260]; // temporary string buffers
566 if (ed->priv.required->free)
568 Con_Printf("%s: FREE\n",PRVM_NAME);
573 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
574 for (i=1 ; i<prog->progs->numfielddefs ; i++)
576 d = &prog->fielddefs[i];
577 name = PRVM_GetString(d->s_name);
578 if (name[strlen(name)-2] == '_')
579 continue; // skip _x, _y, _z vars
581 v = (int *)((char *)ed->fields.vp + d->ofs*4);
583 // if the value is still all 0, skip the field
584 type = d->type & ~DEF_SAVEGLOBAL;
586 for (j=0 ; j<prvm_type_size[type] ; j++)
589 if (j == prvm_type_size[type])
592 if (strlen(name) > 256)
594 memcpy (tempstring2, name, 256);
595 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
596 tempstring2[259] = 0;
599 strcat(tempstring, name);
600 for (l = strlen(name);l < 14;l++)
601 strcat(tempstring, " ");
602 strcat(tempstring, " ");
604 name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
605 if (strlen(name) > 256)
607 memcpy (tempstring2, name, 256);
608 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
609 tempstring2[259] = 0;
612 strcat(tempstring, name);
613 strcat(tempstring, "\n");
614 if (strlen(tempstring) >= 4096)
616 Con_Print(tempstring);
621 Con_Print(tempstring);
631 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
641 if (ed->priv.required->free)
647 for (i=1 ; i<prog->progs->numfielddefs ; i++)
649 d = &prog->fielddefs[i];
650 name = PRVM_GetString(d->s_name);
651 if (name[strlen(name)-2] == '_')
652 continue; // skip _x, _y, _z vars
654 v = (int *)((char *)ed->fields.vp + d->ofs*4);
656 // if the value is still all 0, skip the field
657 type = d->type & ~DEF_SAVEGLOBAL;
658 for (j=0 ; j<prvm_type_size[type] ; j++)
661 if (j == prvm_type_size[type])
664 FS_Printf(f,"\"%s\" ",name);
665 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(d->type, (prvm_eval_t *)v));
671 void PRVM_ED_PrintNum (int ent)
673 PRVM_ED_Print(PRVM_EDICT_NUM(ent));
678 PRVM_ED_PrintEdicts_f
680 For debugging, prints all the entities in the current server
683 void PRVM_ED_PrintEdicts_f (void)
689 Con_Print("prvm_edicts <program name>\n");
694 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
697 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
698 for (i=0 ; i<prog->num_edicts ; i++)
699 PRVM_ED_PrintNum (i);
708 For debugging, prints a single edict
711 void PRVM_ED_PrintEdict_f (void)
717 Con_Print("prvm_edict <program name> <edict number>\n");
722 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
725 i = atoi (Cmd_Argv(2));
726 if (i >= prog->num_edicts)
728 Con_Print("Bad edict number\n");
732 PRVM_ED_PrintNum (i);
744 // 2 possibilities : 1. just displaying the active edict count
745 // 2. making a function pointer [x]
746 void PRVM_ED_Count_f (void)
754 Con_Print("prvm_count <program name>\n");
759 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
762 if(prog->count_edicts)
763 prog->count_edicts();
767 for (i=0 ; i<prog->num_edicts ; i++)
769 ent = PRVM_EDICT_NUM(i);
770 if (ent->priv.required->free)
775 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
776 Con_Printf("active :%3i\n", active);
783 ==============================================================================
787 FIXME: need to tag constants, doesn't really work
788 ==============================================================================
796 void PRVM_ED_WriteGlobals (qfile_t *f)
804 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
806 def = &prog->globaldefs[i];
808 if ( !(def->type & DEF_SAVEGLOBAL) )
810 type &= ~DEF_SAVEGLOBAL;
812 if (type != ev_string && type != ev_float && type != ev_entity)
815 name = PRVM_GetString(def->s_name);
816 FS_Printf(f,"\"%s\" ", name);
817 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
827 void PRVM_ED_ParseGlobals (const char *data)
829 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
835 if (!COM_ParseToken(&data, false))
836 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
837 if (com_token[0] == '}')
840 strcpy (keyname, com_token);
843 if (!COM_ParseToken(&data, false))
844 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
846 if (com_token[0] == '}')
847 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
849 key = PRVM_ED_FindGlobal (keyname);
852 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
856 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
857 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
861 //============================================================================
868 Can parse either fields or globals
869 returns false if error
872 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
881 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
883 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
884 switch (key->type & ~DEF_SAVEGLOBAL)
888 new_p = PRVM_AllocString(l);
889 val->string = PRVM_SetQCString(new_p);
890 for (i = 0;i < l;i++)
892 if (s[i] == '\\' && i < l-1)
897 else if (s[i] == 'r')
908 while (*s && *s <= ' ')
910 val->_float = atof(s);
914 for (i = 0;i < 3;i++)
916 while (*s && *s <= ' ')
920 val->vector[i] = atof(s);
929 while (*s && *s <= ' ')
932 if (i < 0 || i >= prog->limit_edicts)
933 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i) on %s\n", i, MAX_EDICTS, PRVM_NAME);
934 while (i >= prog->max_edicts)
935 PRVM_MEM_IncreaseEdicts();
936 //SV_IncreaseEdicts();
937 // if SV_IncreaseEdicts was called the base pointer needs to be updated
939 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
940 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(i));
944 def = PRVM_ED_FindField(s);
947 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
950 val->_int = def->ofs;
954 func = PRVM_ED_FindFunction(s);
957 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
960 val->function = func - prog->functions;
964 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
974 Console command to set a field of a specified edict
977 void PRVM_ED_EdictSet_f(void)
984 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
989 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
991 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
995 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
997 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
998 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1000 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1006 ====================
1009 Parses an edict out of the given string, returning the new position
1010 ed should be a properly initialized empty edict.
1011 Used for initial level load and for savegames.
1012 ====================
1014 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1024 // go through all the dictionary pairs
1028 if (!COM_ParseToken(&data, false))
1029 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1030 if (com_token[0] == '}')
1033 // anglehack is to allow QuakeEd to write single scalar angles
1034 // and allow them to be turned into vectors. (FIXME...)
1035 if (!strcmp(com_token, "angle"))
1037 strcpy (com_token, "angles");
1043 // FIXME: change light to _light to get rid of this hack
1044 if (!strcmp(com_token, "light"))
1045 strcpy (com_token, "light_lev"); // hack for single light def
1047 strcpy (keyname, com_token);
1049 // another hack to fix keynames with trailing spaces
1050 n = strlen(keyname);
1051 while (n && keyname[n-1] == ' ')
1058 if (!COM_ParseToken(&data, false))
1059 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1061 if (com_token[0] == '}')
1062 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
1066 // keynames with a leading underscore are used for utility comments,
1067 // and are immediately discarded by quake
1068 if (keyname[0] == '_')
1071 key = PRVM_ED_FindField (keyname);
1074 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1081 strcpy (temp, com_token);
1082 sprintf (com_token, "0 %s 0", temp);
1085 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1086 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1090 ent->priv.required->free = true;
1098 PRVM_ED_LoadFromFile
1100 The entities are directly placed in the array, rather than allocated with
1101 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1102 number references out of order.
1104 Creates a server's entity / program execution context by
1105 parsing textual entity definitions out of an ent file.
1107 Used for both fresh maps and savegame loads. A fresh map would also need
1108 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1111 void PRVM_ED_LoadFromFile (const char *data)
1114 int parsed, inhibited, spawned, died;
1126 // parse the opening brace
1127 if (!COM_ParseToken(&data, false))
1129 if (com_token[0] != '{')
1130 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1132 // CHANGED: this is not conform to PR_LoadFromFile
1133 if(prog->loadintoworld)
1135 prog->loadintoworld = false;
1136 ent = PRVM_EDICT_NUM(0);
1139 ent = PRVM_ED_Alloc();
1142 if (ent != prog->edicts) // hack
1143 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1145 data = PRVM_ED_ParseEdict (data, ent);
1148 // remove the entity ?
1149 if(prog->load_edict && !prog->load_edict(ent))
1157 // immediately call spawn function, but only if there is a self global and a classname
1159 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1161 string_t handle = *(string_t*)&((qbyte*)ent->fields.vp)[PRVM_ED_FindFieldOffset("classname")];
1164 Con_Print("No classname for:\n");
1170 // look for the spawn function
1171 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1175 if (developer.integer) // don't confuse non-developers with errors
1177 Con_Print("No spawn function for:\n");
1185 PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1186 PRVM_ExecuteProgram (func - prog->functions, "");
1190 if (ent->priv.required->free)
1194 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);
1199 typedef struct dpfield_s
1206 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1208 dpfield_t dpfields[] =
1219 void PRVM_ResetProg()
1221 PRVM_GCALL(reset_cmd)();
1222 Mem_FreePool(&prog->progs_mempool);
1223 memset(prog,0,sizeof(prvm_prog_t));
1231 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field)
1235 ddef_t *infielddefs;
1236 dfunction_t *dfunctions;
1238 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false);
1239 if (prog->progs == NULL)
1240 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1242 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, fs_filesize/1024);
1244 prog->filecrc = 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->headercrc)
1253 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1255 //prog->functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1256 dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
1258 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1259 prog->stringssize = 0;
1260 for (i = 0;i < prog->progs->numstrings;i++)
1262 if (prog->progs->ofs_strings + prog->stringssize >= fs_filesize)
1263 PRVM_ERROR ("%s: %s strings go past end of file\n", PRVM_NAME, filename);
1264 prog->stringssize += strlen (prog->strings + prog->stringssize) + 1;
1266 prog->numknownstrings = 0;
1267 prog->maxknownstrings = 0;
1268 prog->knownstrings = NULL;
1270 prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
1272 // we need to expand the fielddefs list to include all the engine fields,
1273 // so allocate a new place for it
1274 infielddefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_fielddefs);
1276 prog->fielddefs = Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1278 prog->statements = (dstatement_t *)((qbyte *)prog->progs + prog->progs->ofs_statements);
1280 // moved edict_size calculation down below field adding code
1282 //pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1283 prog->globals.generic = (float *)((qbyte *)prog->progs + prog->progs->ofs_globals);
1285 // byte swap the lumps
1286 for (i=0 ; i<prog->progs->numstatements ; i++)
1288 prog->statements[i].op = LittleShort(prog->statements[i].op);
1289 prog->statements[i].a = LittleShort(prog->statements[i].a);
1290 prog->statements[i].b = LittleShort(prog->statements[i].b);
1291 prog->statements[i].c = LittleShort(prog->statements[i].c);
1294 prog->functions = Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1295 for (i = 0;i < prog->progs->numfunctions;i++)
1297 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1298 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1299 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1300 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1301 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1302 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1303 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1306 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1308 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1309 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1310 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1313 // copy the progs fields to the new fields list
1314 for (i = 0;i < prog->progs->numfielddefs;i++)
1316 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1317 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1318 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1319 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1320 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1323 // append the required fields
1324 for (i = 0;i < (int) numrequiredfields;i++)
1326 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1327 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1328 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1329 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1330 prog->progs->entityfields += 3;
1332 prog->progs->entityfields++;
1333 prog->progs->numfielddefs++;
1336 // check required functions
1337 for(i=0 ; i < numrequiredfunc ; i++)
1338 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1339 PRVM_ERROR("%s: %s not found in %s\n",PRVM_NAME, required_func[i], filename);
1341 for (i=0 ; i<prog->progs->numglobals ; i++)
1342 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1344 // moved edict_size calculation down here, below field adding code
1345 // LordHavoc: this no longer includes the prvm_edict_t header
1346 prog->edict_size = prog->progs->entityfields * 4;
1347 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1349 // LordHavoc: bounds check anything static
1350 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1356 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1357 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s\n", i, PRVM_NAME);
1360 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1361 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s\n", i, PRVM_NAME);
1363 // global global global
1398 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1399 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n", i);
1401 // global none global
1407 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1408 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1424 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1425 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n in %s", i, PRVM_NAME);
1439 if ((unsigned short) st->a >= prog->progs->numglobals)
1440 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1443 PRVM_ERROR("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1450 prog->loaded = TRUE;
1452 // set flags & ddef_ts in prog
1456 prog->self = PRVM_ED_FindGlobal("self");
1458 if( PRVM_ED_FindGlobal("time") && PRVM_ED_FindGlobal("time")->type & ev_float )
1459 prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs);
1461 if(PRVM_ED_FindField ("chain"))
1462 prog->flag |= PRVM_FE_CHAIN;
1464 if(PRVM_ED_FindField ("classname"))
1465 prog->flag |= PRVM_FE_CLASSNAME;
1467 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1468 && prog->flag && prog->self)
1469 prog->flag |= PRVM_OP_STATE;
1471 PRVM_GCALL(init_cmd)();
1478 void PRVM_Fields_f (void)
1480 int i, j, ednum, used, usedamount;
1482 char tempstring[5000], tempstring2[260];
1492 Con_Print("no progs loaded\n");
1499 Con_Print("prvm_fields <program name>\n");
1504 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1507 counts = Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1508 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1510 ed = PRVM_EDICT_NUM(ednum);
1511 if (ed->priv.required->free)
1513 for (i = 1;i < prog->progs->numfielddefs;i++)
1515 d = &prog->fielddefs[i];
1516 name = PRVM_GetString(d->s_name);
1517 if (name[strlen(name)-2] == '_')
1518 continue; // skip _x, _y, _z vars
1519 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1520 // if the value is still all 0, skip the field
1521 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1534 for (i = 0;i < prog->progs->numfielddefs;i++)
1536 d = &prog->fielddefs[i];
1537 name = PRVM_GetString(d->s_name);
1538 if (name[strlen(name)-2] == '_')
1539 continue; // skip _x, _y, _z vars
1540 switch(d->type & ~DEF_SAVEGLOBAL)
1543 strcat(tempstring, "string ");
1546 strcat(tempstring, "entity ");
1549 strcat(tempstring, "function ");
1552 strcat(tempstring, "field ");
1555 strcat(tempstring, "void ");
1558 strcat(tempstring, "float ");
1561 strcat(tempstring, "vector ");
1564 strcat(tempstring, "pointer ");
1567 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1568 strcat(tempstring, tempstring2);
1571 if (strlen(name) > 256)
1573 memcpy (tempstring2, name, 256);
1574 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1575 tempstring2[259] = 0;
1578 strcat(tempstring, name);
1579 for (j = strlen(name);j < 25;j++)
1580 strcat(tempstring, " ");
1581 sprintf(tempstring2, "%5d", counts[i]);
1582 strcat(tempstring, tempstring2);
1583 strcat(tempstring, "\n");
1584 if (strlen(tempstring) >= 4096)
1586 Con_Print(tempstring);
1592 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1596 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);
1601 void PRVM_Globals_f (void)
1607 Con_Print("no progs loaded\n");
1610 if(Cmd_Argc () != 2)
1612 Con_Print("prvm_globals <program name>\n");
1617 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1620 Con_Printf("%s :", PRVM_NAME);
1622 for (i = 0;i < prog->progs->numglobaldefs;i++)
1623 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1624 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1634 void PRVM_Global_f(void)
1637 if( Cmd_Argc() != 3 ) {
1638 Con_Printf( "prvm_global <program name> <global name>\n" );
1643 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1646 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1648 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1650 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1659 void PRVM_GlobalSet_f(void)
1662 if( Cmd_Argc() != 4 ) {
1663 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1668 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1671 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1673 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1675 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1684 void PRVM_Init (void)
1686 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f);
1687 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f);
1688 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f);
1689 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
1690 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
1691 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
1692 Cmd_AddCommand ("prvm_global", PRVM_Global_f);
1693 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f);
1694 Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f);
1695 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1696 Cvar_RegisterVariable (&prvm_boundscheck);
1697 Cvar_RegisterVariable (&prvm_traceqc);
1707 void PRVM_InitProg(int prognr)
1709 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1710 Sys_Error("PRVM_InitProg: Invalid program number %i\n",prognr);
1712 prog = &prog_list[prognr];
1717 memset(prog, 0, sizeof(prvm_prog_t));
1719 prog->time = &prog->_time;
1722 int PRVM_GetProgNr()
1724 return prog - prog_list;
1727 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1729 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1732 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1734 _Mem_Free(buffer, filename, fileline);
1737 void _PRVM_FreeAll(const char *filename, int fileline)
1740 prog->fielddefs = NULL;
1741 prog->functions = NULL;
1742 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1745 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1746 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1748 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1752 void PRVM_ProcessError(void)
1755 PRVM_GCALL(error_cmd)();
1759 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1761 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1765 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1768 n = e - prog->edicts;
1769 if ((unsigned int)n >= prog->limit_edicts)
1770 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1774 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1776 // return e - prog->edicts;
1779 //#define PRVM_EDICT_TO_PROG(e) ((qbyte *)(((prvm_edict_t *)e)->v) - (qbyte *)(prog->edictsfields))
1780 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1781 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1784 n = e - prog->edicts;
1785 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1786 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, prog->edicts);
1787 return n;// EXPERIMENTAL
1788 //return (qbyte *)e->v - (qbyte *)prog->edictsfields;
1790 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
1792 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1793 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i\n", n);
1794 return prog->edicts + n; // EXPERIMENTAL
1795 //return prog->edicts + ((n) / (progs->entityfields * 4));
1800 const char *PRVM_GetString(int num)
1802 if (num >= 0 && num < prog->stringssize)
1803 return prog->strings + num;
1804 else if (num < 0 && num >= -prog->numknownstrings)
1807 if (!prog->knownstrings[num])
1808 Host_Error("PRVM_GetString: attempt to get string that is already freed\n");
1809 return prog->knownstrings[num];
1813 Host_Error("PRVM_GetString: invalid string offset %i\n", num);
1818 int PRVM_SetQCString(const char *s)
1823 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1824 return s - prog->strings;
1825 for (i = 0;i < prog->numknownstrings;i++)
1826 if (prog->knownstrings[i] == s)
1828 Host_Error("PRVM_SetQCString: unknown string\n");
1832 int PRVM_SetEngineString(const char *s)
1837 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1838 Host_Error("PRVM_SetEngineString: s in prog->strings area\n");
1839 for (i = 0;i < prog->numknownstrings;i++)
1840 if (prog->knownstrings[i] == s)
1842 // new unknown engine string
1843 if (developer.integer >= 3)
1844 Con_Printf("new engine string %p\n", s);
1845 for (i = 0;i < prog->numknownstrings;i++)
1846 if (!prog->knownstrings[i])
1848 if (i >= prog->numknownstrings)
1850 if (i >= prog->maxknownstrings)
1852 const char **oldstrings = prog->knownstrings;
1853 prog->maxknownstrings += 128;
1854 prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
1855 if (prog->numknownstrings)
1856 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
1858 prog->numknownstrings++;
1860 prog->knownstrings[i] = s;
1864 char *PRVM_AllocString(int bufferlength)
1869 for (i = 0;i < prog->numknownstrings;i++)
1870 if (!prog->knownstrings[i])
1872 if (i >= prog->numknownstrings)
1874 if (i >= prog->maxknownstrings)
1876 const char **oldstrings = prog->knownstrings;
1877 prog->maxknownstrings += 128;
1878 prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
1879 if (prog->numknownstrings)
1880 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
1882 prog->numknownstrings++;
1884 return (char *)(prog->knownstrings[i] = PRVM_Alloc(bufferlength));
1887 void PRVM_FreeString(char *s)
1891 Host_Error("PRVM_FreeString: attempt to free a NULL string\n");
1892 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1893 Host_Error("PRVM_FreeString: attempt to free a constant string\n");
1894 for (i = 0;i < prog->numknownstrings;i++)
1895 if (prog->knownstrings[i] == s)
1897 if (i == prog->numknownstrings)
1898 Host_Error("PRVM_FreeString: attempt to free a non-existent or already freed string\n");
1899 PRVM_Free((char *)prog->knownstrings[i]);
1900 prog->knownstrings[i] = NULL;