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, qboolean parsebackslash);
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 #ifdef PRVM_BOUNDSCHECK_CVAR
36 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)"};
38 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
39 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
40 // LordHavoc: counts usage of each QuakeC statement
41 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)"};
42 cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"};
44 extern sizebuf_t vm_tempstringsbuf;
46 //============================================================================
54 void PRVM_MEM_Alloc(void)
58 // reserve space for the null entity aka world
59 // check bound of max_edicts
60 prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
61 prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
63 // edictprivate_size has to be min as big prvm_edict_private_t
64 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
67 prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
69 // alloc edict private space
70 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
73 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
76 for(i = 0; i < prog->max_edicts; i++)
78 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
79 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
85 PRVM_MEM_IncreaseEdicts
88 void PRVM_MEM_IncreaseEdicts(void)
91 int oldmaxedicts = prog->max_edicts;
92 void *oldedictsfields = prog->edictsfields;
93 void *oldedictprivate = prog->edictprivate;
95 if(prog->max_edicts >= prog->limit_edicts)
98 PRVM_GCALL(begin_increase_edicts)();
101 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
103 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
104 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
106 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
107 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
109 //set e and v pointers
110 for(i = 0; i < prog->max_edicts; i++)
112 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
113 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
116 PRVM_GCALL(end_increase_edicts)();
118 Mem_Free(oldedictsfields);
119 Mem_Free(oldedictprivate);
122 //============================================================================
125 int PRVM_ED_FindFieldOffset(const char *field)
128 d = PRVM_ED_FindField(field);
134 int PRVM_ED_FindGlobalOffset(const char *global)
137 d = PRVM_ED_FindGlobal(global);
143 func_t PRVM_ED_FindFunctionOffset(const char *function)
146 f = PRVM_ED_FindFunction(function);
149 return (func_t)(f - prog->functions);
152 qboolean PRVM_ProgLoaded(int prognr)
154 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
157 return (prog_list[prognr].loaded ? TRUE : FALSE);
162 PRVM_SetProgFromString
165 // perhaps add a return value when the str doesnt exist
166 qboolean PRVM_SetProgFromString(const char *str)
169 for(; i < PRVM_MAXPROGS ; i++)
170 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
172 if(prog_list[i].loaded)
174 prog = &prog_list[i];
179 Con_Printf("%s not loaded !\n",PRVM_NAME);
184 Con_Printf("Invalid program name %s !\n", str);
193 void PRVM_SetProg(int prognr)
195 if(0 <= prognr && prognr < PRVM_MAXPROGS)
197 if(prog_list[prognr].loaded)
198 prog = &prog_list[prognr];
200 PRVM_ERROR("%i not loaded !", prognr);
203 PRVM_ERROR("Invalid program number %i", prognr);
210 Sets everything to NULL
213 void PRVM_ED_ClearEdict (prvm_edict_t *e)
215 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
216 e->priv.required->free = false;
218 // AK: Let the init_edict function determine if something needs to be initialized
219 PRVM_GCALL(init_edict)(e);
226 Either finds a free edict, or allocates a new one.
227 Try to avoid reusing an entity that was recently freed, because it
228 can cause the client to think the entity morphed into something else
229 instead of being removed and recreated, which can cause interpolated
230 angles and bad trails.
233 prvm_edict_t *PRVM_ED_Alloc (void)
238 // the client qc dont need maxclients
239 // thus it doesnt need to use svs.maxclients
240 // AK: changed i=svs.maxclients+1
241 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
242 // although the menu/client has no world
243 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
245 e = PRVM_EDICT_NUM(i);
246 // the first couple seconds of server time can involve a lot of
247 // freeing and allocating, so relax the replacement policy
248 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 ) )
250 PRVM_ED_ClearEdict (e);
255 if (i == prog->limit_edicts)
256 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
259 if (prog->num_edicts >= prog->max_edicts)
260 PRVM_MEM_IncreaseEdicts();
262 e = PRVM_EDICT_NUM(i);
263 PRVM_ED_ClearEdict (e);
272 Marks the edict as free
273 FIXME: walk all entities and NULL out references to this entity
276 void PRVM_ED_Free (prvm_edict_t *ed)
278 // dont delete the null entity (world) or reserved edicts
279 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
282 PRVM_GCALL(free_edict)(ed);
284 ed->priv.required->free = true;
285 ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0;
288 //===========================================================================
295 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
300 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
302 def = &prog->globaldefs[i];
314 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
319 for (i=0 ; i<prog->progs->numfielddefs ; i++)
321 def = &prog->fielddefs[i];
333 ddef_t *PRVM_ED_FindField (const char *name)
338 for (i=0 ; i<prog->progs->numfielddefs ; i++)
340 def = &prog->fielddefs[i];
341 if (!strcmp(PRVM_GetString(def->s_name), name))
352 ddef_t *PRVM_ED_FindGlobal (const char *name)
357 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
359 def = &prog->globaldefs[i];
360 if (!strcmp(PRVM_GetString(def->s_name), name))
372 mfunction_t *PRVM_ED_FindFunction (const char *name)
377 for (i=0 ; i<prog->progs->numfunctions ; i++)
379 func = &prog->functions[i];
380 if (!strcmp(PRVM_GetString(func->s_name), name))
391 Returns a string describing *data in a type specific manner
394 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
396 static char line[MAX_INPUTLINE];
401 type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
406 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
410 if (n < 0 || n >= prog->limit_edicts)
411 sprintf (line, "entity %i (invalid!)", n);
413 sprintf (line, "entity %i", n);
416 f = prog->functions + val->function;
417 sprintf (line, "%s()", PRVM_GetString(f->s_name));
420 def = PRVM_ED_FieldAtOfs ( val->_int );
421 sprintf (line, ".%s", PRVM_GetString(def->s_name));
424 sprintf (line, "void");
427 // LordHavoc: changed from %5.1f to %10.4f
428 sprintf (line, "%10.4f", val->_float);
431 // LordHavoc: changed from %5.1f to %10.4f
432 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
435 sprintf (line, "pointer");
438 sprintf (line, "bad type %i", (int) type);
449 Returns a string describing *data in a type specific manner
450 Easier to parse than PR_ValueString
453 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
455 static char line[MAX_INPUTLINE];
461 type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
466 // Parse the string a bit to turn special characters
467 // (like newline, specifically) into escape codes,
468 // this fixes saving games from various mods
469 s = PRVM_GetString (val->string);
470 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
494 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
497 f = prog->functions + val->function;
498 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
501 def = PRVM_ED_FieldAtOfs ( val->_int );
502 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
505 dpsnprintf (line, sizeof (line), "void");
508 dpsnprintf (line, sizeof (line), "%f", val->_float);
511 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
514 dpsnprintf (line, sizeof (line), "bad type %i", type);
525 Returns a string with a description and the contents of a global,
526 padded to 20 field width
529 char *PRVM_GlobalString (int ofs)
535 static char line[128];
537 val = (void *)&prog->globals.generic[ofs];
538 def = PRVM_ED_GlobalAtOfs(ofs);
540 sprintf (line,"GLOBAL%i", ofs);
543 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
544 sprintf (line,"%s (=%s)", PRVM_GetString(def->s_name), s);
548 //for ( ; i<20 ; i++)
549 // strcat (line," ");
555 char *PRVM_GlobalStringNoContents (int ofs)
559 static char line[128];
561 def = PRVM_ED_GlobalAtOfs(ofs);
563 sprintf (line,"GLOBAL%i", ofs);
565 sprintf (line,"%s", PRVM_GetString(def->s_name));
568 //for ( ; i<20 ; i++)
569 // strcat (line," ");
583 // LordHavoc: optimized this to print out much more quickly (tempstring)
584 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
585 void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
593 char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
595 if (ed->priv.required->free)
597 Con_Printf("%s: FREE\n",PRVM_NAME);
602 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
603 for (i=1 ; i<prog->progs->numfielddefs ; i++)
605 d = &prog->fielddefs[i];
606 name = PRVM_GetString(d->s_name);
607 if (name[strlen(name)-2] == '_')
608 continue; // skip _x, _y, _z vars
610 // Check Field Name Wildcard
611 if(wildcard_fieldname)
612 if( !matchpattern(name, wildcard_fieldname, 1) )
613 // Didn't match; skip
616 v = (int *)((char *)ed->fields.vp + d->ofs*4);
618 // if the value is still all 0, skip the field
619 type = d->type & ~DEF_SAVEGLOBAL;
621 for (j=0 ; j<prvm_type_size[type] ; j++)
624 if (j == prvm_type_size[type])
627 if (strlen(name) > sizeof(tempstring2)-4)
629 memcpy (tempstring2, name, sizeof(tempstring2)-4);
630 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
631 tempstring2[sizeof(tempstring2)-1] = 0;
634 strlcat(tempstring, name, sizeof(tempstring));
635 for (l = strlen(name);l < 14;l++)
636 strlcat(tempstring, " ", sizeof(tempstring));
637 strlcat(tempstring, " ", sizeof(tempstring));
639 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
640 if (strlen(name) > sizeof(tempstring2)-4)
642 memcpy (tempstring2, name, sizeof(tempstring2)-4);
643 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
644 tempstring2[sizeof(tempstring2)-1] = 0;
647 strlcat(tempstring, name, sizeof(tempstring));
648 strlcat(tempstring, "\n", sizeof(tempstring));
649 if (strlen(tempstring) >= sizeof(tempstring)/2)
651 Con_Print(tempstring);
656 Con_Print(tempstring);
666 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
676 if (ed->priv.required->free)
682 for (i=1 ; i<prog->progs->numfielddefs ; i++)
684 d = &prog->fielddefs[i];
685 name = PRVM_GetString(d->s_name);
686 if (name[strlen(name)-2] == '_')
687 continue; // skip _x, _y, _z vars
689 v = (int *)((char *)ed->fields.vp + d->ofs*4);
691 // if the value is still all 0, skip the field
692 type = d->type & ~DEF_SAVEGLOBAL;
693 for (j=0 ; j<prvm_type_size[type] ; j++)
696 if (j == prvm_type_size[type])
699 FS_Printf(f,"\"%s\" ",name);
700 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
706 void PRVM_ED_PrintNum (int ent, const char *wildcard_fieldname)
708 PRVM_ED_Print(PRVM_EDICT_NUM(ent), wildcard_fieldname);
713 PRVM_ED_PrintEdicts_f
715 For debugging, prints all the entities in the current server
718 void PRVM_ED_PrintEdicts_f (void)
721 const char *wildcard_fieldname;
723 if(Cmd_Argc() < 2 || Cmd_Argc() > 3)
725 Con_Print("prvm_edicts <program name> <optional field name wildcard>\n");
730 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
734 wildcard_fieldname = Cmd_Argv(2);
736 wildcard_fieldname = NULL;
738 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
739 for (i=0 ; i<prog->num_edicts ; i++)
740 PRVM_ED_PrintNum (i, wildcard_fieldname);
749 For debugging, prints a single edict
752 void PRVM_ED_PrintEdict_f (void)
755 const char *wildcard_fieldname;
757 if(Cmd_Argc() < 3 || Cmd_Argc() > 4)
759 Con_Print("prvm_edict <program name> <edict number> <optional field name wildcard>\n");
764 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
767 i = atoi (Cmd_Argv(2));
768 if (i >= prog->num_edicts)
770 Con_Print("Bad edict number\n");
775 // Optional Wildcard Provided
776 wildcard_fieldname = Cmd_Argv(3);
779 wildcard_fieldname = NULL;
780 PRVM_ED_PrintNum (i, wildcard_fieldname);
792 // 2 possibilities : 1. just displaying the active edict count
793 // 2. making a function pointer [x]
794 void PRVM_ED_Count_f (void)
802 Con_Print("prvm_count <program name>\n");
807 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
810 if(prog->count_edicts)
811 prog->count_edicts();
815 for (i=0 ; i<prog->num_edicts ; i++)
817 ent = PRVM_EDICT_NUM(i);
818 if (ent->priv.required->free)
823 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
824 Con_Printf("active :%3i\n", active);
831 ==============================================================================
835 FIXME: need to tag constants, doesn't really work
836 ==============================================================================
844 void PRVM_ED_WriteGlobals (qfile_t *f)
852 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
854 def = &prog->globaldefs[i];
856 if ( !(def->type & DEF_SAVEGLOBAL) )
858 type &= ~DEF_SAVEGLOBAL;
860 if (type != ev_string && type != ev_float && type != ev_entity)
863 name = PRVM_GetString(def->s_name);
864 FS_Printf(f,"\"%s\" ", name);
865 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
875 void PRVM_ED_ParseGlobals (const char *data)
877 char keyname[MAX_INPUTLINE];
883 if (!COM_ParseToken_Simple(&data, false, false))
884 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
885 if (com_token[0] == '}')
888 strlcpy (keyname, com_token, sizeof(keyname));
891 if (!COM_ParseToken_Simple(&data, false, true))
892 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
894 if (com_token[0] == '}')
895 PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
897 key = PRVM_ED_FindGlobal (keyname);
900 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
904 if (!PRVM_ED_ParseEpair(NULL, key, com_token, true))
905 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
909 //============================================================================
916 Can parse either fields or globals
917 returns false if error
920 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
929 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
931 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
932 switch (key->type & ~DEF_SAVEGLOBAL)
935 l = (int)strlen(s) + 1;
936 val->string = PRVM_AllocString(l, &new_p);
937 for (i = 0;i < l;i++)
939 if (s[i] == '\\' && s[i+1] && parsebackslash)
944 else if (s[i] == 'r')
955 while (*s && *s <= ' ')
957 val->_float = atof(s);
961 for (i = 0;i < 3;i++)
963 while (*s && *s <= ' ')
967 val->vector[i] = atof(s);
976 while (*s && *s <= ' ')
979 if (i >= prog->limit_edicts)
980 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);
981 while (i >= prog->max_edicts)
982 PRVM_MEM_IncreaseEdicts();
983 // if IncreaseEdicts was called the base pointer needs to be updated
985 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
986 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
992 Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, PRVM_NAME);
995 def = PRVM_ED_FindField(s + 1);
998 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
1001 val->_int = def->ofs;
1005 func = PRVM_ED_FindFunction(s);
1008 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
1011 val->function = func - prog->functions;
1015 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
1025 Console command to send a string to QC function GameCommand of the
1029 sv_cmd adminmsg 3 "do not teamkill"
1030 cl_cmd someclientcommand
1031 menu_cmd somemenucommand
1033 All progs can support this extension; sg calls it in server QC, cg in client
1037 void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
1041 Con_Printf("%s text...\n", whichcmd);
1046 if(!PRVM_SetProgFromString(whichprogs))
1047 // note: this is not PRVM_SetProg because that one aborts "hard" using PRVM_Error
1048 // also, it makes printing error messages easier!
1050 Con_Printf("%s program not loaded.\n", whichprogs);
1054 if(!prog->funcoffsets.GameCommand)
1056 Con_Printf("%s program do not support GameCommand!\n", whichprogs);
1060 int restorevm_tempstringsbuf_cursize;
1065 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1066 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
1067 PRVM_ExecuteProgram (prog->funcoffsets.GameCommand, "QC function GameCommand is missing");
1068 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1073 void PRVM_GameCommand_Server_f(void)
1075 PRVM_GameCommand("server", "sv_cmd");
1077 void PRVM_GameCommand_Client_f(void)
1079 PRVM_GameCommand("client", "cl_cmd");
1081 void PRVM_GameCommand_Menu_f(void)
1083 PRVM_GameCommand("menu", "menu_cmd");
1090 Console command to set a field of a specified edict
1093 void PRVM_ED_EdictSet_f(void)
1100 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1105 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1107 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1111 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1113 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1114 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1116 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4), true);
1122 ====================
1125 Parses an edict out of the given string, returning the new position
1126 ed should be a properly initialized empty edict.
1127 Used for initial level load and for savegames.
1128 ====================
1130 extern cvar_t developer_entityparsing;
1131 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1141 // go through all the dictionary pairs
1145 if (!COM_ParseToken_Simple(&data, false, false))
1146 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1147 if (developer_entityparsing.integer)
1148 Con_Printf("Key: \"%s\"", com_token);
1149 if (com_token[0] == '}')
1152 // anglehack is to allow QuakeEd to write single scalar angles
1153 // and allow them to be turned into vectors. (FIXME...)
1154 if (!strcmp(com_token, "angle"))
1156 strlcpy (com_token, "angles", sizeof(com_token));
1162 // FIXME: change light to _light to get rid of this hack
1163 if (!strcmp(com_token, "light"))
1164 strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def
1166 strlcpy (keyname, com_token, sizeof(keyname));
1168 // another hack to fix keynames with trailing spaces
1169 n = strlen(keyname);
1170 while (n && keyname[n-1] == ' ')
1177 if (!COM_ParseToken_Simple(&data, false, false))
1178 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1179 if (developer_entityparsing.integer)
1180 Con_Printf(" \"%s\"\n", com_token);
1182 if (com_token[0] == '}')
1183 PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1187 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1191 // keynames with a leading underscore are used for utility comments,
1192 // and are immediately discarded by quake
1193 if (keyname[0] == '_')
1196 key = PRVM_ED_FindField (keyname);
1199 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1206 strlcpy (temp, com_token, sizeof(temp));
1207 sprintf (com_token, "0 %s 0", temp);
1210 if (!PRVM_ED_ParseEpair(ent, key, com_token, strcmp(keyname, "wad") != 0))
1211 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1215 ent->priv.required->free = true;
1223 PRVM_ED_LoadFromFile
1225 The entities are directly placed in the array, rather than allocated with
1226 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1227 number references out of order.
1229 Creates a server's entity / program execution context by
1230 parsing textual entity definitions out of an ent file.
1232 Used for both fresh maps and savegame loads. A fresh map would also need
1233 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1236 void PRVM_ED_LoadFromFile (const char *data)
1239 int parsed, inhibited, spawned, died;
1240 const char *funcname;
1252 // parse the opening brace
1253 if (!COM_ParseToken_Simple(&data, false, false))
1255 if (com_token[0] != '{')
1256 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1258 // CHANGED: this is not conform to PR_LoadFromFile
1259 if(prog->loadintoworld)
1261 prog->loadintoworld = false;
1262 ent = PRVM_EDICT_NUM(0);
1265 ent = PRVM_ED_Alloc();
1268 if (ent != prog->edicts) // hack
1269 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1271 data = PRVM_ED_ParseEdict (data, ent);
1274 // remove the entity ?
1275 if(prog->load_edict && !prog->load_edict(ent))
1283 // immediately call spawn function, but only if there is a self global and a classname
1285 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1287 string_t handle = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1290 Con_Print("No classname for:\n");
1291 PRVM_ED_Print(ent, NULL);
1296 // look for the spawn function
1297 funcname = PRVM_GetString(handle);
1298 func = PRVM_ED_FindFunction (va("spawnfunc_%s", funcname));
1300 if(prog->globaloffsets.require_spawnfunc_prefix < 0)
1301 func = PRVM_ED_FindFunction (funcname);
1305 // check for OnEntityNoSpawnFunction
1306 if (prog->funcoffsets.SV_OnEntityNoSpawnFunction)
1309 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1310 PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityNoSpawnFunction, "QC function SV_OnEntityNoSpawnFunction is missing");
1314 if (developer.integer) // don't confuse non-developers with errors
1316 Con_Print("No spawn function for:\n");
1317 PRVM_ED_Print(ent, NULL);
1326 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1327 PRVM_ExecuteProgram (func - prog->functions, "");
1332 if (ent->priv.required->free)
1336 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);
1339 void PRVM_FindOffsets(void)
1341 // field and global searches use -1 for NULL
1342 memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1343 memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1344 // functions use 0 for NULL
1345 memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1347 // server and client qc use a lot of similar fields, so this is combined
1348 prog->fieldoffsets.SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
1349 prog->fieldoffsets.Version = PRVM_ED_FindFieldOffset("Version");
1350 prog->fieldoffsets.alpha = PRVM_ED_FindFieldOffset("alpha");
1351 prog->fieldoffsets.ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
1352 prog->fieldoffsets.ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1353 prog->fieldoffsets.ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1354 prog->fieldoffsets.ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
1355 prog->fieldoffsets.ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
1356 prog->fieldoffsets.ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
1357 prog->fieldoffsets.ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
1358 prog->fieldoffsets.angles = PRVM_ED_FindFieldOffset("angles");
1359 prog->fieldoffsets.button3 = PRVM_ED_FindFieldOffset("button3");
1360 prog->fieldoffsets.button4 = PRVM_ED_FindFieldOffset("button4");
1361 prog->fieldoffsets.button5 = PRVM_ED_FindFieldOffset("button5");
1362 prog->fieldoffsets.button6 = PRVM_ED_FindFieldOffset("button6");
1363 prog->fieldoffsets.button7 = PRVM_ED_FindFieldOffset("button7");
1364 prog->fieldoffsets.button8 = PRVM_ED_FindFieldOffset("button8");
1365 prog->fieldoffsets.button9 = PRVM_ED_FindFieldOffset("button9");
1366 prog->fieldoffsets.button10 = PRVM_ED_FindFieldOffset("button10");
1367 prog->fieldoffsets.button11 = PRVM_ED_FindFieldOffset("button11");
1368 prog->fieldoffsets.button12 = PRVM_ED_FindFieldOffset("button12");
1369 prog->fieldoffsets.button13 = PRVM_ED_FindFieldOffset("button13");
1370 prog->fieldoffsets.button14 = PRVM_ED_FindFieldOffset("button14");
1371 prog->fieldoffsets.button15 = PRVM_ED_FindFieldOffset("button15");
1372 prog->fieldoffsets.button16 = PRVM_ED_FindFieldOffset("button16");
1373 prog->fieldoffsets.buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
1374 prog->fieldoffsets.buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
1375 prog->fieldoffsets.chain = PRVM_ED_FindFieldOffset("chain");
1376 prog->fieldoffsets.classname = PRVM_ED_FindFieldOffset("classname");
1377 prog->fieldoffsets.clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
1378 prog->fieldoffsets.color = PRVM_ED_FindFieldOffset("color");
1379 prog->fieldoffsets.colormod = PRVM_ED_FindFieldOffset("colormod");
1380 prog->fieldoffsets.contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
1381 prog->fieldoffsets.cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
1382 prog->fieldoffsets.cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
1383 prog->fieldoffsets.cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1384 prog->fieldoffsets.cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1385 prog->fieldoffsets.cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
1386 prog->fieldoffsets.customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
1387 prog->fieldoffsets.dimension_hit = PRVM_ED_FindFieldOffset("dimension_hit");
1388 prog->fieldoffsets.dimension_solid = PRVM_ED_FindFieldOffset("dimension_solid");
1389 prog->fieldoffsets.disableclientprediction = PRVM_ED_FindFieldOffset("disableclientprediction");
1390 prog->fieldoffsets.dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1391 prog->fieldoffsets.drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
1392 prog->fieldoffsets.exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1393 prog->fieldoffsets.fatness = PRVM_ED_FindFieldOffset("fatness");
1394 prog->fieldoffsets.forceshader = PRVM_ED_FindFieldOffset("forceshader");
1395 prog->fieldoffsets.frame = PRVM_ED_FindFieldOffset("frame");
1396 prog->fieldoffsets.frame1time = PRVM_ED_FindFieldOffset("frame1time");
1397 prog->fieldoffsets.frame2 = PRVM_ED_FindFieldOffset("frame2");
1398 prog->fieldoffsets.frame2time = PRVM_ED_FindFieldOffset("frame2time");
1399 prog->fieldoffsets.fullbright = PRVM_ED_FindFieldOffset("fullbright");
1400 prog->fieldoffsets.glow_color = PRVM_ED_FindFieldOffset("glow_color");
1401 prog->fieldoffsets.glow_size = PRVM_ED_FindFieldOffset("glow_size");
1402 prog->fieldoffsets.glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
1403 prog->fieldoffsets.gravity = PRVM_ED_FindFieldOffset("gravity");
1404 prog->fieldoffsets.groundentity = PRVM_ED_FindFieldOffset("groundentity");
1405 prog->fieldoffsets.hull = PRVM_ED_FindFieldOffset("hull");
1406 prog->fieldoffsets.ideal_yaw = PRVM_ED_FindFieldOffset("ideal_yaw");
1407 prog->fieldoffsets.idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
1408 prog->fieldoffsets.items2 = PRVM_ED_FindFieldOffset("items2");
1409 prog->fieldoffsets.lerpfrac = PRVM_ED_FindFieldOffset("lerpfrac");
1410 prog->fieldoffsets.light_lev = PRVM_ED_FindFieldOffset("light_lev");
1411 prog->fieldoffsets.message = PRVM_ED_FindFieldOffset("message");
1412 prog->fieldoffsets.modelflags = PRVM_ED_FindFieldOffset("modelflags");
1413 prog->fieldoffsets.movement = PRVM_ED_FindFieldOffset("movement");
1414 prog->fieldoffsets.movetypesteplandevent = PRVM_ED_FindFieldOffset("movetypesteplandevent");
1415 prog->fieldoffsets.netaddress = PRVM_ED_FindFieldOffset("netaddress");
1416 prog->fieldoffsets.nextthink = PRVM_ED_FindFieldOffset("nextthink");
1417 prog->fieldoffsets.nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
1418 prog->fieldoffsets.pflags = PRVM_ED_FindFieldOffset("pflags");
1419 prog->fieldoffsets.ping = PRVM_ED_FindFieldOffset("ping");
1420 prog->fieldoffsets.pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
1421 prog->fieldoffsets.playermodel = PRVM_ED_FindFieldOffset("playermodel");
1422 prog->fieldoffsets.playerskin = PRVM_ED_FindFieldOffset("playerskin");
1423 prog->fieldoffsets.pmodel = PRVM_ED_FindFieldOffset("pmodel");
1424 prog->fieldoffsets.punchvector = PRVM_ED_FindFieldOffset("punchvector");
1425 prog->fieldoffsets.renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1426 prog->fieldoffsets.renderflags = PRVM_ED_FindFieldOffset("renderflags");
1427 prog->fieldoffsets.rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1428 prog->fieldoffsets.scale = PRVM_ED_FindFieldOffset("scale");
1429 prog->fieldoffsets.style = PRVM_ED_FindFieldOffset("style");
1430 prog->fieldoffsets.tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
1431 prog->fieldoffsets.tag_index = PRVM_ED_FindFieldOffset("tag_index");
1432 prog->fieldoffsets.think = PRVM_ED_FindFieldOffset("think");
1433 prog->fieldoffsets.viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
1434 prog->fieldoffsets.viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
1435 prog->fieldoffsets.yaw_speed = PRVM_ED_FindFieldOffset("yaw_speed");
1436 prog->fieldoffsets.clientcamera = PRVM_ED_FindFieldOffset("clientcamera");
1437 prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1438 prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1439 prog->funcoffsets.CSQC_Ent_Update = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1440 prog->funcoffsets.CSQC_Ent_Spawn = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
1441 prog->funcoffsets.CSQC_Event = PRVM_ED_FindFunctionOffset("CSQC_Event");
1442 prog->funcoffsets.CSQC_Event_Sound = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
1443 prog->funcoffsets.CSQC_Init = PRVM_ED_FindFunctionOffset("CSQC_Init");
1444 prog->funcoffsets.CSQC_InputEvent = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1445 prog->funcoffsets.CSQC_Parse_CenterPrint = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1446 prog->funcoffsets.CSQC_Parse_Print = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1447 prog->funcoffsets.CSQC_Parse_StuffCmd = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1448 prog->funcoffsets.CSQC_Parse_TempEntity = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1449 prog->funcoffsets.CSQC_Shutdown = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1450 prog->funcoffsets.CSQC_UpdateView = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1451 prog->funcoffsets.Gecko_Query = PRVM_ED_FindFunctionOffset("Gecko_Query");
1452 prog->funcoffsets.EndFrame = PRVM_ED_FindFunctionOffset("EndFrame");
1453 prog->funcoffsets.RestoreGame = PRVM_ED_FindFunctionOffset("RestoreGame");
1454 prog->funcoffsets.SV_ChangeTeam = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1455 prog->funcoffsets.SV_ParseClientCommand = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1456 prog->funcoffsets.SV_PlayerPhysics = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1457 prog->funcoffsets.SV_OnEntityNoSpawnFunction = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
1458 prog->funcoffsets.GameCommand = PRVM_ED_FindFunctionOffset("GameCommand");
1459 prog->funcoffsets.SV_Shutdown = PRVM_ED_FindFunctionOffset("SV_Shutdown");
1460 prog->globaloffsets.SV_InitCmd = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1461 prog->globaloffsets.self = PRVM_ED_FindGlobalOffset("self");
1462 prog->globaloffsets.time = PRVM_ED_FindGlobalOffset("time");
1463 prog->globaloffsets.v_forward = PRVM_ED_FindGlobalOffset("v_forward");
1464 prog->globaloffsets.v_right = PRVM_ED_FindGlobalOffset("v_right");
1465 prog->globaloffsets.v_up = PRVM_ED_FindGlobalOffset("v_up");
1466 prog->globaloffsets.view_angles = PRVM_ED_FindGlobalOffset("view_angles");
1467 prog->globaloffsets.trace_allsolid = PRVM_ED_FindGlobalOffset("trace_allsolid");
1468 prog->globaloffsets.trace_startsolid = PRVM_ED_FindGlobalOffset("trace_startsolid");
1469 prog->globaloffsets.trace_fraction = PRVM_ED_FindGlobalOffset("trace_fraction");
1470 prog->globaloffsets.trace_inwater = PRVM_ED_FindGlobalOffset("trace_inwater");
1471 prog->globaloffsets.trace_inopen = PRVM_ED_FindGlobalOffset("trace_inopen");
1472 prog->globaloffsets.trace_endpos = PRVM_ED_FindGlobalOffset("trace_endpos");
1473 prog->globaloffsets.trace_plane_normal = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1474 prog->globaloffsets.trace_plane_dist = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1475 prog->globaloffsets.trace_ent = PRVM_ED_FindGlobalOffset("trace_ent");
1476 prog->globaloffsets.trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1477 prog->globaloffsets.trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1478 prog->globaloffsets.trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1479 prog->globaloffsets.trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1480 prog->globaloffsets.intermission = PRVM_ED_FindGlobalOffset("intermission");
1481 prog->globaloffsets.coop = PRVM_ED_FindGlobalOffset("coop");
1482 prog->globaloffsets.deathmatch = PRVM_ED_FindGlobalOffset("deathmatch");
1483 prog->globaloffsets.dmg_take = PRVM_ED_FindGlobalOffset("dmg_take");
1484 prog->globaloffsets.dmg_save = PRVM_ED_FindGlobalOffset("dmg_save");
1485 prog->globaloffsets.dmg_origin = PRVM_ED_FindGlobalOffset("dmg_origin");
1486 prog->globaloffsets.sb_showscores = PRVM_ED_FindGlobalOffset("sb_showscores");
1487 prog->globaloffsets.drawfont = PRVM_ED_FindGlobalOffset("drawfont");
1488 prog->globaloffsets.require_spawnfunc_prefix = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
1490 // menu qc only uses some functions, nothing else
1491 prog->funcoffsets.m_draw = PRVM_ED_FindFunctionOffset("m_draw");
1492 prog->funcoffsets.m_init = PRVM_ED_FindFunctionOffset("m_init");
1493 prog->funcoffsets.m_keydown = PRVM_ED_FindFunctionOffset("m_keydown");
1494 prog->funcoffsets.m_keyup = PRVM_ED_FindFunctionOffset("m_keyup");
1495 prog->funcoffsets.m_shutdown = PRVM_ED_FindFunctionOffset("m_shutdown");
1496 prog->funcoffsets.m_toggle = PRVM_ED_FindFunctionOffset("m_toggle");
1501 typedef struct dpfield_s
1508 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1510 dpfield_t dpfields[] =
1521 void PRVM_ResetProg()
1523 PRVM_GCALL(reset_cmd)();
1524 Mem_FreePool(&prog->progs_mempool);
1525 memset(prog,0,sizeof(prvm_prog_t));
1526 prog->starttime = Sys_DoubleTime();
1534 void PRVM_LoadLNO( const char *progname ) {
1535 fs_offset_t filesize;
1537 unsigned int *header;
1540 FS_StripExtension( progname, filename, sizeof( filename ) );
1541 strlcat( filename, ".lno", sizeof( filename ) );
1543 lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1549 <Spike> SafeWrite (h, &lnotype, sizeof(int));
1550 <Spike> SafeWrite (h, &version, sizeof(int));
1551 <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
1552 <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
1553 <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
1554 <Spike> SafeWrite (h, &numstatements, sizeof(int));
1555 <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1557 if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1562 header = (unsigned int *) lno;
1563 if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1564 LittleLong( header[ 1 ] ) == 1 &&
1565 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1566 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1567 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1568 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1570 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1571 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1581 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1585 ddef_t *infielddefs;
1586 dfunction_t *dfunctions;
1587 fs_offset_t filesize;
1589 if( prog->loaded ) {
1590 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1593 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1594 if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1595 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1597 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1599 prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1601 // byte swap the header
1602 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1603 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1605 if (prog->progs->version != PROG_VERSION)
1606 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1607 if (prog->progs->crc != prog->headercrc && prog->progs->crc != prog->headercrc2)
1608 PRVM_ERROR ("%s: %s system vars have been modified (CRC of progs.dat systemvars %i != engine %i), progdefs.h is out of date", PRVM_NAME, filename, prog->progs->crc, prog->headercrc);
1610 //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1611 dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1613 if (prog->progs->ofs_strings + prog->progs->numstrings >= (int)filesize)
1614 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1615 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1616 prog->stringssize = prog->progs->numstrings;
1618 prog->numknownstrings = 0;
1619 prog->maxknownstrings = 0;
1620 prog->knownstrings = NULL;
1621 prog->knownstrings_freeable = NULL;
1623 Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
1625 prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1627 // we need to expand the fielddefs list to include all the engine fields,
1628 // so allocate a new place for it
1629 infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1631 prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1633 prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1635 prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1637 // moved edict_size calculation down below field adding code
1639 //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1640 prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1642 // byte swap the lumps
1643 for (i=0 ; i<prog->progs->numstatements ; i++)
1645 prog->statements[i].op = LittleShort(prog->statements[i].op);
1646 prog->statements[i].a = LittleShort(prog->statements[i].a);
1647 prog->statements[i].b = LittleShort(prog->statements[i].b);
1648 prog->statements[i].c = LittleShort(prog->statements[i].c);
1651 prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1652 for (i = 0;i < prog->progs->numfunctions;i++)
1654 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1655 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1656 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1657 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1658 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1659 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1660 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1663 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1665 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1666 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1667 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1670 // copy the progs fields to the new fields list
1671 for (i = 0;i < prog->progs->numfielddefs;i++)
1673 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1674 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1675 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1676 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1677 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1680 // append the required fields
1681 for (i = 0;i < (int) numrequiredfields;i++)
1683 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1684 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1685 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1686 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1687 prog->progs->entityfields += 3;
1689 prog->progs->entityfields++;
1690 prog->progs->numfielddefs++;
1693 // check required functions
1694 for(i=0 ; i < numrequiredfunc ; i++)
1695 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1696 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1698 // check required globals
1699 for(i=0 ; i < numrequiredglobals ; i++)
1700 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1701 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1703 for (i=0 ; i<prog->progs->numglobals ; i++)
1704 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1706 // moved edict_size calculation down here, below field adding code
1707 // LordHavoc: this no longer includes the prvm_edict_t header
1708 prog->edict_size = prog->progs->entityfields * 4;
1709 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1711 // LordHavoc: bounds check anything static
1712 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1718 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1719 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1722 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1723 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1725 // global global global
1760 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1761 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1763 // global none global
1769 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1770 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1786 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1787 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1801 if ((unsigned short) st->a >= prog->progs->numglobals)
1802 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1805 Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1810 PRVM_LoadLNO(filename);
1814 prog->loaded = TRUE;
1816 // set flags & ddef_ts in prog
1822 PRVM_GCALL(init_cmd)();
1829 void PRVM_Fields_f (void)
1831 int i, j, ednum, used, usedamount;
1833 char tempstring[MAX_INPUTLINE], tempstring2[260];
1843 Con_Print("no progs loaded\n");
1850 Con_Print("prvm_fields <program name>\n");
1855 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1858 counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1859 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1861 ed = PRVM_EDICT_NUM(ednum);
1862 if (ed->priv.required->free)
1864 for (i = 1;i < prog->progs->numfielddefs;i++)
1866 d = &prog->fielddefs[i];
1867 name = PRVM_GetString(d->s_name);
1868 if (name[strlen(name)-2] == '_')
1869 continue; // skip _x, _y, _z vars
1870 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1871 // if the value is still all 0, skip the field
1872 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1885 for (i = 0;i < prog->progs->numfielddefs;i++)
1887 d = &prog->fielddefs[i];
1888 name = PRVM_GetString(d->s_name);
1889 if (name[strlen(name)-2] == '_')
1890 continue; // skip _x, _y, _z vars
1891 switch(d->type & ~DEF_SAVEGLOBAL)
1894 strlcat(tempstring, "string ", sizeof(tempstring));
1897 strlcat(tempstring, "entity ", sizeof(tempstring));
1900 strlcat(tempstring, "function ", sizeof(tempstring));
1903 strlcat(tempstring, "field ", sizeof(tempstring));
1906 strlcat(tempstring, "void ", sizeof(tempstring));
1909 strlcat(tempstring, "float ", sizeof(tempstring));
1912 strlcat(tempstring, "vector ", sizeof(tempstring));
1915 strlcat(tempstring, "pointer ", sizeof(tempstring));
1918 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1919 strlcat(tempstring, tempstring2, sizeof(tempstring));
1922 if (strlen(name) > sizeof(tempstring2)-4)
1924 memcpy (tempstring2, name, sizeof(tempstring2)-4);
1925 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1926 tempstring2[sizeof(tempstring2)-1] = 0;
1929 strlcat(tempstring, name, sizeof(tempstring));
1930 for (j = (int)strlen(name);j < 25;j++)
1931 strlcat(tempstring, " ", sizeof(tempstring));
1932 sprintf(tempstring2, "%5d", counts[i]);
1933 strlcat(tempstring, tempstring2, sizeof(tempstring));
1934 strlcat(tempstring, "\n", sizeof(tempstring));
1935 if (strlen(tempstring) >= sizeof(tempstring)/2)
1937 Con_Print(tempstring);
1943 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1947 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);
1952 void PRVM_Globals_f (void)
1955 const char *wildcard;
1961 Con_Print("no progs loaded\n");
1964 if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
1966 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
1971 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1974 if( Cmd_Argc() == 3)
1975 wildcard = Cmd_Argv(2);
1979 Con_Printf("%s :", PRVM_NAME);
1981 for (i = 0;i < prog->progs->numglobaldefs;i++)
1984 if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
1989 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1991 Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->progs->numglobals, numculled, prog->progs->numglobals * 4);
2001 void PRVM_Global_f(void)
2004 if( Cmd_Argc() != 3 ) {
2005 Con_Printf( "prvm_global <program name> <global name>\n" );
2010 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2013 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2015 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2017 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
2026 void PRVM_GlobalSet_f(void)
2029 if( Cmd_Argc() != 4 ) {
2030 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2035 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2038 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2040 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2042 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3), true );
2051 void PRVM_Init (void)
2053 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2054 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2055 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2056 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2057 Cmd_AddCommand ("prvm_callprofile", PRVM_CallProfile_f, "prints execution statistics about the most time consuming QuakeC calls from the engine in the selected VM (server, client, menu)");
2058 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)");
2059 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2060 Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2061 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2062 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)");
2063 Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2064 Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2065 Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2066 Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2067 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
2068 #ifdef PRVM_BOUNDSCHECK_CVAR
2069 Cvar_RegisterVariable (&prvm_boundscheck);
2071 Cvar_RegisterVariable (&prvm_traceqc);
2072 Cvar_RegisterVariable (&prvm_statementprofiling);
2073 Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2083 void PRVM_InitProg(int prognr)
2085 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
2086 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
2088 prog = &prog_list[prognr];
2093 memset(prog, 0, sizeof(prvm_prog_t));
2094 prog->starttime = Sys_DoubleTime();
2096 prog->error_cmd = Host_Error;
2099 int PRVM_GetProgNr()
2101 return prog - prog_list;
2104 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
2106 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
2109 void _PRVM_Free(void *buffer, const char *filename, int fileline)
2111 _Mem_Free(buffer, filename, fileline);
2114 void _PRVM_FreeAll(const char *filename, int fileline)
2117 prog->fielddefs = NULL;
2118 prog->functions = NULL;
2119 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
2122 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2123 unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, char *filename, int fileline)
2125 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
2130 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
2132 PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
2136 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
2139 n = e - prog->edicts;
2140 if ((unsigned int)n >= prog->limit_edicts)
2141 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
2145 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
2147 // return e - prog->edicts;
2150 //#define PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
2151 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
2152 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
2155 n = e - prog->edicts;
2156 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2157 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2158 return n;// EXPERIMENTAL
2159 //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2161 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2163 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2164 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2165 return prog->edicts + n; // EXPERIMENTAL
2166 //return prog->edicts + ((n) / (progs->entityfields * 4));
2171 sizebuf_t vm_tempstringsbuf;
2173 const char *PRVM_GetString(int num)
2177 if (num < prog->stringssize)
2178 return prog->strings + num;
2181 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2183 num -= prog->stringssize;
2184 if (num < vm_tempstringsbuf.cursize)
2185 return (char *)vm_tempstringsbuf.data + num;
2188 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2195 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
2205 // special range reserved for tempstrings
2207 if (num < vm_tempstringsbuf.cursize)
2208 return (char *)vm_tempstringsbuf.data + num;
2211 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2217 if (num < prog->numknownstrings)
2219 if (!prog->knownstrings[num])
2220 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
2221 return prog->knownstrings[num];
2225 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
2231 int PRVM_SetEngineString(const char *s)
2236 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2237 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2238 // if it's in the tempstrings area, use a reserved range
2239 // (otherwise we'd get millions of useless string offsets cluttering the database)
2240 if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2242 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2244 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2246 // see if it's a known string address
2247 for (i = 0;i < prog->numknownstrings;i++)
2248 if (prog->knownstrings[i] == s)
2250 // new unknown engine string
2251 if (developer.integer >= 200)
2252 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2253 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2254 if (!prog->knownstrings[i])
2256 if (i >= prog->numknownstrings)
2258 if (i >= prog->maxknownstrings)
2260 const char **oldstrings = prog->knownstrings;
2261 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2262 prog->maxknownstrings += 128;
2263 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2264 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2265 if (prog->numknownstrings)
2267 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2268 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2271 prog->numknownstrings++;
2273 prog->firstfreeknownstring = i + 1;
2274 prog->knownstrings[i] = s;
2278 // temp string handling
2280 // all tempstrings go into this buffer consecutively, and it is reset
2281 // whenever PRVM_ExecuteProgram returns to the engine
2282 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2283 // restores it on return, so multiple recursive calls can share the same
2285 // the buffer size is automatically grown as needed
2287 int PRVM_SetTempString(const char *s)
2293 size = (int)strlen(s) + 1;
2294 if (developer.integer >= 300)
2295 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2296 if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2298 sizebuf_t old = vm_tempstringsbuf;
2299 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2300 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);
2301 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2302 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2303 vm_tempstringsbuf.maxsize *= 2;
2304 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2306 if (developer.integer >= 100)
2307 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2308 vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2310 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2315 t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2317 vm_tempstringsbuf.cursize += size;
2318 return PRVM_SetEngineString(t);
2321 int PRVM_AllocString(size_t bufferlength, char **pointer)
2326 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2327 if (!prog->knownstrings[i])
2329 if (i >= prog->numknownstrings)
2331 if (i >= prog->maxknownstrings)
2333 const char **oldstrings = prog->knownstrings;
2334 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2335 prog->maxknownstrings += 128;
2336 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2337 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2338 if (prog->numknownstrings)
2340 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2341 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2344 prog->numknownstrings++;
2346 prog->firstfreeknownstring = i + 1;
2347 prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2348 prog->knownstrings_freeable[i] = true;
2350 *pointer = (char *)(prog->knownstrings[i]);
2354 void PRVM_FreeString(int num)
2357 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2358 else if (num >= 0 && num < prog->stringssize)
2359 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2360 else if (num < 0 && num >= -prog->numknownstrings)
2363 if (!prog->knownstrings[num])
2364 PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2365 if (!prog->knownstrings[num])
2366 PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2367 PRVM_Free((char *)prog->knownstrings[num]);
2368 prog->knownstrings[num] = NULL;
2369 prog->knownstrings_freeable[num] = false;
2370 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2373 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);