2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 static prvm_prog_t prog_list[PRVM_MAXPROGS];
28 int prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
30 ddef_t *PRVM_ED_FieldAtOfs(int ofs);
31 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s);
33 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
34 cvar_t prvm_boundscheck = {0, "prvm_boundscheck", "1"};
35 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
36 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0"};
38 ddef_t *PRVM_ED_FindField (const char *name);
39 mfunction_t *PRVM_ED_FindFunction (const char *name);
41 //============================================================================
53 // check bound of max_edicts
54 prog->max_edicts = min(prog->max_edicts,prog->limit_edicts);
56 // edictprivate_size has to be min as big prvm_edict_private_t
57 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
60 prog->edicts = Mem_Alloc(prog->edicts_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
62 // alloc edict private space
63 prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
66 prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
69 for(i = 0; i < prog->max_edicts; i++)
71 prog->edicts[i].e = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
72 prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
78 PRVM_MEM_IncreaseEdicts
81 void PRVM_MEM_IncreaseEdicts()
84 int oldmaxedicts = prog->max_edicts;
85 void *oldedictsfields = prog->edictsfields;
86 void *oldedictprivate = prog->edictprivate;
88 if(prog->max_edicts >= prog->limit_edicts)
91 PRVM_GCALL(begin_increase_edicts)();
94 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
96 prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
97 prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
99 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
100 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
102 //set e and v pointers
103 for(i = 0; i < prog->max_edicts; i++)
105 prog->edicts[i].e = (prvm_edict_private_t *)((qbyte *)prog->edictprivate + i * prog->edictprivate_size);
106 prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
109 PRVM_GCALL(end_increase_edicts)();
111 Mem_Free(oldedictsfields);
112 Mem_Free(oldedictprivate);
115 //============================================================================
118 int PRVM_ED_FindFieldOffset(const char *field)
121 d = PRVM_ED_FindField(field);
127 qboolean PRVM_ProgLoaded(int prognr)
129 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
132 return (prog_list[prognr].loaded ? TRUE : FALSE);
137 PRVM_SetProgFromString
140 // perhaps add a return value when the str doesnt exist
141 qboolean PRVM_SetProgFromString(const char *str)
144 for(; i < PRVM_MAXPROGS ; i++)
145 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
147 if(prog_list[i].loaded)
149 prog = &prog_list[i];
154 Con_Printf("%s not loaded !\n",PRVM_NAME);
159 Con_Printf("Invalid program name %s !\n", str);
168 void PRVM_SetProg(int prognr)
170 if(prognr && prognr < PRVM_MAXPROGS)
172 if(prog_list[prognr].loaded)
173 prog = &prog_list[prognr];
175 PRVM_ERROR("%i(%s) not loaded !\n", prognr, PRVM_NAME);
178 PRVM_ERROR("Invalid program number %i\n", prognr);
185 Sets everything to NULL
188 void PRVM_ED_ClearEdict (prvm_edict_t *e)
191 memset (e->v, 0, prog->progs->entityfields * 4);
193 // LordHavoc: for consistency set these here
194 num = PRVM_NUM_FOR_EDICT(e) - 1;
196 // AK: Let the init_edict function determine if something needs to be initialized
197 PRVM_GCALL(init_edict)(num);
204 Either finds a free edict, or allocates a new one.
205 Try to avoid reusing an entity that was recently freed, because it
206 can cause the client to think the entity morphed into something else
207 instead of being removed and recreated, which can cause interpolated
208 angles and bad trails.
211 prvm_edict_t *PRVM_ED_Alloc (void)
216 // the client qc dont need maxclients
217 // thus it doesnt need to use svs.maxclients
218 // AK: changed i=svs.maxclients+1
219 // AK: changed so the edict 0 wont spawned -> used as reserved/world entity
220 // although the menu/client has no world
221 for (i = 1;i < prog->num_edicts;i++)
223 e = PRVM_EDICT_NUM(i);
224 // the first couple seconds of server time can involve a lot of
225 // freeing and allocating, so relax the replacement policy
226 if (e->e->free && ( e->e->freetime < 2 || prog->time - e->e->freetime > 0.5 ) )
228 PRVM_ED_ClearEdict (e);
234 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
237 if (prog->num_edicts >= prog->max_edicts)
238 PRVM_MEM_IncreaseEdicts();
240 e = PRVM_EDICT_NUM(i);
241 PRVM_ED_ClearEdict (e);
250 Marks the edict as free
251 FIXME: walk all entities and NULL out references to this entity
254 void PRVM_ED_Free (prvm_edict_t *ed)
256 PRVM_GCALL(free_edict)(ed);
259 ed->e->freetime = prog->time;
262 //===========================================================================
269 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
274 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
276 def = &prog->globaldefs[i];
288 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
293 for (i=0 ; i<prog->progs->numfielddefs ; i++)
295 def = &prog->fielddefs[i];
307 ddef_t *PRVM_ED_FindField (const char *name)
312 for (i=0 ; i<prog->progs->numfielddefs ; i++)
314 def = &prog->fielddefs[i];
315 if (!strcmp(PRVM_GetString(def->s_name), name))
326 ddef_t *PRVM_ED_FindGlobal (const char *name)
331 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
333 def = &prog->globaldefs[i];
334 if (!strcmp(PRVM_GetString(def->s_name), name))
346 mfunction_t *PRVM_ED_FindFunction (const char *name)
351 for (i=0 ; i<prog->progs->numfunctions ; i++)
353 func = &prog->functions[i];
354 if (!strcmp(PRVM_GetString(func->s_name), name))
365 Returns a string describing *data in a type specific manner
368 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
370 static char line[1024]; // LordHavoc: enlarged a bit (was 256)
375 type &= ~DEF_SAVEGLOBAL;
380 sprintf (line, "%s", PRVM_GetString(val->string));
384 if (n < 0 || n >= MAX_EDICTS)
385 sprintf (line, "entity %i (invalid!)", n);
387 sprintf (line, "entity %i", n);
390 f = prog->functions + val->function;
391 sprintf (line, "%s()", PRVM_GetString(f->s_name));
394 def = PRVM_ED_FieldAtOfs ( val->_int );
395 sprintf (line, ".%s", PRVM_GetString(def->s_name));
398 sprintf (line, "void");
401 // LordHavoc: changed from %5.1f to %10.4f
402 sprintf (line, "%10.4f", val->_float);
405 // LordHavoc: changed from %5.1f to %10.4f
406 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
409 sprintf (line, "pointer");
412 sprintf (line, "bad type %i", type);
423 Returns a string describing *data in a type specific manner
424 Easier to parse than PR_ValueString
427 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
429 static char line[4096];
435 type &= ~DEF_SAVEGLOBAL;
440 // Parse the string a bit to turn special characters
441 // (like newline, specifically) into escape codes,
442 // this fixes saving games from various mods
443 s = PRVM_GetString (val->string);
444 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
463 snprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
466 f = pr_functions + val->function;
467 snprintf (line, sizeof (line), "%s", PRVM_GetString(f->s_name));
470 def = PRVM_ED_FieldAtOfs ( val->_int );
471 snprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
474 snprintf (line, sizeof (line), "void");
477 snprintf (line, sizeof (line), "%f", val->_float);
480 snprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
483 snprintf (line, sizeof (line), "bad type %i", type);
494 Returns a string with a description and the contents of a global,
495 padded to 20 field width
498 char *PRVM_GlobalString (int ofs)
504 static char line[128];
506 val = (void *)&prog->globals[ofs];
507 def = PRVM_ED_GlobalAtOfs(ofs);
509 sprintf (line,"%i(?)", ofs);
512 s = PRVM_ValueString (def->type, val);
513 sprintf (line,"%i(%s)%s", ofs, PRVM_GetString(def->s_name), s);
524 char *PRVM_GlobalStringNoContents (int ofs)
528 static char line[128];
530 def = PRVM_ED_GlobalAtOfs(ofs);
532 sprintf (line,"%i(?)", ofs);
534 sprintf (line,"%i(%s)", ofs, PRVM_GetString(def->s_name));
552 // LordHavoc: optimized this to print out much more quickly (tempstring)
553 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
554 void PRVM_ED_Print (prvm_edict_t *ed)
562 char tempstring[8192], tempstring2[260]; // temporary string buffers
566 Con_Printf ("%s: FREE\n",PRVM_NAME);
571 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
572 for (i=1 ; i<prog->progs->numfielddefs ; i++)
574 d = &prog->fielddefs[i];
575 name = PRVM_GetString(d->s_name);
576 if (name[strlen(name)-2] == '_')
577 continue; // skip _x, _y, _z vars
579 v = (int *)((char *)ed->v + d->ofs*4);
581 // if the value is still all 0, skip the field
582 type = d->type & ~DEF_SAVEGLOBAL;
584 for (j=0 ; j<prvm_type_size[type] ; j++)
587 if (j == prvm_type_size[type])
590 if (strlen(name) > 256)
592 strncpy(tempstring2, name, 256);
593 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
594 tempstring2[259] = 0;
597 strcat(tempstring, name);
598 for (l = strlen(name);l < 14;l++)
599 strcat(tempstring, " ");
600 strcat(tempstring, " ");
602 name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
603 if (strlen(name) > 256)
605 strncpy(tempstring2, name, 256);
606 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
607 tempstring2[259] = 0;
610 strcat(tempstring, name);
611 strcat(tempstring, "\n");
612 if (strlen(tempstring) >= 4096)
614 Con_Printf("%s", tempstring);
619 Con_Printf("%s", tempstring);
629 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
637 FS_Printf (f, "{\n");
641 FS_Printf (f, "}\n");
645 for (i=1 ; i<prog->progs->numfielddefs ; i++)
647 d = &prog->fielddefs[i];
648 name = PRVM_GetString(d->s_name);
649 if (name[strlen(name)-2] == '_')
650 continue; // skip _x, _y, _z vars
652 v = (int *)((char *)ed->v + d->ofs*4);
654 // if the value is still all 0, skip the field
655 type = d->type & ~DEF_SAVEGLOBAL;
656 for (j=0 ; j<prvm_type_size[type] ; j++)
659 if (j == prvm_type_size[type])
662 FS_Printf (f,"\"%s\" ",name);
663 FS_Printf (f,"\"%s\"\n", PRVM_UglyValueString(d->type, (prvm_eval_t *)v));
666 FS_Printf (f, "}\n");
669 void PRVM_ED_PrintNum (int ent)
671 PRVM_ED_Print (PRVM_EDICT_NUM(ent));
676 PRVM_ED_PrintEdicts_f
678 For debugging, prints all the entities in the current server
681 void PRVM_ED_PrintEdicts_f (void)
687 Con_Print("prvm_edicts <program name>\n");
692 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
695 Con_Printf ("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
696 for (i=0 ; i<prog->num_edicts ; i++)
697 PRVM_ED_PrintNum (i);
706 For debugging, prints a single edict
709 void PRVM_ED_PrintEdict_f (void)
715 Con_Print("prvm_edict <program name> <edict number>\n");
720 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
723 i = atoi (Cmd_Argv(2));
724 if (i >= prog->num_edicts)
726 Con_Printf("Bad edict number\n");
729 PRVM_ED_PrintNum (i);
741 // 2 possibilities : 1. just displaying the active edict count
742 // 2. making a function pointer [x]
743 void PRVM_ED_Count_f (void)
751 Con_Print("prvm_count <program name>\n");
756 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
759 if(prog->count_edicts)
760 prog->count_edicts();
764 for (i=0 ; i<prog->num_edicts ; i++)
766 ent = PRVM_EDICT_NUM(i);
772 Con_Printf ("num_edicts:%3i\n", sv.num_edicts);
773 Con_Printf ("active :%3i\n", active);
780 ==============================================================================
784 FIXME: need to tag constants, doesn't really work
785 ==============================================================================
793 void PRVM_ED_WriteGlobals (qfile_t *f)
801 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
803 def = &prog->globaldefs[i];
805 if ( !(def->type & DEF_SAVEGLOBAL) )
807 type &= ~DEF_SAVEGLOBAL;
809 if (type != ev_string && type != ev_float && type != ev_entity)
812 name = PRVM_GetString(def->s_name);
813 FS_Printf (f,"\"%s\" ", name);
814 FS_Printf (f,"\"%s\"\n", PRVM_UglyValueString(type, (prvm_eval_t *)&prog->globals[def->ofs]));
824 void PRVM_ED_ParseGlobals (const char *data)
826 char keyname[1024]; // LordHavoc: good idea? bad idea? was 64
832 if (!COM_ParseToken(&data, false))
833 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
834 if (com_token[0] == '}')
837 strcpy (keyname, com_token);
840 if (!COM_ParseToken(&data, false))
841 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
843 if (com_token[0] == '}')
844 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
846 key = PRVM_ED_FindGlobal (keyname);
849 Con_DPrintf ("'%s' is not a global on %s\n", keyname, PRVM_NAME);
853 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
854 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
858 //============================================================================
866 char *PRVM_ED_NewString (const char *string)
871 l = strlen(string) + 1;
872 new = Mem_Alloc(prog->edictstring_mempool, l);
875 for (i=0 ; i< l ; i++)
877 if (string[i] == '\\' && i < l-1)
880 if (string[i] == 'n')
886 *new_p++ = string[i];
897 Can parse either fields or globals
898 returns false if error
901 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
909 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
911 val = (prvm_eval_t *)((int *)pr_globals + key->ofs);
912 switch (key->type & ~DEF_SAVEGLOBAL)
915 val->string = PRVM_SetString(ED_NewString(s));
919 while (*s && *s <= ' ')
921 val->_float = atof(s);
925 for (i = 0;i < 3;i++)
927 while (*s && *s <= ' ')
931 val->vector[i] = atof(s);
940 while (*s && *s <= ' ')
943 if (i < 0 || i >= MAX_EDICTS)
944 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %i >= MAX_EDICTS %i) on %s\n", i, MAX_EDICTS, PRVM_NAME);
945 while (i >= prog->max_edicts)
946 PRVM_MEM_IncreaseEdicts();
947 //SV_IncreaseEdicts();
948 // if SV_IncreaseEdicts was called the base pointer needs to be updated
950 val = (prvm_eval_t *)((int *)ent->v + key->ofs);
951 val->edict = PRVM_EDICT_TO_PROG(EDICT_NUM(i));
955 def = PRVM_ED_FindField(s);
958 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s on %s\n", s, PRVM_NAME);
961 val->_int = PRVM_G_INT(def->ofs);
965 func = PRVM_ED_FindFunction(s);
968 Con_Printf ("PRVM_ED_ParseEpair: Can't find function %s on %s\n", s, PRVM_NAME);
971 val->function = func - prog->functions;
975 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PR_GetString(key->s_name), PRVM_NAME);
985 Parses an edict out of the given string, returning the new position
986 ed should be a properly initialized empty edict.
987 Used for initial level load and for savegames.
990 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1001 if (ent != prog->edicts) // hack
1002 memset (ent->v, 0, prog->progs->entityfields * 4);
1004 // go through all the dictionary pairs
1008 if (!COM_ParseToken(&data, false))
1009 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1010 if (com_token[0] == '}')
1013 // anglehack is to allow QuakeEd to write single scalar angles
1014 // and allow them to be turned into vectors. (FIXME...)
1015 if (!strcmp(com_token, "angle"))
1017 strcpy (com_token, "angles");
1023 // FIXME: change light to _light to get rid of this hack
1024 if (!strcmp(com_token, "light"))
1025 strcpy (com_token, "light_lev"); // hack for single light def
1027 strcpy (keyname, com_token);
1029 // another hack to fix heynames with trailing spaces
1030 n = strlen(keyname);
1031 while (n && keyname[n-1] == ' ')
1038 if (!COM_ParseToken(&data, false))
1039 PRVM_ERROR ("PRVM_ED_ParseEntity: EOF without closing brace");
1041 if (com_token[0] == '}')
1042 PRVM_ERROR ("PRVM_ED_ParseEntity: closing brace without data");
1046 // keynames with a leading underscore are used for utility comments,
1047 // and are immediately discarded by quake
1048 if (keyname[0] == '_')
1051 key = PRVM_ED_FindField (keyname);
1054 Con_DPrintf ("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1061 strcpy (temp, com_token);
1062 sprintf (com_token, "0 %s 0", temp);
1065 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1066 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1070 ent->e->free = true;
1078 PRVM_ED_LoadFromFile
1080 The entities are directly placed in the array, rather than allocated with
1081 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1082 number references out of order.
1084 Creates a server's entity / program execution context by
1085 parsing textual entity definitions out of an ent file.
1087 Used for both fresh maps and savegame loads. A fresh map would also need
1088 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1091 void PRVM_ED_LoadFromFile (const char *data)
1094 int parsed, inhibited, spawned, died;
1104 if(prog->flag & PRVM_GE_TIME)
1105 PRVM_G_FLOAT(PRVM_ED_FindFieldOffset("time")) = prog->time;
1110 // parse the opening brace
1111 if (!COM_ParseToken(&data, false))
1113 if (com_token[0] != '{')
1114 PRVM_ERROR ("PRVM_ED_LoadFromFile: found %s when expecting (%s) {",com_token, PRVM_NAME);
1117 ent = PRVM_EDICT_NUM(0);
1119 ent = PRVM_ED_Alloc ();
1120 data = PRVM_ED_ParseEdict (data, ent);
1123 // remove the entity ?
1124 if(prog->load_edict && !prog->load_edict(ent))
1132 // immediately call spawn function, but only if there is a self global
1134 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1136 string_t handle = *(string_t*)&((float*)ent->v)[PRVM_ED_FindFieldOffset("classname")];
1139 Con_Printf ("No classname for:\n");
1140 PRVM_ED_Print (ent);
1145 // look for the spawn function
1146 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1150 if (developer.integer) // don't confuse non-developers with errors
1152 Con_Printf ("No spawn function for:\n");
1153 PRVM_ED_Print (ent);
1160 PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1161 PRVM_ExecuteProgram (func - prog->functions, "");
1169 Con_DPrintf ("%s: %i entities parsed, %i inhibited, %i spawned (%i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, spawned, died, spawned - died);
1174 typedef struct dpfield_s
1181 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1183 dpfield_t dpfields[] =
1194 void PRVM_ResetProg()
1196 mempool_t *t1, *t2, *t3;
1198 t1 = prog->progs_mempool;
1199 t2 = prog->edictstring_mempool;
1200 t3 = prog->edicts_mempool;
1202 Mem_EmptyPool(prog->progs_mempool);
1203 Mem_EmptyPool(prog->edictstring_mempool);
1204 Mem_EmptyPool(prog->edicts_mempool);
1206 memset(prog,0,sizeof(prvm_prog_t));
1209 prog->progs_mempool = t1;
1210 prog->edictstring_mempool = t2;
1211 prog->edicts_mempool = t3;
1213 PRVM_GCALL(reset_cmd)();
1221 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func)
1225 ddef_t *infielddefs;
1227 dfunction_t *dfunctions;
1229 Mem_EmptyPool(prog->progs_mempool);
1230 Mem_EmptyPool(prog->edictstring_mempool);
1232 temp = FS_LoadFile (filename, false);
1234 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1236 prog->progs = (dprograms_t *)Mem_Alloc(prog->progs_mempool, fs_filesize);
1238 memcpy(prog->progs, temp, fs_filesize);
1241 Con_DPrintf ("%s programs occupy %iK.\n", PRVM_NAME, fs_filesize/1024);
1243 pr_crc = CRC_Block((qbyte *)prog->progs, fs_filesize);
1245 // byte swap the header
1246 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1247 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1249 if (prog->progs->version != PROG_VERSION)
1250 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1251 if (prog->progs->crc != prog->crc)
1252 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1254 //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
1255 dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
1256 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1257 prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
1259 // we need to expand the fielddefs list to include all the engine fields,
1260 // so allocate a new place for it
1261 infielddefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_fielddefs);
1263 prog->fielddefs = Mem_Alloc(prog->progs_mempool, prog->progs->numfielddefs * sizeof(ddef_t));
1265 prog->statements = (dstatement_t *)((qbyte *)prog->progs + prog->progs->ofs_statements);
1267 // moved edict_size calculation down below field adding code
1269 //pr_global_struct = (globalvars_t *)((qbyte *)progs + progs->ofs_globals);
1270 prog->globals = (float *)((qbyte *)prog->progs + prog->progs->ofs_globals);
1272 // byte swap the lumps
1273 for (i=0 ; i<prog->progs->numstatements ; i++)
1275 prog->statements[i].op = LittleShort(prog->statements[i].op);
1276 prog->statements[i].a = LittleShort(prog->statements[i].a);
1277 prog->statements[i].b = LittleShort(prog->statements[i].b);
1278 prog->statements[i].c = LittleShort(prog->statements[i].c);
1281 prog->functions = Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1282 for (i = 0;i < prog->progs->numfunctions;i++)
1284 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1285 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1286 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1287 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1288 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1289 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1290 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1293 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1295 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1296 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1297 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1300 // copy the progs fields to the new fields list
1301 for (i = 0;i < prog->progs->numfielddefs;i++)
1303 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1304 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1305 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1306 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1307 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1310 /* // append the darkplaces fields
1311 for (i = 0;i < (int) DPFIELDS;i++)
1313 pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
1314 pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
1315 pr_fielddefs[progs->numfielddefs].s_name = PR_SetString(dpfields[i].string);
1316 if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
1317 progs->entityfields += 3;
1319 progs->entityfields++;
1320 progs->numfielddefs++;
1323 // check required functions
1324 for(i=0 ; i < numrequiredfunc ; i++)
1325 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1326 PRVM_ERROR("%s: %s not found in %s\n",PRVM_NAME, required_func[i], filename);
1328 for (i=0 ; i<prog->progs->numglobals ; i++)
1329 ((int *)prog->globals)[i] = LittleLong (((int *)prog->globals)[i]);
1331 // moved edict_size calculation down here, below field adding code
1332 // LordHavoc: this no longer includes the edict_t header
1333 prog->edict_size = prog->progs->entityfields * 4;
1334 prog->edictareasize = prog->edict_size * MAX_EDICTS;
1336 // LordHavoc: bounds check anything static
1337 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1343 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1344 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s\n", i, PRVM_NAME);
1347 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1348 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s\n", i, PRVM_NAME);
1350 // global global global
1385 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1386 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n", i);
1388 // global none global
1394 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1395 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1411 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1412 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)\n in %s", i, PRVM_NAME);
1426 if ((unsigned short) st->a >= prog->progs->numglobals)
1427 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s\n", i, PRVM_NAME);
1430 PRVM_ERROR("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1437 prog->loaded = TRUE;
1439 // set flags & ddef_ts in prog
1443 prog->self = PRVM_ED_FindGlobal("self");
1445 if(PRVM_ED_FindGlobal("time"))
1446 prog->flag |= PRVM_GE_TIME;
1448 if(PRVM_ED_FindField ("chain"))
1449 prog->flag |= PRVM_FE_CHAIN;
1451 if(PRVM_ED_FindField ("classname"))
1452 prog->flag |= PRVM_FE_CLASSNAME;
1454 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1455 && prog->flag & PRVM_GE_TIME && prog->self)
1456 prog->flag |= PRVM_OP_STATE;
1458 PRVM_GCALL(reset_cmd)();
1465 void PRVM_Fields_f (void)
1467 int i, j, ednum, used, usedamount;
1469 char tempstring[5000], tempstring2[260], *name;
1478 Con_Printf("no progs loaded\n");
1485 Con_Print("prvm_fields <program name>\n");
1490 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1493 counts = Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1494 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1496 ed = PRVM_EDICT_NUM(ednum);
1499 for (i = 1;i < prog->progs->numfielddefs;i++)
1501 d = &prog->fielddefs[i];
1502 name = PRVM_GetString(d->s_name);
1503 if (name[strlen(name)-2] == '_')
1504 continue; // skip _x, _y, _z vars
1505 v = (int *)((char *)ed->v + d->ofs*4);
1506 // if the value is still all 0, skip the field
1507 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1520 for (i = 0;i < prog->progs->numfielddefs;i++)
1522 d = &prog->fielddefs[i];
1523 name = PRVM_GetString(d->s_name);
1524 if (name[strlen(name)-2] == '_')
1525 continue; // skip _x, _y, _z vars
1526 switch(d->type & ~DEF_SAVEGLOBAL)
1529 strcat(tempstring, "string ");
1532 strcat(tempstring, "entity ");
1535 strcat(tempstring, "function ");
1538 strcat(tempstring, "field ");
1541 strcat(tempstring, "void ");
1544 strcat(tempstring, "float ");
1547 strcat(tempstring, "vector ");
1550 strcat(tempstring, "pointer ");
1553 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1554 strcat(tempstring, tempstring2);
1557 if (strlen(name) > 256)
1559 strncpy(tempstring2, name, 256);
1560 tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
1561 tempstring2[259] = 0;
1564 strcat(tempstring, name);
1565 for (j = strlen(name);j < 25;j++)
1566 strcat(tempstring, " ");
1567 sprintf(tempstring2, "%5d", counts[i]);
1568 strcat(tempstring, tempstring2);
1569 strcat(tempstring, "\n");
1570 if (strlen(tempstring) >= 4096)
1572 Con_Printf("%s", tempstring);
1578 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1582 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);
1587 void PRVM_Globals_f (void)
1593 Con_Printf("no progs loaded\n");
1596 if(Cmd_Argc () != 2)
1598 Con_Print ("prvm_globals <program name>\n");
1603 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1606 Con_Printf("%s :", PRVM_NAME);
1608 for (i = 0;i < prog->progs->numglobaldefs;i++)
1609 Con_Printf("%s\n", PRVM_GetString(pr_globaldefs[i].s_name));
1610 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1620 void PRVM_Init (void)
1622 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f);
1623 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f);
1624 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f);
1625 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
1626 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
1627 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
1628 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1629 Cvar_RegisterVariable (&prvm_boundscheck);
1630 Cvar_RegisterVariable (&prvm_traceqc);
1640 void PRVM_InitProg(int prognr)
1642 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1643 Sys_Error("PRVM_InitProg: Invalid program number %i\n",prognr);
1645 prog = &prog_list[prognr];
1647 memset(prog, 0, sizeof(prvm_prog_t));
1649 PRVM_GCALL(init_cmd)();
1652 int PRVM_GetProgNr()
1654 return prog - prog_list;
1657 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1658 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1660 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1665 int NUM_FOR_EDICT_ERROR(edict_t *e)
1667 Host_Error ("NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, sv.edicts, e - sv.edicts);
1671 int NUM_FOR_EDICT(edict_t *e)
1675 if ((unsigned int)n >= MAX_EDICTS)
1676 Host_Error ("NUM_FOR_EDICT: bad pointer");
1680 //int NoCrash_NUM_FOR_EDICT(edict_t *e)
1682 // return e - sv.edicts;
1685 //#define EDICT_TO_PROG(e) ((qbyte *)(((edict_t *)e)->v) - (qbyte *)(sv.edictsfields))
1686 //#define PROG_TO_EDICT(e) (sv.edicts + ((e) / (progs->entityfields * 4)))
1687 int EDICT_TO_PROG(edict_t *e)
1691 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1692 Host_Error("EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)\n", e, n, sv.edicts);
1693 return n;// EXPERIMENTAL
1694 //return (qbyte *)e->v - (qbyte *)sv.edictsfields;
1696 edict_t *PROG_TO_EDICT(int n)
1698 if ((unsigned int)n >= (unsigned int)sv.max_edicts)
1699 Host_Error("PROG_TO_EDICT: invalid edict number %i\n", n);
1700 return sv.edicts + n; // EXPERIMENTAL
1701 //return sv.edicts + ((n) / (progs->entityfields * 4));