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 ddef_t *PRVM_ED_FindField (const char *name);
40 mfunction_t *PRVM_ED_FindFunction (const char *name);
42 //============================================================================
54 // reserve space for the null entity aka world
55 // check bound of max_edicts
56 prog->max_edicts = bound(1, prog->max_edicts, prog->limit_edicts);
57 prog->num_edicts = bound(1, prog->num_edicts, prog->max_edicts);
59 // edictprivate_size has to be min as big prvm_edict_private_t
60 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
63 prog->edicts = Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
65 // alloc edict private space
66 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
69 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
72 for(i = 0; i < prog->max_edicts; i++)
74 prog->edicts[i].priv.required = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
75 prog->edicts[i].fields.vp = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
81 PRVM_MEM_IncreaseEdicts
84 void PRVM_MEM_IncreaseEdicts()
87 int oldmaxedicts = prog->max_edicts;
88 void *oldedictsfields = prog->edictsfields;
89 void *oldedictprivate = prog->edictprivate;
91 if(prog->max_edicts >= prog->limit_edicts)
94 PRVM_GCALL(begin_increase_edicts)();
97 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
99 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
100 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
102 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
103 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
105 //set e and v pointers
106 for(i = 0; i < prog->max_edicts; i++)
108 prog->edicts[i].priv.required = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
109 prog->edicts[i].fields.vp = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
112 PRVM_GCALL(end_increase_edicts)();
114 Mem_Free(oldedictsfields);
115 Mem_Free(oldedictprivate);
118 //============================================================================
121 int PRVM_ED_FindFieldOffset(const char *field)
124 d = PRVM_ED_FindField(field);
130 qboolean PRVM_ProgLoaded(int prognr)
132 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
135 return (prog_list[prognr].loaded ? TRUE : FALSE);
140 PRVM_SetProgFromString
143 // perhaps add a return value when the str doesnt exist
144 qboolean PRVM_SetProgFromString(const char *str)
147 for(; i < PRVM_MAXPROGS ; i++)
148 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
150 if(prog_list[i].loaded)
152 prog = &prog_list[i];
157 Con_Printf("%s not loaded !\n",PRVM_NAME);
162 Con_Printf("Invalid program name %s !\n", str);
171 void PRVM_SetProg(int prognr)
173 if(prognr && prognr < PRVM_MAXPROGS)
175 if(prog_list[prognr].loaded)
176 prog = &prog_list[prognr];
178 PRVM_ERROR("%i(%s) not loaded !\n", prognr, PRVM_NAME);
181 PRVM_ERROR("Invalid program number %i\n", prognr);
188 Sets everything to NULL
191 void PRVM_ED_ClearEdict (prvm_edict_t *e)
194 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
195 e->priv.required->free = false;
196 // LordHavoc: for consistency set these here
197 num = PRVM_NUM_FOR_EDICT(e) - 1;
199 // AK: Let the init_edict function determine if something needs to be initialized
200 PRVM_GCALL(init_edict)(num);
207 Either finds a free edict, or allocates a new one.
208 Try to avoid reusing an entity that was recently freed, because it
209 can cause the client to think the entity morphed into something else
210 instead of being removed and recreated, which can cause interpolated
211 angles and bad trails.
214 prvm_edict_t *PRVM_ED_Alloc (void)
219 // the client qc dont need maxclients
220 // thus it doesnt need to use svs.maxclients
221 // AK: changed i=svs.maxclients+1
222 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
223 // although the menu/client has no world
224 for (i = 1;i < prog->num_edicts;i++)
226 e = PRVM_EDICT_NUM(i);
227 // the first couple seconds of server time can involve a lot of
228 // freeing and allocating, so relax the replacement policy
229 if (e->priv.required->free && ( e->priv.required->freetime < 2 || (*prog->time - e->priv.required->freetime) > 0.5 ) )
231 PRVM_ED_ClearEdict (e);
237 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
240 if (prog->num_edicts >= prog->max_edicts)
241 PRVM_MEM_IncreaseEdicts();
243 e = PRVM_EDICT_NUM(i);
244 PRVM_ED_ClearEdict (e);
253 Marks the edict as free
254 FIXME: walk all entities and NULL out references to this entity
257 void PRVM_ED_Free (prvm_edict_t *ed)
259 // dont delete the null entity (world)
260 if(PRVM_NUM_FOR_EDICT(ed) == 0)
263 PRVM_GCALL(free_edict)(ed);
265 ed->priv.required->free = true;
266 ed->priv.required->freetime = *prog->time;
269 //===========================================================================
276 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
281 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
283 def = &prog->globaldefs[i];
295 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
300 for (i=0 ; i<prog->progs->numfielddefs ; i++)
302 def = &prog->fielddefs[i];
314 ddef_t *PRVM_ED_FindField (const char *name)
319 for (i=0 ; i<prog->progs->numfielddefs ; i++)
321 def = &prog->fielddefs[i];
322 if (!strcmp(PRVM_GetString(def->s_name), name))
333 ddef_t *PRVM_ED_FindGlobal (const char *name)
338 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
340 def = &prog->globaldefs[i];
341 if (!strcmp(PRVM_GetString(def->s_name), name))
353 mfunction_t *PRVM_ED_FindFunction (const char *name)
358 for (i=0 ; i<prog->progs->numfunctions ; i++)
360 func = &prog->functions[i];
361 if (!strcmp(PRVM_GetString(func->s_name), name))
372 Returns a string describing *data in a type specific manner
375 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
377 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
382 type &= ~DEF_SAVEGLOBAL;
387 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
391 if (n < 0 || n >= MAX_EDICTS)
392 sprintf (line, "entity %i (invalid!)", n);
394 sprintf (line, "entity %i", n);
397 f = prog->functions + val->function;
398 sprintf (line, "%s()", PRVM_GetString(f->s_name));
401 def = PRVM_ED_FieldAtOfs ( val->_int );
402 sprintf (line, ".%s", PRVM_GetString(def->s_name));
405 sprintf (line, "void");
408 // LordHavoc: changed from %5.1f to %10.4f
409 sprintf (line, "%10.4f", val->_float);
412 // LordHavoc: changed from %5.1f to %10.4f
413 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
416 sprintf (line, "pointer");
419 sprintf (line, "bad type %i", type);
430 Returns a string describing *data in a type specific manner
431 Easier to parse than PR_ValueString
434 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
436 static char line[4096];
442 type &= ~DEF_SAVEGLOBAL;
447 // Parse the string a bit to turn special characters
448 // (like newline, specifically) into escape codes,
449 // this fixes saving games from various mods
450 s = PRVM_GetString (val->string);
451 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
470 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
473 f = pr_functions + val->function;
474 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
477 def = PRVM_ED_FieldAtOfs ( val->_int );
478 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
481 dpsnprintf (line, sizeof (line), "void");
484 dpsnprintf (line, sizeof (line), "%f", val->_float);
487 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
490 dpsnprintf (line, sizeof (line), "bad type %i", type);
501 Returns a string with a description and the contents of a global,
502 padded to 20 field width
505 char *PRVM_GlobalString (int ofs)
511 static char line[128];
513 val = (void *)&prog->globals[ofs];
514 def = PRVM_ED_GlobalAtOfs(ofs);
516 sprintf (line,"%i(?)", ofs);
519 s = PRVM_ValueString (def->type, val);
520 sprintf (line,"%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
531 char *PRVM_GlobalStringNoContents (int ofs)
535 static char line[128];
537 def = PRVM_ED_GlobalAtOfs(ofs);
539 sprintf (line,"%i(?)", ofs);
541 sprintf (line,"%i(%s)", ofs, PRVM_GetString(def->s_name));
559 // LordHavoc: optimized this to print out much more quickly (tempstring)
560 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
561 void PRVM_ED_Print(prvm_edict_t *ed)
569 char tempstring[8192], tempstring2[260]; // temporary string buffers
571 if (ed->priv.required->free)
573 Con_Printf("%s: FREE\n",PRVM_NAME);
578 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
579 for (i=1 ; i<prog->progs->numfielddefs ; i++)
581 d = &prog->fielddefs[i];
582 name = PRVM_GetString(d->s_name);
583 if (name[strlen(name)-2] == '_')
584 continue; // skip _x, _y, _z vars
586 v = (int *)((char *)ed->fields.vp + d->ofs*4);
588 // if the value is still all 0, skip the field
589 type = d->type & ~DEF_SAVEGLOBAL;
591 for (j=0 ; j<prvm_type_size[type] ; j++)
594 if (j == prvm_type_size[type])
597 if (strlen(name) > 256)
599 memcpy (tempstring2, name, 256);
600 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
601 tempstring2[259] = 0;
604 strcat(tempstring, name);
605 for (l = strlen(name);l < 14;l++)
606 strcat(tempstring, " ");
607 strcat(tempstring, " ");
609 name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
610 if (strlen(name) > 256)
612 memcpy (tempstring2, name, 256);
613 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
614 tempstring2[259] = 0;
617 strcat(tempstring, name);
618 strcat(tempstring, "\n");
619 if (strlen(tempstring) >= 4096)
621 Con_Print(tempstring);
626 Con_Print(tempstring);
636 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
646 if (ed->priv.required->free)
652 for (i=1 ; i<prog->progs->numfielddefs ; i++)
654 d = &prog->fielddefs[i];
655 name = PRVM_GetString(d->s_name);
656 if (name[strlen(name)-2] == '_')
657 continue; // skip _x, _y, _z vars
659 v = (int *)((char *)ed->fields.vp + d->ofs*4);
661 // if the value is still all 0, skip the field
662 type = d->type & ~DEF_SAVEGLOBAL;
663 for (j=0 ; j<prvm_type_size[type] ; j++)
666 if (j == prvm_type_size[type])
669 FS_Printf(f,"\"%s\" ",name);
670 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(d->type, (prvm_eval_t *)v));
676 void PRVM_ED_PrintNum (int ent)
678 PRVM_ED_Print(PRVM_EDICT_NUM(ent));
683 PRVM_ED_PrintEdicts_f
685 For debugging, prints all the entities in the current server
688 void PRVM_ED_PrintEdicts_f (void)
694 Con_Print("prvm_edicts <program name>\n");
699 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
702 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
703 for (i=0 ; i<prog->num_edicts ; i++)
704 PRVM_ED_PrintNum (i);
713 For debugging, prints a single edict
716 void PRVM_ED_PrintEdict_f (void)
722 Con_Print("prvm_edict <program name> <edict number>\n");
727 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
730 i = atoi (Cmd_Argv(2));
731 if (i >= prog->num_edicts)
733 Con_Print("Bad edict number\n");
737 PRVM_ED_PrintNum (i);
749 // 2 possibilities : 1. just displaying the active edict count
750 // 2. making a function pointer [x]
751 void PRVM_ED_Count_f (void)
759 Con_Print("prvm_count <program name>\n");
764 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
767 if(prog->count_edicts)
768 prog->count_edicts();
772 for (i=0 ; i<prog->num_edicts ; i++)
774 ent = PRVM_EDICT_NUM(i);
775 if (ent->priv.required->free)
780 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
781 Con_Printf("active :%3i\n", active);
788 ==============================================================================
792 FIXME: need to tag constants, doesn't really work
793 ==============================================================================
801 void PRVM_ED_WriteGlobals (qfile_t *f)
809 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
811 def = &prog->globaldefs[i];
813 if ( !(def->type & DEF_SAVEGLOBAL) )
815 type &= ~DEF_SAVEGLOBAL;
817 if (type != ev_string && type != ev_float && type != ev_entity)
820 name = PRVM_GetString(def->s_name);
821 FS_Printf(f,"\"%s\" ", name);
822 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(type, (prvm_eval_t *)&prog->globals[def->ofs]));
832 void PRVM_ED_ParseGlobals (const char *data)
834 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
840 if (!COM_ParseToken(&data, false))
841 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
842 if (com_token[0] == '}')
845 strcpy (keyname, com_token);
848 if (!COM_ParseToken(&data, false))
849 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
851 if (com_token[0] == '}')
852 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
854 key = PRVM_ED_FindGlobal (keyname);
857 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
861 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
862 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
866 //============================================================================
873 Can parse either fields or globals
874 returns false if error
877 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
886 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
888 val = (prvm_eval_t *)((int *)prog->globals + key->ofs);
889 switch (key->type & ~DEF_SAVEGLOBAL)
893 new_p = PRVM_AllocString(l);
894 val->string = PRVM_SetQCString(new_p);
895 for (i = 0;i < l;i++)
897 if (s[i] == '\\' && i < l-1)
902 else if (s[i] == 'r')
913 while (*s && *s <= ' ')
915 val->_float = atof(s);
919 for (i = 0;i < 3;i++)
921 while (*s && *s <= ' ')
925 val->vector[i] = atof(s);
934 while (*s && *s <= ' ')
937 if (i < 0 || i >= MAX_EDICTS)
938 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i) on %s\n", i, MAX_EDICTS, PRVM_NAME);
939 while (i >= prog->max_edicts)
940 PRVM_MEM_IncreaseEdicts();
941 //SV_IncreaseEdicts();
942 // if SV_IncreaseEdicts was called the base pointer needs to be updated
944 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
945 val->edict = PRVM_EDICT_TO_PROG(EDICT_NUM(i));
949 def = PRVM_ED_FindField(s);
952 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
955 val->_int = def->ofs;
959 func = PRVM_ED_FindFunction(s);
962 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
965 val->function = func - prog->functions;
969 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PR_GetString(key->s_name), PRVM_NAME);
979 Console command to set a field of a specified edict
982 void PRVM_ED_EdictSet_f(void)
989 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
994 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
996 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1000 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1002 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1003 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1005 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1011 ====================
1014 Parses an edict out of the given string, returning the new position
1015 ed should be a properly initialized empty edict.
1016 Used for initial level load and for savegames.
1017 ====================
1019 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1029 // go through all the dictionary pairs
1033 if (!COM_ParseToken(&data, false))
1034 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1035 if (com_token[0] == '}')
1038 // anglehack is to allow QuakeEd to write single scalar angles
1039 // and allow them to be turned into vectors. (FIXME...)
1040 if (!strcmp(com_token, "angle"))
1042 strcpy (com_token, "angles");
1048 // FIXME: change light to _light to get rid of this hack
1049 if (!strcmp(com_token, "light"))
1050 strcpy (com_token, "light_lev"); // hack for single light def
1052 strcpy (keyname, com_token);
1054 // another hack to fix keynames with trailing spaces
1055 n = strlen(keyname);
1056 while (n && keyname[n-1] == ' ')
1063 if (!COM_ParseToken(&data, false))
1064 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1066 if (com_token[0] == '}')
1067 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
1071 // keynames with a leading underscore are used for utility comments,
1072 // and are immediately discarded by quake
1073 if (keyname[0] == '_')
1076 key = PRVM_ED_FindField (keyname);
1079 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1086 strcpy (temp, com_token);
1087 sprintf (com_token, "0 %s 0", temp);
1090 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1091 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1095 ent->priv.required->free = true;
1103 PRVM_ED_LoadFromFile
1105 The entities are directly placed in the array, rather than allocated with
1106 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1107 number references out of order.
1109 Creates a server's entity / program execution context by
1110 parsing textual entity definitions out of an ent file.
1112 Used for both fresh maps and savegame loads. A fresh map would also need
1113 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1116 void PRVM_ED_LoadFromFile (const char *data)
1119 int parsed, inhibited, spawned, died;
1131 // parse the opening brace
1132 if (!COM_ParseToken(&data, false))
1134 if (com_token[0] != '{')
1135 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1137 // CHANGED: this is not conform to ED_LoadFromFile
1138 if(!prog->num_edicts)
1139 ent = PRVM_EDICT_NUM(0);
1141 ent = PRVM_ED_Alloc();
1144 if (ent != prog->edicts) // hack
1145 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1147 data = PRVM_ED_ParseEdict (data, ent);
1150 // remove the entity ?
1151 if(prog->load_edict && !prog->load_edict(ent))
1159 // immediately call spawn function, but only if there is a self global and a classname
1161 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1163 string_t handle = *(string_t*)&((float*)ent->fields.vp)[PRVM_ED_FindFieldOffset("classname")];
1166 Con_Print("No classname for:\n");
1172 // look for the spawn function
1173 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1177 if (developer.integer) // don't confuse non-developers with errors
1179 Con_Print("No spawn function for:\n");
1187 PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1188 PRVM_ExecuteProgram (func - prog->functions, "");
1192 if (ent->priv.required->free)
1196 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);
1201 typedef struct dpfield_s
1208 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1210 dpfield_t dpfields[] =
1221 void PRVM_ResetProg()
1223 PRVM_GCALL(reset_cmd)();
1224 Mem_FreePool(&prog->progs_mempool);
1225 memset(prog,0,sizeof(prvm_prog_t));
1233 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func)
1237 ddef_t *infielddefs;
1238 dfunction_t *dfunctions;
1240 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false);
1241 if (prog->progs == NULL)
1242 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1244 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, fs_filesize/1024);
1246 pr_crc = CRC_Block((qbyte *)prog->progs, fs_filesize);
1248 // byte swap the header
1249 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1250 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1252 if (prog->progs->version != PROG_VERSION)
1253 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1254 if (prog->progs->crc != prog->crc)
1255 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1257 //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1258 dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
1260 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1261 prog->stringssize = 0;
1262 for (i = 0;i < prog->progs->numstrings;i++)
1264 if (prog->progs->ofs_strings + prog->stringssize >= fs_filesize)
1265 PRVM_ERROR ("%s: %s strings go past end of file\n", PRVM_NAME, filename);
1266 prog->stringssize += strlen (prog->strings + prog->stringssize) + 1;
1268 prog->numknownstrings = 0;
1269 prog->maxknownstrings = 0;
1270 prog->knownstrings = NULL;
1272 prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
1274 // we need to expand the fielddefs list to include all the engine fields,
1275 // so allocate a new place for it
1276 infielddefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_fielddefs);
1278 prog->fielddefs = Mem_Alloc(prog->progs_mempool, prog->progs->numfielddefs * sizeof(ddef_t));
1280 prog->statements = (dstatement_t *)((qbyte *)prog->progs + prog->progs->ofs_statements);
1282 // moved edict_size calculation down below field adding code
1284 //pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1285 prog->globals = (float *)((qbyte *)prog->progs + prog->progs->ofs_globals);
1287 // byte swap the lumps
1288 for (i=0 ; i<prog->progs->numstatements ; i++)
1290 prog->statements[i].op = LittleShort(prog->statements[i].op);
1291 prog->statements[i].a = LittleShort(prog->statements[i].a);
1292 prog->statements[i].b = LittleShort(prog->statements[i].b);
1293 prog->statements[i].c = LittleShort(prog->statements[i].c);
1296 prog->functions = Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1297 for (i = 0;i < prog->progs->numfunctions;i++)
1299 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1300 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1301 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1302 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1303 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1304 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1305 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1308 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1310 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1311 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1312 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1315 // copy the progs fields to the new fields list
1316 for (i = 0;i < prog->progs->numfielddefs;i++)
1318 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1319 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1320 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1321 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1322 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1325 /* // append the darkplaces fields
1326 for (i = 0;i < (int) DPFIELDS;i++)
1328 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1329 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1330 pr_fielddefs[progs->numfielddefs].s_name = PR_SetEngineString(dpfields[i].string);
1331 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1332 progs->entityfields += 3;
1334 progs->entityfields++;
1335 progs->numfielddefs++;
1338 // check required functions
1339 for(i=0 ; i < numrequiredfunc ; i++)
1340 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1341 PRVM_ERROR("%s: %s not found in %s\n",PRVM_NAME, required_func[i], filename);
1343 for (i=0 ; i<prog->progs->numglobals ; i++)
1344 ((int *)prog->globals)[i] = LittleLong (((int *)prog->globals)[i]);
1346 // moved edict_size calculation down here, below field adding code
1347 // LordHavoc: this no longer includes the edict_t header
1348 prog->edict_size = prog->progs->entityfields * 4;
1349 prog->edictareasize = prog->edict_size * MAX_EDICTS;
1351 // LordHavoc: bounds check anything static
1352 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1358 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1359 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s\n", i, PRVM_NAME);
1362 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1363 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s\n", i, PRVM_NAME);
1365 // global global global
1400 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1401 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n", i);
1403 // global none global
1409 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1410 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1426 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1427 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n in %s", i, PRVM_NAME);
1441 if ((unsigned short) st->a >= prog->progs->numglobals)
1442 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1445 PRVM_ERROR("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1452 prog->loaded = TRUE;
1454 // set flags & ddef_ts in prog
1458 prog->self = PRVM_ED_FindGlobal("self");
1460 if( PRVM_ED_FindGlobal("time") && PRVM_ED_FindGlobal("time")->type & ev_float )
1461 prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs);
1463 if(PRVM_ED_FindField ("chain"))
1464 prog->flag |= PRVM_FE_CHAIN;
1466 if(PRVM_ED_FindField ("classname"))
1467 prog->flag |= PRVM_FE_CLASSNAME;
1469 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1470 && prog->flag && prog->self)
1471 prog->flag |= PRVM_OP_STATE;
1473 PRVM_GCALL(init_cmd)();
1480 void PRVM_Fields_f (void)
1482 int i, j, ednum, used, usedamount;
1484 char tempstring[5000], tempstring2[260];
1494 Con_Print("no progs loaded\n");
1501 Con_Print("prvm_fields <program name>\n");
1506 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1509 counts = Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1510 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1512 ed = PRVM_EDICT_NUM(ednum);
1513 if (ed->priv.required->free)
1515 for (i = 1;i < prog->progs->numfielddefs;i++)
1517 d = &prog->fielddefs[i];
1518 name = PRVM_GetString(d->s_name);
1519 if (name[strlen(name)-2] == '_')
1520 continue; // skip _x, _y, _z vars
1521 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1522 // if the value is still all 0, skip the field
1523 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1536 for (i = 0;i < prog->progs->numfielddefs;i++)
1538 d = &prog->fielddefs[i];
1539 name = PRVM_GetString(d->s_name);
1540 if (name[strlen(name)-2] == '_')
1541 continue; // skip _x, _y, _z vars
1542 switch(d->type & ~DEF_SAVEGLOBAL)
1545 strcat(tempstring, "string ");
1548 strcat(tempstring, "entity ");
1551 strcat(tempstring, "function ");
1554 strcat(tempstring, "field ");
1557 strcat(tempstring, "void ");
1560 strcat(tempstring, "float ");
1563 strcat(tempstring, "vector ");
1566 strcat(tempstring, "pointer ");
1569 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1570 strcat(tempstring, tempstring2);
1573 if (strlen(name) > 256)
1575 memcpy (tempstring2, name, 256);
1576 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1577 tempstring2[259] = 0;
1580 strcat(tempstring, name);
1581 for (j = strlen(name);j < 25;j++)
1582 strcat(tempstring, " ");
1583 sprintf(tempstring2, "%5d", counts[i]);
1584 strcat(tempstring, tempstring2);
1585 strcat(tempstring, "\n");
1586 if (strlen(tempstring) >= 4096)
1588 Con_Print(tempstring);
1594 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1598 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);
1603 void PRVM_Globals_f (void)
1609 Con_Print("no progs loaded\n");
1612 if(Cmd_Argc () != 2)
1614 Con_Print("prvm_globals <program name>\n");
1619 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1622 Con_Printf("%s :", PRVM_NAME);
1624 for (i = 0;i < prog->progs->numglobaldefs;i++)
1625 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1626 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1636 void PRVM_Global_f(void)
1639 if( Cmd_Argc() != 3 ) {
1640 Con_Printf( "prvm_global <program name> <global name>\n" );
1645 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1648 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1650 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1652 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( global->type, (prvm_eval_t *) &prog->globals[ global->ofs ] ) );
1661 void PRVM_GlobalSet_f(void)
1664 if( Cmd_Argc() != 4 ) {
1665 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1670 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1673 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1675 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1677 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1686 void PRVM_Init (void)
1688 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f);
1689 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f);
1690 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f);
1691 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
1692 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
1693 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
1694 Cmd_AddCommand ("prvm_global", PRVM_Global_f);
1695 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f);
1696 Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f);
1697 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1698 Cvar_RegisterVariable (&prvm_boundscheck);
1699 Cvar_RegisterVariable (&prvm_traceqc);
1709 void PRVM_InitProg(int prognr)
1711 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1712 Sys_Error("PRVM_InitProg: Invalid program number %i\n",prognr);
1714 prog = &prog_list[prognr];
1719 memset(prog, 0, sizeof(prvm_prog_t));
1721 prog->time = &prog->_time;
1724 int PRVM_GetProgNr()
1726 return prog - prog_list;
1729 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1731 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1734 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1736 _Mem_Free(buffer, filename, fileline);
1739 void _PRVM_FreeAll(const char *filename, int fileline)
1742 prog->fielddefs = NULL;
1743 prog->functions = NULL;
1744 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1747 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1748 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1750 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1754 void PRVM_ProcessError(void)
1757 PRVM_GCALL(error_cmd)();
1761 int NUM_FOR_EDICT_ERROR(edict_t *e)
1763 Host_Error ("NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, sv.edicts, e - sv.edicts);
1767 int NUM_FOR_EDICT(edict_t *e)
1771 if ((unsigned int)n >= MAX_EDICTS)
1772 Host_Error ("NUM_FOR_EDICT: bad pointer");
1776 //int NoCrash_NUM_FOR_EDICT(edict_t *e)
1778 // return e - sv.edicts;
1781 //#define EDICT_TO_PROG(e) ((qbyte *)(((edict_t *)e)->v) - (qbyte *)(sv.edictsfields))
1782 //#define PROG_TO_EDICT(e) (sv.edicts + ((e) / (progs->entityfields * 4)))
1783 int EDICT_TO_PROG(edict_t *e)
1787 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1788 Host_Error("EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, sv.edicts);
1789 return n;// EXPERIMENTAL
1790 //return (qbyte *)e->v - (qbyte *)sv.edictsfields;
1792 edict_t *PROG_TO_EDICT(int n)
1794 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1795 Host_Error("PROG_TO_EDICT: invalid edict number %i\n", n);
1796 return sv.edicts + n; // EXPERIMENTAL
1797 //return sv.edicts + ((n) / (progs->entityfields * 4));
1802 const char *PRVM_GetString(int num)
1804 if (num >= 0 && num < prog->stringssize)
1805 return prog->strings + num;
1806 else if (num < 0 && num >= -prog->numknownstrings)
1809 if (!prog->knownstrings[num])
1810 Host_Error("PRVM_GetString: attempt to get string that is already freed\n");
1811 return prog->knownstrings[num];
1815 Host_Error("PRVM_GetString: invalid string offset %i\n", num);
1820 int PRVM_SetQCString(const char *s)
1825 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1826 return s - prog->strings;
1827 for (i = 0;i < prog->numknownstrings;i++)
1828 if (prog->knownstrings[i] == s)
1830 Host_Error("PRVM_SetQCString: unknown string\n");
1834 int PRVM_SetEngineString(const char *s)
1839 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1840 Host_Error("PRVM_SetEngineString: s in prog->strings area\n");
1841 for (i = 0;i < prog->numknownstrings;i++)
1842 if (prog->knownstrings[i] == s)
1844 // new unknown engine string
1845 if (developer.integer >= 3)
1846 Con_Printf("new engine string %p\n", s);
1847 for (i = 0;i < prog->numknownstrings;i++)
1848 if (!prog->knownstrings[i])
1850 if (i >= prog->numknownstrings)
1852 if (i >= prog->maxknownstrings)
1854 const char **oldstrings = prog->knownstrings;
1855 prog->maxknownstrings += 128;
1856 prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
1857 if (prog->numknownstrings)
1858 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
1860 prog->numknownstrings++;
1862 prog->knownstrings[i] = s;
1866 char *PRVM_AllocString(int bufferlength)
1871 for (i = 0;i < prog->numknownstrings;i++)
1872 if (!prog->knownstrings[i])
1874 if (i >= prog->numknownstrings)
1876 if (i >= prog->maxknownstrings)
1878 const char **oldstrings = prog->knownstrings;
1879 prog->maxknownstrings += 128;
1880 prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
1881 if (prog->numknownstrings)
1882 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
1884 prog->numknownstrings++;
1886 return (char *)(prog->knownstrings[i] = PRVM_Alloc(bufferlength));
1889 void PRVM_FreeString(char *s)
1893 Host_Error("PRVM_FreeString: attempt to free a NULL string\n");
1894 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1895 Host_Error("PRVM_FreeString: attempt to free a constant string\n");
1896 for (i = 0;i < prog->numknownstrings;i++)
1897 if (prog->knownstrings[i] == s)
1899 if (i == prog->numknownstrings)
1900 Host_Error("PRVM_FreeString: attempt to free a non-existent or already freed string\n");
1901 PRVM_Free((char *)prog->knownstrings[i]);
1902 prog->knownstrings[i] = NULL;