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", "enables detection of out of bounds memory access in the QuakeC code being run (in other words, prevents really exceedingly bad QuakeC code from doing nasty things to your computer)"};
36 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
37 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
38 // LordHavoc: counts usage of each QuakeC statement
39 cvar_t prvm_statementprofiling = {0, "prvm_statementprofiling", "0", "counts how many times each QuakeC statement has been executed, these counts are displayed in prvm_printfunction output (if enabled)"};
41 extern sizebuf_t vm_tempstringsbuf;
43 //============================================================================
51 void PRVM_MEM_Alloc(void)
55 // reserve space for the null entity aka world
56 // check bound of max_edicts
57 prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
58 prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
60 // edictprivate_size has to be min as big prvm_edict_private_t
61 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
64 prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
66 // alloc edict private space
67 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
70 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
73 for(i = 0; i < prog->max_edicts; i++)
75 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
76 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
82 PRVM_MEM_IncreaseEdicts
85 void PRVM_MEM_IncreaseEdicts(void)
88 int oldmaxedicts = prog->max_edicts;
89 void *oldedictsfields = prog->edictsfields;
90 void *oldedictprivate = prog->edictprivate;
92 if(prog->max_edicts >= prog->limit_edicts)
95 PRVM_GCALL(begin_increase_edicts)();
98 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
100 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
101 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
103 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
104 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
106 //set e and v pointers
107 for(i = 0; i < prog->max_edicts; i++)
109 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
110 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
113 PRVM_GCALL(end_increase_edicts)();
115 Mem_Free(oldedictsfields);
116 Mem_Free(oldedictprivate);
119 //============================================================================
122 int PRVM_ED_FindFieldOffset(const char *field)
125 d = PRVM_ED_FindField(field);
131 int PRVM_ED_FindGlobalOffset(const char *global)
134 d = PRVM_ED_FindGlobal(global);
140 func_t PRVM_ED_FindFunctionOffset(const char *function)
143 f = PRVM_ED_FindFunction(function);
146 return (func_t)(f - prog->functions);
149 qboolean PRVM_ProgLoaded(int prognr)
151 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
154 return (prog_list[prognr].loaded ? TRUE : FALSE);
159 PRVM_SetProgFromString
162 // perhaps add a return value when the str doesnt exist
163 qboolean PRVM_SetProgFromString(const char *str)
166 for(; i < PRVM_MAXPROGS ; i++)
167 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
169 if(prog_list[i].loaded)
171 prog = &prog_list[i];
176 Con_Printf("%s not loaded !\n",PRVM_NAME);
181 Con_Printf("Invalid program name %s !\n", str);
190 void PRVM_SetProg(int prognr)
192 if(0 <= prognr && prognr < PRVM_MAXPROGS)
194 if(prog_list[prognr].loaded)
195 prog = &prog_list[prognr];
197 PRVM_ERROR("%i not loaded !", prognr);
200 PRVM_ERROR("Invalid program number %i", prognr);
207 Sets everything to NULL
210 void PRVM_ED_ClearEdict (prvm_edict_t *e)
212 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
213 e->priv.required->free = false;
215 // AK: Let the init_edict function determine if something needs to be initialized
216 PRVM_GCALL(init_edict)(e);
223 Either finds a free edict, or allocates a new one.
224 Try to avoid reusing an entity that was recently freed, because it
225 can cause the client to think the entity morphed into something else
226 instead of being removed and recreated, which can cause interpolated
227 angles and bad trails.
230 prvm_edict_t *PRVM_ED_Alloc (void)
235 // the client qc dont need maxclients
236 // thus it doesnt need to use svs.maxclients
237 // AK: changed i=svs.maxclients+1
238 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
239 // although the menu/client has no world
240 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
242 e = PRVM_EDICT_NUM(i);
243 // the first couple seconds of server time can involve a lot of
244 // freeing and allocating, so relax the replacement policy
245 if (e->priv.required->free && ( e->priv.required->freetime < 2 || prog->globaloffsets.time < 0 || (PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float - e->priv.required->freetime) > 0.5 ) )
247 PRVM_ED_ClearEdict (e);
252 if (i == prog->limit_edicts)
253 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
256 if (prog->num_edicts >= prog->max_edicts)
257 PRVM_MEM_IncreaseEdicts();
259 e = PRVM_EDICT_NUM(i);
260 PRVM_ED_ClearEdict (e);
269 Marks the edict as free
270 FIXME: walk all entities and NULL out references to this entity
273 void PRVM_ED_Free (prvm_edict_t *ed)
275 // dont delete the null entity (world) or reserved edicts
276 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
279 PRVM_GCALL(free_edict)(ed);
281 ed->priv.required->free = true;
282 ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0;
285 //===========================================================================
292 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
297 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
299 def = &prog->globaldefs[i];
311 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
316 for (i=0 ; i<prog->progs->numfielddefs ; i++)
318 def = &prog->fielddefs[i];
330 ddef_t *PRVM_ED_FindField (const char *name)
335 for (i=0 ; i<prog->progs->numfielddefs ; i++)
337 def = &prog->fielddefs[i];
338 if (!strcmp(PRVM_GetString(def->s_name), name))
349 ddef_t *PRVM_ED_FindGlobal (const char *name)
354 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
356 def = &prog->globaldefs[i];
357 if (!strcmp(PRVM_GetString(def->s_name), name))
369 mfunction_t *PRVM_ED_FindFunction (const char *name)
374 for (i=0 ; i<prog->progs->numfunctions ; i++)
376 func = &prog->functions[i];
377 if (!strcmp(PRVM_GetString(func->s_name), name))
388 Returns a string describing *data in a type specific manner
391 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
393 static char line[MAX_INPUTLINE];
398 type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
403 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
407 if (n < 0 || n >= prog->limit_edicts)
408 sprintf (line, "entity %i (invalid!)", n);
410 sprintf (line, "entity %i", n);
413 f = prog->functions + val->function;
414 sprintf (line, "%s()", PRVM_GetString(f->s_name));
417 def = PRVM_ED_FieldAtOfs ( val->_int );
418 sprintf (line, ".%s", PRVM_GetString(def->s_name));
421 sprintf (line, "void");
424 // LordHavoc: changed from %5.1f to %10.4f
425 sprintf (line, "%10.4f", val->_float);
428 // LordHavoc: changed from %5.1f to %10.4f
429 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
432 sprintf (line, "pointer");
435 sprintf (line, "bad type %i", (int) type);
446 Returns a string describing *data in a type specific manner
447 Easier to parse than PR_ValueString
450 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
452 static char line[MAX_INPUTLINE];
458 type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
463 // Parse the string a bit to turn special characters
464 // (like newline, specifically) into escape codes,
465 // this fixes saving games from various mods
466 s = PRVM_GetString (val->string);
467 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
486 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
489 f = prog->functions + val->function;
490 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
493 def = PRVM_ED_FieldAtOfs ( val->_int );
494 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
497 dpsnprintf (line, sizeof (line), "void");
500 dpsnprintf (line, sizeof (line), "%f", val->_float);
503 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
506 dpsnprintf (line, sizeof (line), "bad type %i", type);
517 Returns a string with a description and the contents of a global,
518 padded to 20 field width
521 char *PRVM_GlobalString (int ofs)
527 static char line[128];
529 val = (void *)&prog->globals.generic[ofs];
530 def = PRVM_ED_GlobalAtOfs(ofs);
532 sprintf (line,"GLOBAL%i", ofs);
535 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
536 sprintf (line,"%s (=%s)", PRVM_GetString(def->s_name), s);
540 //for ( ; i<20 ; i++)
541 // strcat (line," ");
547 char *PRVM_GlobalStringNoContents (int ofs)
551 static char line[128];
553 def = PRVM_ED_GlobalAtOfs(ofs);
555 sprintf (line,"GLOBAL%i", ofs);
557 sprintf (line,"%s", PRVM_GetString(def->s_name));
560 //for ( ; i<20 ; i++)
561 // strcat (line," ");
575 // LordHavoc: optimized this to print out much more quickly (tempstring)
576 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
577 void PRVM_ED_Print(prvm_edict_t *ed)
585 char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
587 if (ed->priv.required->free)
589 Con_Printf("%s: FREE\n",PRVM_NAME);
594 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
595 for (i=1 ; i<prog->progs->numfielddefs ; i++)
597 d = &prog->fielddefs[i];
598 name = PRVM_GetString(d->s_name);
599 if (name[strlen(name)-2] == '_')
600 continue; // skip _x, _y, _z vars
602 v = (int *)((char *)ed->fields.vp + d->ofs*4);
604 // if the value is still all 0, skip the field
605 type = d->type & ~DEF_SAVEGLOBAL;
607 for (j=0 ; j<prvm_type_size[type] ; j++)
610 if (j == prvm_type_size[type])
613 if (strlen(name) > sizeof(tempstring2)-4)
615 memcpy (tempstring2, name, sizeof(tempstring2)-4);
616 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
617 tempstring2[sizeof(tempstring2)-1] = 0;
620 strlcat(tempstring, name, sizeof(tempstring));
621 for (l = strlen(name);l < 14;l++)
622 strlcat(tempstring, " ", sizeof(tempstring));
623 strlcat(tempstring, " ", sizeof(tempstring));
625 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
626 if (strlen(name) > sizeof(tempstring2)-4)
628 memcpy (tempstring2, name, sizeof(tempstring2)-4);
629 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
630 tempstring2[sizeof(tempstring2)-1] = 0;
633 strlcat(tempstring, name, sizeof(tempstring));
634 strlcat(tempstring, "\n", sizeof(tempstring));
635 if (strlen(tempstring) >= sizeof(tempstring)/2)
637 Con_Print(tempstring);
642 Con_Print(tempstring);
652 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
662 if (ed->priv.required->free)
668 for (i=1 ; i<prog->progs->numfielddefs ; i++)
670 d = &prog->fielddefs[i];
671 name = PRVM_GetString(d->s_name);
672 if (name[strlen(name)-2] == '_')
673 continue; // skip _x, _y, _z vars
675 v = (int *)((char *)ed->fields.vp + d->ofs*4);
677 // if the value is still all 0, skip the field
678 type = d->type & ~DEF_SAVEGLOBAL;
679 for (j=0 ; j<prvm_type_size[type] ; j++)
682 if (j == prvm_type_size[type])
685 FS_Printf(f,"\"%s\" ",name);
686 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
692 void PRVM_ED_PrintNum (int ent)
694 PRVM_ED_Print(PRVM_EDICT_NUM(ent));
699 PRVM_ED_PrintEdicts_f
701 For debugging, prints all the entities in the current server
704 void PRVM_ED_PrintEdicts_f (void)
710 Con_Print("prvm_edicts <program name>\n");
715 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
718 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
719 for (i=0 ; i<prog->num_edicts ; i++)
720 PRVM_ED_PrintNum (i);
729 For debugging, prints a single edict
732 void PRVM_ED_PrintEdict_f (void)
738 Con_Print("prvm_edict <program name> <edict number>\n");
743 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
746 i = atoi (Cmd_Argv(2));
747 if (i >= prog->num_edicts)
749 Con_Print("Bad edict number\n");
753 PRVM_ED_PrintNum (i);
765 // 2 possibilities : 1. just displaying the active edict count
766 // 2. making a function pointer [x]
767 void PRVM_ED_Count_f (void)
775 Con_Print("prvm_count <program name>\n");
780 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
783 if(prog->count_edicts)
784 prog->count_edicts();
788 for (i=0 ; i<prog->num_edicts ; i++)
790 ent = PRVM_EDICT_NUM(i);
791 if (ent->priv.required->free)
796 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
797 Con_Printf("active :%3i\n", active);
804 ==============================================================================
808 FIXME: need to tag constants, doesn't really work
809 ==============================================================================
817 void PRVM_ED_WriteGlobals (qfile_t *f)
825 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
827 def = &prog->globaldefs[i];
829 if ( !(def->type & DEF_SAVEGLOBAL) )
831 type &= ~DEF_SAVEGLOBAL;
833 if (type != ev_string && type != ev_float && type != ev_entity)
836 name = PRVM_GetString(def->s_name);
837 FS_Printf(f,"\"%s\" ", name);
838 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
848 void PRVM_ED_ParseGlobals (const char *data)
850 char keyname[MAX_INPUTLINE];
856 if (!COM_ParseTokenConsole(&data))
857 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
858 if (com_token[0] == '}')
861 strlcpy (keyname, com_token, sizeof(keyname));
864 if (!COM_ParseTokenConsole(&data))
865 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
867 if (com_token[0] == '}')
868 PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
870 key = PRVM_ED_FindGlobal (keyname);
873 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
877 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
878 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
882 //============================================================================
889 Can parse either fields or globals
890 returns false if error
893 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
902 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
904 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
905 switch (key->type & ~DEF_SAVEGLOBAL)
908 l = (int)strlen(s) + 1;
909 val->string = PRVM_AllocString(l, &new_p);
910 for (i = 0;i < l;i++)
912 if (s[i] == '\\' && i < l-1)
917 else if (s[i] == 'r')
928 while (*s && *s <= ' ')
930 val->_float = atof(s);
934 for (i = 0;i < 3;i++)
936 while (*s && *s <= ' ')
940 val->vector[i] = atof(s);
949 while (*s && *s <= ' ')
952 if (i >= prog->limit_edicts)
953 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (unsigned int)i, (unsigned int)MAX_EDICTS, PRVM_NAME);
954 while (i >= prog->max_edicts)
955 PRVM_MEM_IncreaseEdicts();
956 //SV_IncreaseEdicts();
957 // if SV_IncreaseEdicts was called the base pointer needs to be updated
959 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
960 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
964 def = PRVM_ED_FindField(s);
967 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
970 val->_int = def->ofs;
974 func = PRVM_ED_FindFunction(s);
977 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
980 val->function = func - prog->functions;
984 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
994 Console command to send a string to QC function GameCommand of the
998 sv_cmd adminmsg 3 "do not teamkill"
999 cl_cmd someclientcommand
1000 menu_cmd somemenucommand
1002 All progs can support this extension; sg calls it in server QC, cg in client
1006 void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
1010 Con_Printf("%s text...\n", whichcmd);
1015 if(!PRVM_SetProgFromString(whichprogs))
1016 // note: this is not PRVM_SetProg because that one aborts "hard" using PRVM_Error
1017 // also, it makes printing error messages easier!
1019 Con_Printf("%s program not loaded.\n", whichprogs);
1023 if(!prog->funcoffsets.GameCommand)
1025 Con_Printf("%s program do not support GameCommand!\n", whichprogs);
1029 int restorevm_tempstringsbuf_cursize;
1034 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1035 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
1036 PRVM_ExecuteProgram (prog->funcoffsets.GameCommand, "QC function GameCommand is missing");
1037 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1042 void PRVM_GameCommand_Server_f(void)
1044 PRVM_GameCommand("server", "sv_cmd");
1046 void PRVM_GameCommand_Client_f(void)
1048 PRVM_GameCommand("client", "cl_cmd");
1050 void PRVM_GameCommand_Menu_f(void)
1052 PRVM_GameCommand("menu", "menu_cmd");
1059 Console command to set a field of a specified edict
1062 void PRVM_ED_EdictSet_f(void)
1069 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1074 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1076 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1080 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1082 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1083 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1085 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1091 ====================
1094 Parses an edict out of the given string, returning the new position
1095 ed should be a properly initialized empty edict.
1096 Used for initial level load and for savegames.
1097 ====================
1099 extern cvar_t developer_entityparsing;
1100 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1110 // go through all the dictionary pairs
1114 if (!COM_ParseTokenConsole(&data))
1115 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1116 if (developer_entityparsing.integer)
1117 Con_Printf("Key: \"%s\"", com_token);
1118 if (com_token[0] == '}')
1121 // anglehack is to allow QuakeEd to write single scalar angles
1122 // and allow them to be turned into vectors. (FIXME...)
1123 if (!strcmp(com_token, "angle"))
1125 strlcpy (com_token, "angles", sizeof(com_token));
1131 // FIXME: change light to _light to get rid of this hack
1132 if (!strcmp(com_token, "light"))
1133 strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def
1135 strlcpy (keyname, com_token, sizeof(keyname));
1137 // another hack to fix keynames with trailing spaces
1138 n = strlen(keyname);
1139 while (n && keyname[n-1] == ' ')
1146 if (!COM_ParseTokenConsole(&data))
1147 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1148 if (developer_entityparsing.integer)
1149 Con_Printf(" \"%s\"\n", com_token);
1151 if (com_token[0] == '}')
1152 PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1156 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1160 // keynames with a leading underscore are used for utility comments,
1161 // and are immediately discarded by quake
1162 if (keyname[0] == '_')
1165 key = PRVM_ED_FindField (keyname);
1168 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1175 strlcpy (temp, com_token, sizeof(temp));
1176 sprintf (com_token, "0 %s 0", temp);
1179 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1180 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1184 ent->priv.required->free = true;
1192 PRVM_ED_LoadFromFile
1194 The entities are directly placed in the array, rather than allocated with
1195 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1196 number references out of order.
1198 Creates a server's entity / program execution context by
1199 parsing textual entity definitions out of an ent file.
1201 Used for both fresh maps and savegame loads. A fresh map would also need
1202 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1205 void PRVM_ED_LoadFromFile (const char *data)
1208 int parsed, inhibited, spawned, died;
1220 // parse the opening brace
1221 if (!COM_ParseTokenConsole(&data))
1223 if (com_token[0] != '{')
1224 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1226 // CHANGED: this is not conform to PR_LoadFromFile
1227 if(prog->loadintoworld)
1229 prog->loadintoworld = false;
1230 ent = PRVM_EDICT_NUM(0);
1233 ent = PRVM_ED_Alloc();
1236 if (ent != prog->edicts) // hack
1237 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1239 data = PRVM_ED_ParseEdict (data, ent);
1242 // remove the entity ?
1243 if(prog->load_edict && !prog->load_edict(ent))
1251 // immediately call spawn function, but only if there is a self global and a classname
1253 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1255 string_t handle = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1258 Con_Print("No classname for:\n");
1264 // look for the spawn function
1265 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1269 if (developer.integer) // don't confuse non-developers with errors
1271 Con_Print("No spawn function for:\n");
1279 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1280 PRVM_ExecuteProgram (func - prog->functions, "");
1284 if (ent->priv.required->free)
1288 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);
1291 void PRVM_FindOffsets(void)
1293 // field and global searches use -1 for NULL
1294 memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1295 memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1296 // functions use 0 for NULL
1297 memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1299 // server and client qc use a lot of similar fields, so this is combined
1300 prog->fieldoffsets.SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
1301 prog->fieldoffsets.Version = PRVM_ED_FindFieldOffset("Version");
1302 prog->fieldoffsets.alpha = PRVM_ED_FindFieldOffset("alpha");
1303 prog->fieldoffsets.ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
1304 prog->fieldoffsets.ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1305 prog->fieldoffsets.ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1306 prog->fieldoffsets.ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
1307 prog->fieldoffsets.ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
1308 prog->fieldoffsets.ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
1309 prog->fieldoffsets.ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
1310 prog->fieldoffsets.angles = PRVM_ED_FindFieldOffset("angles");
1311 prog->fieldoffsets.button3 = PRVM_ED_FindFieldOffset("button3");
1312 prog->fieldoffsets.button4 = PRVM_ED_FindFieldOffset("button4");
1313 prog->fieldoffsets.button5 = PRVM_ED_FindFieldOffset("button5");
1314 prog->fieldoffsets.button6 = PRVM_ED_FindFieldOffset("button6");
1315 prog->fieldoffsets.button7 = PRVM_ED_FindFieldOffset("button7");
1316 prog->fieldoffsets.button8 = PRVM_ED_FindFieldOffset("button8");
1317 prog->fieldoffsets.button9 = PRVM_ED_FindFieldOffset("button9");
1318 prog->fieldoffsets.button10 = PRVM_ED_FindFieldOffset("button10");
1319 prog->fieldoffsets.button11 = PRVM_ED_FindFieldOffset("button11");
1320 prog->fieldoffsets.button12 = PRVM_ED_FindFieldOffset("button12");
1321 prog->fieldoffsets.button13 = PRVM_ED_FindFieldOffset("button13");
1322 prog->fieldoffsets.button14 = PRVM_ED_FindFieldOffset("button14");
1323 prog->fieldoffsets.button15 = PRVM_ED_FindFieldOffset("button15");
1324 prog->fieldoffsets.button16 = PRVM_ED_FindFieldOffset("button16");
1325 prog->fieldoffsets.buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
1326 prog->fieldoffsets.buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
1327 prog->fieldoffsets.chain = PRVM_ED_FindFieldOffset("chain");
1328 prog->fieldoffsets.classname = PRVM_ED_FindFieldOffset("classname");
1329 prog->fieldoffsets.clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
1330 prog->fieldoffsets.color = PRVM_ED_FindFieldOffset("color");
1331 prog->fieldoffsets.colormod = PRVM_ED_FindFieldOffset("colormod");
1332 prog->fieldoffsets.contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
1333 prog->fieldoffsets.cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
1334 prog->fieldoffsets.cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
1335 prog->fieldoffsets.cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1336 prog->fieldoffsets.cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1337 prog->fieldoffsets.cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
1338 prog->fieldoffsets.customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
1339 prog->fieldoffsets.dimension_hit = PRVM_ED_FindFieldOffset("dimension_hit");
1340 prog->fieldoffsets.dimension_solid = PRVM_ED_FindFieldOffset("dimension_solid");
1341 prog->fieldoffsets.disableclientprediction = PRVM_ED_FindFieldOffset("disableclientprediction");
1342 prog->fieldoffsets.dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1343 prog->fieldoffsets.drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
1344 prog->fieldoffsets.exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1345 prog->fieldoffsets.fatness = PRVM_ED_FindFieldOffset("fatness");
1346 prog->fieldoffsets.forceshader = PRVM_ED_FindFieldOffset("forceshader");
1347 prog->fieldoffsets.frame = PRVM_ED_FindFieldOffset("frame");
1348 prog->fieldoffsets.frame1time = PRVM_ED_FindFieldOffset("frame1time");
1349 prog->fieldoffsets.frame2 = PRVM_ED_FindFieldOffset("frame2");
1350 prog->fieldoffsets.frame2time = PRVM_ED_FindFieldOffset("frame2time");
1351 prog->fieldoffsets.fullbright = PRVM_ED_FindFieldOffset("fullbright");
1352 prog->fieldoffsets.glow_color = PRVM_ED_FindFieldOffset("glow_color");
1353 prog->fieldoffsets.glow_size = PRVM_ED_FindFieldOffset("glow_size");
1354 prog->fieldoffsets.glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
1355 prog->fieldoffsets.gravity = PRVM_ED_FindFieldOffset("gravity");
1356 prog->fieldoffsets.groundentity = PRVM_ED_FindFieldOffset("groundentity");
1357 prog->fieldoffsets.hull = PRVM_ED_FindFieldOffset("hull");
1358 prog->fieldoffsets.ideal_yaw = PRVM_ED_FindFieldOffset("ideal_yaw");
1359 prog->fieldoffsets.idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
1360 prog->fieldoffsets.items2 = PRVM_ED_FindFieldOffset("items2");
1361 prog->fieldoffsets.lerpfrac = PRVM_ED_FindFieldOffset("lerpfrac");
1362 prog->fieldoffsets.light_lev = PRVM_ED_FindFieldOffset("light_lev");
1363 prog->fieldoffsets.modelflags = PRVM_ED_FindFieldOffset("modelflags");
1364 prog->fieldoffsets.movement = PRVM_ED_FindFieldOffset("movement");
1365 prog->fieldoffsets.netaddress = PRVM_ED_FindFieldOffset("netaddress");
1366 prog->fieldoffsets.nextthink = PRVM_ED_FindFieldOffset("nextthink");
1367 prog->fieldoffsets.nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
1368 prog->fieldoffsets.pflags = PRVM_ED_FindFieldOffset("pflags");
1369 prog->fieldoffsets.ping = PRVM_ED_FindFieldOffset("ping");
1370 prog->fieldoffsets.pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
1371 prog->fieldoffsets.playermodel = PRVM_ED_FindFieldOffset("playermodel");
1372 prog->fieldoffsets.playerskin = PRVM_ED_FindFieldOffset("playerskin");
1373 prog->fieldoffsets.pmodel = PRVM_ED_FindFieldOffset("pmodel");
1374 prog->fieldoffsets.punchvector = PRVM_ED_FindFieldOffset("punchvector");
1375 prog->fieldoffsets.renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1376 prog->fieldoffsets.renderflags = PRVM_ED_FindFieldOffset("renderflags");
1377 prog->fieldoffsets.rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1378 prog->fieldoffsets.scale = PRVM_ED_FindFieldOffset("scale");
1379 prog->fieldoffsets.style = PRVM_ED_FindFieldOffset("style");
1380 prog->fieldoffsets.tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
1381 prog->fieldoffsets.tag_index = PRVM_ED_FindFieldOffset("tag_index");
1382 prog->fieldoffsets.think = PRVM_ED_FindFieldOffset("think");
1383 prog->fieldoffsets.viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
1384 prog->fieldoffsets.viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
1385 prog->fieldoffsets.yaw_speed = PRVM_ED_FindFieldOffset("yaw_speed");
1386 prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1387 prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1388 prog->funcoffsets.CSQC_Ent_Update = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1389 prog->funcoffsets.CSQC_Event = PRVM_ED_FindFunctionOffset("CSQC_Event");
1390 prog->funcoffsets.CSQC_Init = PRVM_ED_FindFunctionOffset("CSQC_Init");
1391 prog->funcoffsets.CSQC_InputEvent = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1392 prog->funcoffsets.CSQC_Parse_CenterPrint = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1393 prog->funcoffsets.CSQC_Parse_Print = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1394 prog->funcoffsets.CSQC_Parse_StuffCmd = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1395 prog->funcoffsets.CSQC_Parse_TempEntity = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1396 prog->funcoffsets.CSQC_Shutdown = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1397 prog->funcoffsets.CSQC_UpdateView = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1398 prog->funcoffsets.EndFrame = PRVM_ED_FindFunctionOffset("EndFrame");
1399 prog->funcoffsets.RestoreGame = PRVM_ED_FindFunctionOffset("RestoreGame");
1400 prog->funcoffsets.SV_ChangeTeam = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1401 prog->funcoffsets.SV_ParseClientCommand = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1402 prog->funcoffsets.SV_PlayerPhysics = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1403 prog->funcoffsets.GameCommand = PRVM_ED_FindFunctionOffset("GameCommand");
1404 prog->globaloffsets.SV_InitCmd = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1405 prog->globaloffsets.self = PRVM_ED_FindGlobalOffset("self");
1406 prog->globaloffsets.time = PRVM_ED_FindGlobalOffset("time");
1407 prog->globaloffsets.v_forward = PRVM_ED_FindGlobalOffset("v_forward");
1408 prog->globaloffsets.v_right = PRVM_ED_FindGlobalOffset("v_right");
1409 prog->globaloffsets.v_up = PRVM_ED_FindGlobalOffset("v_up");
1410 prog->globaloffsets.trace_allsolid = PRVM_ED_FindGlobalOffset("trace_allsolid");
1411 prog->globaloffsets.trace_startsolid = PRVM_ED_FindGlobalOffset("trace_startsolid");
1412 prog->globaloffsets.trace_fraction = PRVM_ED_FindGlobalOffset("trace_fraction");
1413 prog->globaloffsets.trace_inwater = PRVM_ED_FindGlobalOffset("trace_inwater");
1414 prog->globaloffsets.trace_inopen = PRVM_ED_FindGlobalOffset("trace_inopen");
1415 prog->globaloffsets.trace_endpos = PRVM_ED_FindGlobalOffset("trace_endpos");
1416 prog->globaloffsets.trace_plane_normal = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1417 prog->globaloffsets.trace_plane_dist = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1418 prog->globaloffsets.trace_ent = PRVM_ED_FindGlobalOffset("trace_ent");
1419 prog->globaloffsets.trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1420 prog->globaloffsets.trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1421 prog->globaloffsets.trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1422 prog->globaloffsets.trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1424 // menu qc only uses some functions, nothing else
1425 prog->funcoffsets.m_display = PRVM_ED_FindFunctionOffset("m_display");
1426 prog->funcoffsets.m_draw = PRVM_ED_FindFunctionOffset("m_draw");
1427 prog->funcoffsets.m_hide = PRVM_ED_FindFunctionOffset("m_hide");
1428 prog->funcoffsets.m_init = PRVM_ED_FindFunctionOffset("m_init");
1429 prog->funcoffsets.m_keydown = PRVM_ED_FindFunctionOffset("m_keydown");
1430 prog->funcoffsets.m_keyup = PRVM_ED_FindFunctionOffset("m_keyup");
1431 prog->funcoffsets.m_shutdown = PRVM_ED_FindFunctionOffset("m_shutdown");
1432 prog->funcoffsets.m_toggle = PRVM_ED_FindFunctionOffset("m_toggle");
1437 typedef struct dpfield_s
1444 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1446 dpfield_t dpfields[] =
1457 void PRVM_ResetProg()
1459 PRVM_GCALL(reset_cmd)();
1460 Mem_FreePool(&prog->progs_mempool);
1461 memset(prog,0,sizeof(prvm_prog_t));
1469 void PRVM_LoadLNO( const char *progname ) {
1470 fs_offset_t filesize;
1472 unsigned int *header;
1475 FS_StripExtension( progname, filename, sizeof( filename ) );
1476 strlcat( filename, ".lno", sizeof( filename ) );
1478 lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1484 <Spike> SafeWrite (h, &lnotype, sizeof(int));
1485 <Spike> SafeWrite (h, &version, sizeof(int));
1486 <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
1487 <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
1488 <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
1489 <Spike> SafeWrite (h, &numstatements, sizeof(int));
1490 <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1492 if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1497 header = (unsigned int *) lno;
1498 if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1499 LittleLong( header[ 1 ] ) == 1 &&
1500 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1501 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1502 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1503 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1505 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1506 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1516 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1520 ddef_t *infielddefs;
1521 dfunction_t *dfunctions;
1522 fs_offset_t filesize;
1524 if( prog->loaded ) {
1525 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1528 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1529 if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1530 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1532 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1534 prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1536 // byte swap the header
1537 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1538 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1540 if (prog->progs->version != PROG_VERSION)
1541 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1542 if (prog->progs->crc != prog->headercrc)
1543 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1545 //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1546 dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1548 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1549 prog->stringssize = 0;
1550 for (i = 0;i < prog->progs->numstrings;i++)
1552 if (prog->progs->ofs_strings + prog->stringssize >= (int)filesize)
1553 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1554 prog->stringssize += (int)strlen (prog->strings + prog->stringssize) + 1;
1556 prog->numknownstrings = 0;
1557 prog->maxknownstrings = 0;
1558 prog->knownstrings = NULL;
1559 prog->knownstrings_freeable = NULL;
1561 prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1563 // we need to expand the fielddefs list to include all the engine fields,
1564 // so allocate a new place for it
1565 infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1567 prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1569 prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1571 prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1573 // moved edict_size calculation down below field adding code
1575 //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1576 prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1578 // byte swap the lumps
1579 for (i=0 ; i<prog->progs->numstatements ; i++)
1581 prog->statements[i].op = LittleShort(prog->statements[i].op);
1582 prog->statements[i].a = LittleShort(prog->statements[i].a);
1583 prog->statements[i].b = LittleShort(prog->statements[i].b);
1584 prog->statements[i].c = LittleShort(prog->statements[i].c);
1587 prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1588 for (i = 0;i < prog->progs->numfunctions;i++)
1590 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1591 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1592 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1593 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1594 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1595 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1596 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1599 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1601 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1602 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1603 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1606 // copy the progs fields to the new fields list
1607 for (i = 0;i < prog->progs->numfielddefs;i++)
1609 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1610 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1611 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1612 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1613 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1616 // append the required fields
1617 for (i = 0;i < (int) numrequiredfields;i++)
1619 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1620 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1621 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1622 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1623 prog->progs->entityfields += 3;
1625 prog->progs->entityfields++;
1626 prog->progs->numfielddefs++;
1629 // check required functions
1630 for(i=0 ; i < numrequiredfunc ; i++)
1631 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1632 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1634 // check required globals
1635 for(i=0 ; i < numrequiredglobals ; i++)
1636 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1637 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1639 for (i=0 ; i<prog->progs->numglobals ; i++)
1640 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1642 // moved edict_size calculation down here, below field adding code
1643 // LordHavoc: this no longer includes the prvm_edict_t header
1644 prog->edict_size = prog->progs->entityfields * 4;
1645 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1647 // LordHavoc: bounds check anything static
1648 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1654 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1655 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1658 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1659 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1661 // global global global
1696 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1697 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1699 // global none global
1705 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1706 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1722 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1723 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1737 if ((unsigned short) st->a >= prog->progs->numglobals)
1738 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1741 Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1746 PRVM_LoadLNO(filename);
1750 prog->loaded = TRUE;
1752 // set flags & ddef_ts in prog
1758 PRVM_GCALL(init_cmd)();
1765 void PRVM_Fields_f (void)
1767 int i, j, ednum, used, usedamount;
1769 char tempstring[MAX_INPUTLINE], tempstring2[260];
1779 Con_Print("no progs loaded\n");
1786 Con_Print("prvm_fields <program name>\n");
1791 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1794 counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1795 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1797 ed = PRVM_EDICT_NUM(ednum);
1798 if (ed->priv.required->free)
1800 for (i = 1;i < prog->progs->numfielddefs;i++)
1802 d = &prog->fielddefs[i];
1803 name = PRVM_GetString(d->s_name);
1804 if (name[strlen(name)-2] == '_')
1805 continue; // skip _x, _y, _z vars
1806 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1807 // if the value is still all 0, skip the field
1808 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1821 for (i = 0;i < prog->progs->numfielddefs;i++)
1823 d = &prog->fielddefs[i];
1824 name = PRVM_GetString(d->s_name);
1825 if (name[strlen(name)-2] == '_')
1826 continue; // skip _x, _y, _z vars
1827 switch(d->type & ~DEF_SAVEGLOBAL)
1830 strlcat(tempstring, "string ", sizeof(tempstring));
1833 strlcat(tempstring, "entity ", sizeof(tempstring));
1836 strlcat(tempstring, "function ", sizeof(tempstring));
1839 strlcat(tempstring, "field ", sizeof(tempstring));
1842 strlcat(tempstring, "void ", sizeof(tempstring));
1845 strlcat(tempstring, "float ", sizeof(tempstring));
1848 strlcat(tempstring, "vector ", sizeof(tempstring));
1851 strlcat(tempstring, "pointer ", sizeof(tempstring));
1854 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1855 strlcat(tempstring, tempstring2, sizeof(tempstring));
1858 if (strlen(name) > sizeof(tempstring2)-4)
1860 memcpy (tempstring2, name, sizeof(tempstring2)-4);
1861 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1862 tempstring2[sizeof(tempstring2)-1] = 0;
1865 strlcat(tempstring, name, sizeof(tempstring));
1866 for (j = (int)strlen(name);j < 25;j++)
1867 strlcat(tempstring, " ", sizeof(tempstring));
1868 sprintf(tempstring2, "%5d", counts[i]);
1869 strlcat(tempstring, tempstring2, sizeof(tempstring));
1870 strlcat(tempstring, "\n", sizeof(tempstring));
1871 if (strlen(tempstring) >= sizeof(tempstring)/2)
1873 Con_Print(tempstring);
1879 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1883 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);
1888 void PRVM_Globals_f (void)
1894 Con_Print("no progs loaded\n");
1897 if(Cmd_Argc () != 2)
1899 Con_Print("prvm_globals <program name>\n");
1904 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1907 Con_Printf("%s :", PRVM_NAME);
1909 for (i = 0;i < prog->progs->numglobaldefs;i++)
1910 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1911 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1921 void PRVM_Global_f(void)
1924 if( Cmd_Argc() != 3 ) {
1925 Con_Printf( "prvm_global <program name> <global name>\n" );
1930 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1933 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1935 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1937 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1946 void PRVM_GlobalSet_f(void)
1949 if( Cmd_Argc() != 4 ) {
1950 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1955 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1958 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1960 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1962 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1971 void PRVM_Init (void)
1973 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
1974 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
1975 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
1976 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
1977 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)");
1978 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
1979 Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
1980 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
1981 Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)");
1982 Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
1983 Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
1984 Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
1985 Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
1986 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1987 Cvar_RegisterVariable (&prvm_boundscheck);
1988 Cvar_RegisterVariable (&prvm_traceqc);
1989 Cvar_RegisterVariable (&prvm_statementprofiling);
1999 void PRVM_InitProg(int prognr)
2001 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
2002 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
2004 prog = &prog_list[prognr];
2009 memset(prog, 0, sizeof(prvm_prog_t));
2011 prog->error_cmd = Host_Error;
2014 int PRVM_GetProgNr()
2016 return prog - prog_list;
2019 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
2021 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
2024 void _PRVM_Free(void *buffer, const char *filename, int fileline)
2026 _Mem_Free(buffer, filename, fileline);
2029 void _PRVM_FreeAll(const char *filename, int fileline)
2032 prog->fielddefs = NULL;
2033 prog->functions = NULL;
2034 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
2037 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2038 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
2040 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
2045 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
2047 PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
2051 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
2054 n = e - prog->edicts;
2055 if ((unsigned int)n >= prog->limit_edicts)
2056 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
2060 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
2062 // return e - prog->edicts;
2065 //#define PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
2066 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
2067 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
2070 n = e - prog->edicts;
2071 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2072 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2073 return n;// EXPERIMENTAL
2074 //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2076 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2078 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2079 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2080 return prog->edicts + n; // EXPERIMENTAL
2081 //return prog->edicts + ((n) / (progs->entityfields * 4));
2086 sizebuf_t vm_tempstringsbuf;
2088 const char *PRVM_GetString(int num)
2092 if (num < prog->stringssize)
2093 return prog->strings + num;
2096 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2098 num -= prog->stringssize;
2099 if (num < vm_tempstringsbuf.cursize)
2100 return (char *)vm_tempstringsbuf.data + num;
2103 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2110 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
2120 // special range reserved for tempstrings
2122 if (num < vm_tempstringsbuf.cursize)
2123 return (char *)vm_tempstringsbuf.data + num;
2126 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
2132 if (num < prog->numknownstrings)
2134 if (!prog->knownstrings[num])
2135 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
2136 return prog->knownstrings[num];
2140 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
2146 int PRVM_SetEngineString(const char *s)
2151 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2152 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2153 // if it's in the tempstrings area, use a reserved range
2154 // (otherwise we'd get millions of useless string offsets cluttering the database)
2155 if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2157 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2159 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2161 // see if it's a known string address
2162 for (i = 0;i < prog->numknownstrings;i++)
2163 if (prog->knownstrings[i] == s)
2165 // new unknown engine string
2166 if (developer.integer >= 200)
2167 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2168 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2169 if (!prog->knownstrings[i])
2171 if (i >= prog->numknownstrings)
2173 if (i >= prog->maxknownstrings)
2175 const char **oldstrings = prog->knownstrings;
2176 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2177 prog->maxknownstrings += 128;
2178 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2179 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2180 if (prog->numknownstrings)
2182 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2183 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2186 prog->numknownstrings++;
2188 prog->firstfreeknownstring = i + 1;
2189 prog->knownstrings[i] = s;
2193 // temp string handling
2195 // all tempstrings go into this buffer consecutively, and it is reset
2196 // whenever PRVM_ExecuteProgram returns to the engine
2197 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2198 // restores it on return, so multiple recursive calls can share the same
2200 // the buffer size is automatically grown as needed
2202 int PRVM_SetTempString(const char *s)
2208 size = (int)strlen(s) + 1;
2209 if (developer.integer >= 300)
2210 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2211 if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2213 sizebuf_t old = vm_tempstringsbuf;
2214 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2215 PRVM_ERROR("PRVM_SetTempString: ran out of tempstring memory! (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", vm_tempstringsbuf.cursize, size);
2216 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2217 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2218 vm_tempstringsbuf.maxsize *= 2;
2219 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2221 if (developer.integer >= 100)
2222 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2223 vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2225 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2230 t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2232 vm_tempstringsbuf.cursize += size;
2233 return PRVM_SetEngineString(t);
2236 int PRVM_AllocString(size_t bufferlength, char **pointer)
2241 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2242 if (!prog->knownstrings[i])
2244 if (i >= prog->numknownstrings)
2246 if (i >= prog->maxknownstrings)
2248 const char **oldstrings = prog->knownstrings;
2249 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2250 prog->maxknownstrings += 128;
2251 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2252 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2253 if (prog->numknownstrings)
2255 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2256 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2259 prog->numknownstrings++;
2261 prog->firstfreeknownstring = i + 1;
2262 prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2263 prog->knownstrings_freeable[i] = true;
2265 *pointer = (char *)(prog->knownstrings[i]);
2269 void PRVM_FreeString(int num)
2272 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2273 else if (num >= 0 && num < prog->stringssize)
2274 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2275 else if (num < 0 && num >= -prog->numknownstrings)
2278 if (!prog->knownstrings[num])
2279 PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2280 if (!prog->knownstrings[num])
2281 PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2282 PRVM_Free((char *)prog->knownstrings[num]);
2283 prog->knownstrings[num] = NULL;
2284 prog->knownstrings_freeable[num] = false;
2285 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2288 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);