]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_edict.c
reworked animation interpolation code - entity_render_t now has
[divverent/darkplaces.git] / prvm_edict.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // AK new vm
21
22 #include "quakedef.h"
23 #include "progsvm.h"
24
25 prvm_prog_t *prog;
26
27 static prvm_prog_t prog_list[PRVM_MAXPROGS];
28
29 int             prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
30
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);
33
34 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
35 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
36 // LordHavoc: counts usage of each QuakeC statement
37 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)"};
38 cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"};
39 cvar_t prvm_leaktest = {0, "prvm_leaktest", "0", "try to detect memory leaks in strings or entities"};
40 cvar_t prvm_leaktest_ignore_classnames = {0, "prvm_leaktest_ignore_classnames", "", "classnames of entities to NOT leak check because they are found by find(world, classname, ...) but are actually spawned by QC code (NOT map entities)"};
41 cvar_t prvm_errordump = {0, "prvm_errordump", "0", "write a savegame on crash to crash-server.dmp"};
42
43 qboolean prvm_runawaycheck = true;
44
45 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
46 // 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)
47 qboolean prvm_boundscheck = true;
48
49 extern sizebuf_t vm_tempstringsbuf;
50
51 //============================================================================
52 // mempool handling
53
54 /*
55 ===============
56 PRVM_MEM_Alloc
57 ===============
58 */
59 void PRVM_MEM_Alloc(void)
60 {
61         int i;
62
63         // reserve space for the null entity aka world
64         // check bound of max_edicts
65         prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
66         prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
67
68         // edictprivate_size has to be min as big prvm_edict_private_t
69         prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
70
71         // alloc edicts
72         prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
73
74         // alloc edict private space
75         prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
76
77         // alloc edict fields
78         prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
79
80         // set edict pointers
81         for(i = 0; i < prog->max_edicts; i++)
82         {
83                 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
84                 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
85         }
86 }
87
88 /*
89 ===============
90 PRVM_MEM_IncreaseEdicts
91 ===============
92 */
93 void PRVM_MEM_IncreaseEdicts(void)
94 {
95         int             i;
96         int             oldmaxedicts = prog->max_edicts;
97         void    *oldedictsfields = prog->edictsfields;
98         void    *oldedictprivate = prog->edictprivate;
99
100         if(prog->max_edicts >= prog->limit_edicts)
101                 return;
102
103         PRVM_GCALL(begin_increase_edicts)();
104
105         // increase edicts
106         prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
107
108         prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
109         prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
110
111         memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
112         memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
113
114         //set e and v pointers
115         for(i = 0; i < prog->max_edicts; i++)
116         {
117                 prog->edicts[i].priv.required  = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
118                 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
119         }
120
121         PRVM_GCALL(end_increase_edicts)();
122
123         Mem_Free(oldedictsfields);
124         Mem_Free(oldedictprivate);
125 }
126
127 //============================================================================
128 // normal prvm
129
130 int PRVM_ED_FindFieldOffset(const char *field)
131 {
132         ddef_t *d;
133         d = PRVM_ED_FindField(field);
134         if (!d)
135                 return -1;
136         return d->ofs;
137 }
138
139 int PRVM_ED_FindGlobalOffset(const char *global)
140 {
141         ddef_t *d;
142         d = PRVM_ED_FindGlobal(global);
143         if (!d)
144                 return -1;
145         return d->ofs;
146 }
147
148 func_t PRVM_ED_FindFunctionOffset(const char *function)
149 {
150         mfunction_t *f;
151         f = PRVM_ED_FindFunction(function);
152         if (!f)
153                 return 0;
154         return (func_t)(f - prog->functions);
155 }
156
157 qboolean PRVM_ProgLoaded(int prognr)
158 {
159         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
160                 return FALSE;
161
162         return (prog_list[prognr].loaded ? TRUE : FALSE);
163 }
164
165 /*
166 =================
167 PRVM_SetProgFromString
168 =================
169 */
170 // perhaps add a return value when the str doesnt exist
171 qboolean PRVM_SetProgFromString(const char *str)
172 {
173         int i = 0;
174         for(; i < PRVM_MAXPROGS ; i++)
175                 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
176                 {
177                         if(prog_list[i].loaded)
178                         {
179                                 prog = &prog_list[i];
180                                 return TRUE;
181                         }
182                         else
183                         {
184                                 Con_Printf("%s not loaded !\n",PRVM_NAME);
185                                 return FALSE;
186                         }
187                 }
188
189         Con_Printf("Invalid program name %s !\n", str);
190         return FALSE;
191 }
192
193 /*
194 =================
195 PRVM_SetProg
196 =================
197 */
198 void PRVM_SetProg(int prognr)
199 {
200         if(0 <= prognr && prognr < PRVM_MAXPROGS)
201         {
202                 if(prog_list[prognr].loaded)
203                         prog = &prog_list[prognr];
204                 else
205                         PRVM_ERROR("%i not loaded !", prognr);
206                 return;
207         }
208         PRVM_ERROR("Invalid program number %i", prognr);
209 }
210
211 /*
212 =================
213 PRVM_ED_ClearEdict
214
215 Sets everything to NULL
216 =================
217 */
218 void PRVM_ED_ClearEdict (prvm_edict_t *e)
219 {
220         memset (e->fields.vp, 0, prog->progs->entityfields * 4);
221         e->priv.required->free = false;
222
223         // AK: Let the init_edict function determine if something needs to be initialized
224         PRVM_GCALL(init_edict)(e);
225 }
226
227 const char *PRVM_AllocationOrigin()
228 {
229         char *buf = NULL;
230         if(prog->leaktest_active)
231         if(prog->depth > 0) // actually in QC code and not just parsing the entities block of a map/savegame
232         {
233                 buf = (char *)PRVM_Alloc(128);
234                 PRVM_ShortStackTrace(buf, 128);
235         }
236         return buf;
237 }
238
239 /*
240 =================
241 PRVM_ED_Alloc
242
243 Either finds a free edict, or allocates a new one.
244 Try to avoid reusing an entity that was recently freed, because it
245 can cause the client to think the entity morphed into something else
246 instead of being removed and recreated, which can cause interpolated
247 angles and bad trails.
248 =================
249 */
250 prvm_edict_t *PRVM_ED_Alloc (void)
251 {
252         int                     i;
253         prvm_edict_t            *e;
254
255         // the client qc dont need maxclients
256         // thus it doesnt need to use svs.maxclients
257         // AK:  changed i=svs.maxclients+1
258         // AK:  changed so the edict 0 wont spawn -> used as reserved/world entity
259         //              although the menu/client has no world
260         for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
261         {
262                 e = PRVM_EDICT_NUM(i);
263                 // the first couple seconds of server time can involve a lot of
264                 // freeing and allocating, so relax the replacement policy
265                 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 ) )
266                 {
267                         PRVM_ED_ClearEdict (e);
268                         e->priv.required->allocation_origin = PRVM_AllocationOrigin();
269                         return e;
270                 }
271         }
272
273         if (i == prog->limit_edicts)
274                 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
275
276         prog->num_edicts++;
277         if (prog->num_edicts >= prog->max_edicts)
278                 PRVM_MEM_IncreaseEdicts();
279
280         e = PRVM_EDICT_NUM(i);
281         PRVM_ED_ClearEdict (e);
282
283         e->priv.required->allocation_origin = PRVM_AllocationOrigin();
284
285         return e;
286 }
287
288 /*
289 =================
290 PRVM_ED_Free
291
292 Marks the edict as free
293 FIXME: walk all entities and NULL out references to this entity
294 =================
295 */
296 void PRVM_ED_Free (prvm_edict_t *ed)
297 {
298         // dont delete the null entity (world) or reserved edicts
299         if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
300                 return;
301
302         PRVM_GCALL(free_edict)(ed);
303
304         ed->priv.required->free = true;
305         ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0;
306         if(ed->priv.required->allocation_origin)
307         {
308                 PRVM_Free((char *)ed->priv.required->allocation_origin);
309                 ed->priv.required->allocation_origin = NULL;
310         }
311 }
312
313 //===========================================================================
314
315 /*
316 ============
317 PRVM_ED_GlobalAtOfs
318 ============
319 */
320 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
321 {
322         ddef_t          *def;
323         int                     i;
324
325         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
326         {
327                 def = &prog->globaldefs[i];
328                 if (def->ofs == ofs)
329                         return def;
330         }
331         return NULL;
332 }
333
334 /*
335 ============
336 PRVM_ED_FieldAtOfs
337 ============
338 */
339 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
340 {
341         ddef_t          *def;
342         int                     i;
343
344         for (i=0 ; i<prog->progs->numfielddefs ; i++)
345         {
346                 def = &prog->fielddefs[i];
347                 if (def->ofs == ofs)
348                         return def;
349         }
350         return NULL;
351 }
352
353 /*
354 ============
355 PRVM_ED_FindField
356 ============
357 */
358 ddef_t *PRVM_ED_FindField (const char *name)
359 {
360         ddef_t *def;
361         int i;
362
363         for (i=0 ; i<prog->progs->numfielddefs ; i++)
364         {
365                 def = &prog->fielddefs[i];
366                 if (!strcmp(PRVM_GetString(def->s_name), name))
367                         return def;
368         }
369         return NULL;
370 }
371
372 /*
373 ============
374 PRVM_ED_FindGlobal
375 ============
376 */
377 ddef_t *PRVM_ED_FindGlobal (const char *name)
378 {
379         ddef_t *def;
380         int i;
381
382         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
383         {
384                 def = &prog->globaldefs[i];
385                 if (!strcmp(PRVM_GetString(def->s_name), name))
386                         return def;
387         }
388         return NULL;
389 }
390
391
392 /*
393 ============
394 PRVM_ED_FindFunction
395 ============
396 */
397 mfunction_t *PRVM_ED_FindFunction (const char *name)
398 {
399         mfunction_t             *func;
400         int                             i;
401
402         for (i=0 ; i<prog->progs->numfunctions ; i++)
403         {
404                 func = &prog->functions[i];
405                 if (!strcmp(PRVM_GetString(func->s_name), name))
406                         return func;
407         }
408         return NULL;
409 }
410
411
412 /*
413 ============
414 PRVM_ValueString
415
416 Returns a string describing *data in a type specific manner
417 =============
418 */
419 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
420 {
421         static char line[MAX_INPUTLINE];
422         ddef_t *def;
423         mfunction_t *f;
424         int n;
425
426         type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
427
428         switch (type)
429         {
430         case ev_string:
431                 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
432                 break;
433         case ev_entity:
434                 n = val->edict;
435                 if (n < 0 || n >= prog->limit_edicts)
436                         dpsnprintf (line, sizeof(line), "entity %i (invalid!)", n);
437                 else
438                         dpsnprintf (line, sizeof(line), "entity %i", n);
439                 break;
440         case ev_function:
441                 f = prog->functions + val->function;
442                 dpsnprintf (line, sizeof(line), "%s()", PRVM_GetString(f->s_name));
443                 break;
444         case ev_field:
445                 def = PRVM_ED_FieldAtOfs ( val->_int );
446                 dpsnprintf (line, sizeof(line), ".%s", PRVM_GetString(def->s_name));
447                 break;
448         case ev_void:
449                 dpsnprintf (line, sizeof(line), "void");
450                 break;
451         case ev_float:
452                 // LordHavoc: changed from %5.1f to %10.4f
453                 dpsnprintf (line, sizeof(line), "%10.4f", val->_float);
454                 break;
455         case ev_vector:
456                 // LordHavoc: changed from %5.1f to %10.4f
457                 dpsnprintf (line, sizeof(line), "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
458                 break;
459         case ev_pointer:
460                 dpsnprintf (line, sizeof(line), "pointer");
461                 break;
462         default:
463                 dpsnprintf (line, sizeof(line), "bad type %i", (int) type);
464                 break;
465         }
466
467         return line;
468 }
469
470 /*
471 ============
472 PRVM_UglyValueString
473
474 Returns a string describing *data in a type specific manner
475 Easier to parse than PR_ValueString
476 =============
477 */
478 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
479 {
480         static char line[MAX_INPUTLINE];
481         int i;
482         const char *s;
483         ddef_t *def;
484         mfunction_t *f;
485
486         type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
487
488         switch (type)
489         {
490         case ev_string:
491                 // Parse the string a bit to turn special characters
492                 // (like newline, specifically) into escape codes,
493                 // this fixes saving games from various mods
494                 s = PRVM_GetString (val->string);
495                 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
496                 {
497                         if (*s == '\n')
498                         {
499                                 line[i++] = '\\';
500                                 line[i++] = 'n';
501                         }
502                         else if (*s == '\r')
503                         {
504                                 line[i++] = '\\';
505                                 line[i++] = 'r';
506                         }
507                         else if (*s == '\\')
508                         {
509                                 line[i++] = '\\';
510                                 line[i++] = '\\';
511                         }
512                         else if (*s == '"')
513                         {
514                                 line[i++] = '\\';
515                                 line[i++] = '"';
516                         }
517                         else
518                                 line[i++] = *s;
519                         s++;
520                 }
521                 line[i] = '\0';
522                 break;
523         case ev_entity:
524                 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
525                 break;
526         case ev_function:
527                 f = prog->functions + val->function;
528                 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
529                 break;
530         case ev_field:
531                 def = PRVM_ED_FieldAtOfs ( val->_int );
532                 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
533                 break;
534         case ev_void:
535                 dpsnprintf (line, sizeof (line), "void");
536                 break;
537         case ev_float:
538                 dpsnprintf (line, sizeof (line), "%f", val->_float);
539                 break;
540         case ev_vector:
541                 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
542                 break;
543         default:
544                 dpsnprintf (line, sizeof (line), "bad type %i", type);
545                 break;
546         }
547
548         return line;
549 }
550
551 /*
552 ============
553 PRVM_GlobalString
554
555 Returns a string with a description and the contents of a global,
556 padded to 20 field width
557 ============
558 */
559 char *PRVM_GlobalString (int ofs)
560 {
561         char    *s;
562         //size_t        i;
563         ddef_t  *def;
564         void    *val;
565         static char     line[128];
566
567         val = (void *)&prog->globals.generic[ofs];
568         def = PRVM_ED_GlobalAtOfs(ofs);
569         if (!def)
570                 dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
571         else
572         {
573                 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
574                 dpsnprintf (line, sizeof(line), "%s (=%s)", PRVM_GetString(def->s_name), s);
575         }
576
577         //i = strlen(line);
578         //for ( ; i<20 ; i++)
579         //      strcat (line," ");
580         //strcat (line," ");
581
582         return line;
583 }
584
585 char *PRVM_GlobalStringNoContents (int ofs)
586 {
587         //size_t        i;
588         ddef_t  *def;
589         static char     line[128];
590
591         def = PRVM_ED_GlobalAtOfs(ofs);
592         if (!def)
593                 dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
594         else
595                 dpsnprintf (line, sizeof(line), "%s", PRVM_GetString(def->s_name));
596
597         //i = strlen(line);
598         //for ( ; i<20 ; i++)
599         //      strcat (line," ");
600         //strcat (line," ");
601
602         return line;
603 }
604
605
606 /*
607 =============
608 PRVM_ED_Print
609
610 For debugging
611 =============
612 */
613 // LordHavoc: optimized this to print out much more quickly (tempstring)
614 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
615 void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
616 {
617         size_t  l;
618         ddef_t  *d;
619         int             *v;
620         int             i, j;
621         const char      *name;
622         int             type;
623         char    tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
624
625         if (ed->priv.required->free)
626         {
627                 Con_Printf("%s: FREE\n",PRVM_NAME);
628                 return;
629         }
630
631         tempstring[0] = 0;
632         dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
633         for (i=1 ; i<prog->progs->numfielddefs ; i++)
634         {
635                 d = &prog->fielddefs[i];
636                 name = PRVM_GetString(d->s_name);
637                 if (name[strlen(name)-2] == '_')
638                         continue;       // skip _x, _y, _z vars
639
640                 // Check Field Name Wildcard
641                 if(wildcard_fieldname)
642                         if( !matchpattern(name, wildcard_fieldname, 1) )
643                                 // Didn't match; skip
644                                 continue;
645
646                 v = (int *)((char *)ed->fields.vp + d->ofs*4);
647
648         // if the value is still all 0, skip the field
649                 type = d->type & ~DEF_SAVEGLOBAL;
650
651                 for (j=0 ; j<prvm_type_size[type] ; j++)
652                         if (v[j])
653                                 break;
654                 if (j == prvm_type_size[type])
655                         continue;
656
657                 if (strlen(name) > sizeof(tempstring2)-4)
658                 {
659                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
660                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
661                         tempstring2[sizeof(tempstring2)-1] = 0;
662                         name = tempstring2;
663                 }
664                 strlcat(tempstring, name, sizeof(tempstring));
665                 for (l = strlen(name);l < 14;l++)
666                         strlcat(tempstring, " ", sizeof(tempstring));
667                 strlcat(tempstring, " ", sizeof(tempstring));
668
669                 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
670                 if (strlen(name) > sizeof(tempstring2)-4)
671                 {
672                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
673                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
674                         tempstring2[sizeof(tempstring2)-1] = 0;
675                         name = tempstring2;
676                 }
677                 strlcat(tempstring, name, sizeof(tempstring));
678                 strlcat(tempstring, "\n", sizeof(tempstring));
679                 if (strlen(tempstring) >= sizeof(tempstring)/2)
680                 {
681                         Con_Print(tempstring);
682                         tempstring[0] = 0;
683                 }
684         }
685         if (tempstring[0])
686                 Con_Print(tempstring);
687 }
688
689 /*
690 =============
691 PRVM_ED_Write
692
693 For savegames
694 =============
695 */
696 extern cvar_t developer_entityparsing;
697 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
698 {
699         ddef_t  *d;
700         int             *v;
701         int             i, j;
702         const char      *name;
703         int             type;
704
705         FS_Print(f, "{\n");
706
707         if (ed->priv.required->free)
708         {
709                 FS_Print(f, "}\n");
710                 return;
711         }
712
713         for (i=1 ; i<prog->progs->numfielddefs ; i++)
714         {
715                 d = &prog->fielddefs[i];
716                 name = PRVM_GetString(d->s_name);
717
718                 if(developer_entityparsing.integer)
719                         Con_Printf("PRVM_ED_Write: at entity %d field %s\n", PRVM_NUM_FOR_EDICT(ed), name);
720
721                 if (name[strlen(name)-2] == '_')
722                         continue;       // skip _x, _y, _z vars
723
724                 v = (int *)((char *)ed->fields.vp + d->ofs*4);
725
726         // if the value is still all 0, skip the field
727                 type = d->type & ~DEF_SAVEGLOBAL;
728                 for (j=0 ; j<prvm_type_size[type] ; j++)
729                         if (v[j])
730                                 break;
731                 if (j == prvm_type_size[type])
732                         continue;
733
734                 FS_Printf(f,"\"%s\" ",name);
735                 prog->statestring = va("PRVM_ED_Write, ent=%d, name=%s", i, name);
736                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
737                 prog->statestring = NULL;
738         }
739
740         FS_Print(f, "}\n");
741 }
742
743 void PRVM_ED_PrintNum (int ent, const char *wildcard_fieldname)
744 {
745         PRVM_ED_Print(PRVM_EDICT_NUM(ent), wildcard_fieldname);
746 }
747
748 /*
749 =============
750 PRVM_ED_PrintEdicts_f
751
752 For debugging, prints all the entities in the current server
753 =============
754 */
755 void PRVM_ED_PrintEdicts_f (void)
756 {
757         int             i;
758         const char *wildcard_fieldname;
759
760         if(Cmd_Argc() < 2 || Cmd_Argc() > 3)
761         {
762                 Con_Print("prvm_edicts <program name> <optional field name wildcard>\n");
763                 return;
764         }
765
766         PRVM_Begin;
767         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
768                 return;
769
770         if( Cmd_Argc() == 3)
771                 wildcard_fieldname = Cmd_Argv(2);
772         else
773                 wildcard_fieldname = NULL;
774
775         Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
776         for (i=0 ; i<prog->num_edicts ; i++)
777                 PRVM_ED_PrintNum (i, wildcard_fieldname);
778
779         PRVM_End;
780 }
781
782 /*
783 =============
784 PRVM_ED_PrintEdict_f
785
786 For debugging, prints a single edict
787 =============
788 */
789 void PRVM_ED_PrintEdict_f (void)
790 {
791         int             i;
792         const char      *wildcard_fieldname;
793
794         if(Cmd_Argc() < 3 || Cmd_Argc() > 4)
795         {
796                 Con_Print("prvm_edict <program name> <edict number> <optional field name wildcard>\n");
797                 return;
798         }
799
800         PRVM_Begin;
801         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
802                 return;
803
804         i = atoi (Cmd_Argv(2));
805         if (i >= prog->num_edicts)
806         {
807                 Con_Print("Bad edict number\n");
808                 PRVM_End;
809                 return;
810         }
811         if( Cmd_Argc() == 4)
812                 // Optional Wildcard Provided
813                 wildcard_fieldname = Cmd_Argv(3);
814         else
815                 // Use All
816                 wildcard_fieldname = NULL;
817         PRVM_ED_PrintNum (i, wildcard_fieldname);
818
819         PRVM_End;
820 }
821
822 /*
823 =============
824 PRVM_ED_Count
825
826 For debugging
827 =============
828 */
829 // 2 possibilities : 1. just displaying the active edict count
830 //                                       2. making a function pointer [x]
831 void PRVM_ED_Count_f (void)
832 {
833         int             i;
834         prvm_edict_t    *ent;
835         int             active;
836
837         if(Cmd_Argc() != 2)
838         {
839                 Con_Print("prvm_count <program name>\n");
840                 return;
841         }
842
843         PRVM_Begin;
844         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
845                 return;
846
847         if(prog->count_edicts)
848                 prog->count_edicts();
849         else
850         {
851                 active = 0;
852                 for (i=0 ; i<prog->num_edicts ; i++)
853                 {
854                         ent = PRVM_EDICT_NUM(i);
855                         if (ent->priv.required->free)
856                                 continue;
857                         active++;
858                 }
859
860                 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
861                 Con_Printf("active    :%3i\n", active);
862         }
863
864         PRVM_End;
865 }
866
867 /*
868 ==============================================================================
869
870                                         ARCHIVING GLOBALS
871
872 FIXME: need to tag constants, doesn't really work
873 ==============================================================================
874 */
875
876 /*
877 =============
878 PRVM_ED_WriteGlobals
879 =============
880 */
881 void PRVM_ED_WriteGlobals (qfile_t *f)
882 {
883         ddef_t          *def;
884         int                     i;
885         const char              *name;
886         int                     type;
887
888         FS_Print(f,"{\n");
889         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
890         {
891                 def = &prog->globaldefs[i];
892                 type = def->type;
893                 if ( !(def->type & DEF_SAVEGLOBAL) )
894                         continue;
895                 type &= ~DEF_SAVEGLOBAL;
896
897                 if (type != ev_string && type != ev_float && type != ev_entity)
898                         continue;
899
900                 name = PRVM_GetString(def->s_name);
901
902                 if(developer_entityparsing.integer)
903                         Con_Printf("PRVM_ED_WriteGlobals: at global %s\n", name);
904
905                 prog->statestring = va("PRVM_ED_WriteGlobals, name=%s", name);
906                 FS_Printf(f,"\"%s\" ", name);
907                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
908                 prog->statestring = NULL;
909         }
910         FS_Print(f,"}\n");
911 }
912
913 /*
914 =============
915 PRVM_ED_ParseGlobals
916 =============
917 */
918 void PRVM_ED_ParseGlobals (const char *data)
919 {
920         char keyname[MAX_INPUTLINE];
921         ddef_t *key;
922
923         while (1)
924         {
925                 // parse key
926                 if (!COM_ParseToken_Simple(&data, false, false))
927                         PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
928                 if (com_token[0] == '}')
929                         break;
930
931                 if (developer_entityparsing.integer)
932                         Con_Printf("Key: \"%s\"", com_token);
933
934                 strlcpy (keyname, com_token, sizeof(keyname));
935
936                 // parse value
937                 if (!COM_ParseToken_Simple(&data, false, true))
938                         PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
939
940                 if (developer_entityparsing.integer)
941                         Con_Printf(" \"%s\"\n", com_token);
942
943                 if (com_token[0] == '}')
944                         PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
945
946                 key = PRVM_ED_FindGlobal (keyname);
947                 if (!key)
948                 {
949                         Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
950                         continue;
951                 }
952
953                 if (!PRVM_ED_ParseEpair(NULL, key, com_token, true))
954                         PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
955         }
956 }
957
958 //============================================================================
959
960
961 /*
962 =============
963 PRVM_ED_ParseEval
964
965 Can parse either fields or globals
966 returns false if error
967 =============
968 */
969 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
970 {
971         int i, l;
972         char *new_p;
973         ddef_t *def;
974         prvm_eval_t *val;
975         mfunction_t *func;
976
977         if (ent)
978                 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
979         else
980                 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
981         switch (key->type & ~DEF_SAVEGLOBAL)
982         {
983         case ev_string:
984                 l = (int)strlen(s) + 1;
985                 val->string = PRVM_AllocString(l, &new_p);
986                 for (i = 0;i < l;i++)
987                 {
988                         if (s[i] == '\\' && s[i+1] && parsebackslash)
989                         {
990                                 i++;
991                                 if (s[i] == 'n')
992                                         *new_p++ = '\n';
993                                 else if (s[i] == 'r')
994                                         *new_p++ = '\r';
995                                 else
996                                         *new_p++ = s[i];
997                         }
998                         else
999                                 *new_p++ = s[i];
1000                 }
1001                 break;
1002
1003         case ev_float:
1004                 while (*s && ISWHITESPACE(*s))
1005                         s++;
1006                 val->_float = atof(s);
1007                 break;
1008
1009         case ev_vector:
1010                 for (i = 0;i < 3;i++)
1011                 {
1012                         while (*s && ISWHITESPACE(*s))
1013                                 s++;
1014                         if (!*s)
1015                                 break;
1016                         val->vector[i] = atof(s);
1017                         while (!ISWHITESPACE(*s))
1018                                 s++;
1019                         if (!*s)
1020                                 break;
1021                 }
1022                 break;
1023
1024         case ev_entity:
1025                 while (*s && ISWHITESPACE(*s))
1026                         s++;
1027                 i = atoi(s);
1028                 if (i >= prog->limit_edicts)
1029                         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);
1030                 while (i >= prog->max_edicts)
1031                         PRVM_MEM_IncreaseEdicts();
1032                 // if IncreaseEdicts was called the base pointer needs to be updated
1033                 if (ent)
1034                         val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
1035                 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
1036                 break;
1037
1038         case ev_field:
1039                 if (*s != '.')
1040                 {
1041                         Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, PRVM_NAME);
1042                         return false;
1043                 }
1044                 def = PRVM_ED_FindField(s + 1);
1045                 if (!def)
1046                 {
1047                         Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
1048                         return false;
1049                 }
1050                 val->_int = def->ofs;
1051                 break;
1052
1053         case ev_function:
1054                 func = PRVM_ED_FindFunction(s);
1055                 if (!func)
1056                 {
1057                         Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
1058                         return false;
1059                 }
1060                 val->function = func - prog->functions;
1061                 break;
1062
1063         default:
1064                 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
1065                 return false;
1066         }
1067         return true;
1068 }
1069
1070 /*
1071 =============
1072 PRVM_GameCommand_f
1073
1074 Console command to send a string to QC function GameCommand of the
1075 indicated progs
1076
1077 Usage:
1078   sv_cmd adminmsg 3 "do not teamkill"
1079   cl_cmd someclientcommand
1080   menu_cmd somemenucommand
1081
1082 All progs can support this extension; sg calls it in server QC, cg in client
1083 QC, mg in menu QC.
1084 =============
1085 */
1086 void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
1087 {
1088         if(Cmd_Argc() < 1)
1089         {
1090                 Con_Printf("%s text...\n", whichcmd);
1091                 return;
1092         }
1093
1094         PRVM_Begin;
1095         if(!PRVM_SetProgFromString(whichprogs))
1096         // note: this is not PRVM_SetProg because that one aborts "hard" using PRVM_Error
1097         // also, it makes printing error messages easier!
1098         {
1099                 Con_Printf("%s program not loaded.\n", whichprogs);
1100                 return;
1101         }
1102
1103         if(!prog->funcoffsets.GameCommand)
1104         {
1105                 Con_Printf("%s program do not support GameCommand!\n", whichprogs);
1106         }
1107         else
1108         {
1109                 int restorevm_tempstringsbuf_cursize;
1110                 const char *s;
1111
1112                 s = Cmd_Args();
1113
1114                 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1115                 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
1116                 PRVM_ExecuteProgram (prog->funcoffsets.GameCommand, "QC function GameCommand is missing");
1117                 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1118         }
1119
1120         PRVM_End;
1121 }
1122 void PRVM_GameCommand_Server_f(void)
1123 {
1124         PRVM_GameCommand("server", "sv_cmd");
1125 }
1126 void PRVM_GameCommand_Client_f(void)
1127 {
1128         PRVM_GameCommand("client", "cl_cmd");
1129 }
1130 void PRVM_GameCommand_Menu_f(void)
1131 {
1132         PRVM_GameCommand("menu", "menu_cmd");
1133 }
1134
1135 /*
1136 =============
1137 PRVM_ED_EdictSet_f
1138
1139 Console command to set a field of a specified edict
1140 =============
1141 */
1142 void PRVM_ED_EdictSet_f(void)
1143 {
1144         prvm_edict_t *ed;
1145         ddef_t *key;
1146
1147         if(Cmd_Argc() != 5)
1148         {
1149                 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1150                 return;
1151         }
1152
1153         PRVM_Begin;
1154         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1155         {
1156                 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1157                 return;
1158         }
1159
1160         ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1161
1162         if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1163                 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1164         else
1165                 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4), true);
1166
1167         PRVM_End;
1168 }
1169
1170 /*
1171 ====================
1172 PRVM_ED_ParseEdict
1173
1174 Parses an edict out of the given string, returning the new position
1175 ed should be a properly initialized empty edict.
1176 Used for initial level load and for savegames.
1177 ====================
1178 */
1179 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1180 {
1181         ddef_t *key;
1182         qboolean anglehack;
1183         qboolean init;
1184         char keyname[256];
1185         size_t n;
1186
1187         init = false;
1188
1189 // go through all the dictionary pairs
1190         while (1)
1191         {
1192         // parse key
1193                 if (!COM_ParseToken_Simple(&data, false, false))
1194                         PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1195                 if (developer_entityparsing.integer)
1196                         Con_Printf("Key: \"%s\"", com_token);
1197                 if (com_token[0] == '}')
1198                         break;
1199
1200                 // anglehack is to allow QuakeEd to write single scalar angles
1201                 // and allow them to be turned into vectors. (FIXME...)
1202                 if (!strcmp(com_token, "angle"))
1203                 {
1204                         strlcpy (com_token, "angles", sizeof(com_token));
1205                         anglehack = true;
1206                 }
1207                 else
1208                         anglehack = false;
1209
1210                 // FIXME: change light to _light to get rid of this hack
1211                 if (!strcmp(com_token, "light"))
1212                         strlcpy (com_token, "light_lev", sizeof(com_token));    // hack for single light def
1213
1214                 strlcpy (keyname, com_token, sizeof(keyname));
1215
1216                 // another hack to fix keynames with trailing spaces
1217                 n = strlen(keyname);
1218                 while (n && keyname[n-1] == ' ')
1219                 {
1220                         keyname[n-1] = 0;
1221                         n--;
1222                 }
1223
1224         // parse value
1225                 if (!COM_ParseToken_Simple(&data, false, false))
1226                         PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1227                 if (developer_entityparsing.integer)
1228                         Con_Printf(" \"%s\"\n", com_token);
1229
1230                 if (com_token[0] == '}')
1231                         PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1232
1233                 init = true;
1234
1235                 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1236                 if (!keyname[0])
1237                         continue;
1238
1239 // keynames with a leading underscore are used for utility comments,
1240 // and are immediately discarded by quake
1241                 if (keyname[0] == '_')
1242                         continue;
1243
1244                 key = PRVM_ED_FindField (keyname);
1245                 if (!key)
1246                 {
1247                         Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1248                         continue;
1249                 }
1250
1251                 if (anglehack)
1252                 {
1253                         char    temp[32];
1254                         strlcpy (temp, com_token, sizeof(temp));
1255                         dpsnprintf (com_token, sizeof(com_token), "0 %s 0", temp);
1256                 }
1257
1258                 if (!PRVM_ED_ParseEpair(ent, key, com_token, strcmp(keyname, "wad") != 0))
1259                         PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1260         }
1261
1262         if (!init)
1263                 ent->priv.required->free = true;
1264
1265         return data;
1266 }
1267
1268
1269 /*
1270 ================
1271 PRVM_ED_LoadFromFile
1272
1273 The entities are directly placed in the array, rather than allocated with
1274 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1275 number references out of order.
1276
1277 Creates a server's entity / program execution context by
1278 parsing textual entity definitions out of an ent file.
1279
1280 Used for both fresh maps and savegame loads.  A fresh map would also need
1281 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1282 ================
1283 */
1284 void PRVM_ED_LoadFromFile (const char *data)
1285 {
1286         prvm_edict_t *ent;
1287         int parsed, inhibited, spawned, died;
1288         const char *funcname;
1289         mfunction_t *func;
1290
1291         parsed = 0;
1292         inhibited = 0;
1293         spawned = 0;
1294         died = 0;
1295
1296
1297 // parse ents
1298         while (1)
1299         {
1300 // parse the opening brace
1301                 if (!COM_ParseToken_Simple(&data, false, false))
1302                         break;
1303                 if (com_token[0] != '{')
1304                         PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1305
1306                 // CHANGED: this is not conform to PR_LoadFromFile
1307                 if(prog->loadintoworld)
1308                 {
1309                         prog->loadintoworld = false;
1310                         ent = PRVM_EDICT_NUM(0);
1311                 }
1312                 else
1313                         ent = PRVM_ED_Alloc();
1314
1315                 // clear it
1316                 if (ent != prog->edicts)        // hack
1317                         memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1318
1319                 data = PRVM_ED_ParseEdict (data, ent);
1320                 parsed++;
1321
1322                 // remove the entity ?
1323                 if(prog->load_edict && !prog->load_edict(ent))
1324                 {
1325                         PRVM_ED_Free(ent);
1326                         inhibited++;
1327                         continue;
1328                 }
1329
1330                 if (prog->funcoffsets.SV_OnEntityPreSpawnFunction)
1331                 {
1332                         // self = ent
1333                         PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1334                         PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityPreSpawnFunction, "QC function SV_OnEntityPreSpawnFunction is missing");
1335                 }
1336
1337                 if(ent->priv.required->free)
1338                 {
1339                         inhibited++;
1340                         continue;
1341                 }
1342
1343 //
1344 // immediately call spawn function, but only if there is a self global and a classname
1345 //
1346                 if(!ent->priv.required->free)
1347                 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1348                 {
1349                         string_t handle =  PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1350                         if (!handle)
1351                         {
1352                                 Con_Print("No classname for:\n");
1353                                 PRVM_ED_Print(ent, NULL);
1354                                 PRVM_ED_Free (ent);
1355                                 continue;
1356                         }
1357
1358                         // look for the spawn function
1359                         funcname = PRVM_GetString(handle);
1360                         func = PRVM_ED_FindFunction (va("spawnfunc_%s", funcname));
1361                         if(!func)
1362                                 if(prog->globaloffsets.require_spawnfunc_prefix < 0)
1363                                         func = PRVM_ED_FindFunction (funcname);
1364
1365                         if (!func)
1366                         {
1367                                 // check for OnEntityNoSpawnFunction
1368                                 if (prog->funcoffsets.SV_OnEntityNoSpawnFunction)
1369                                 {
1370                                         // self = ent
1371                                         PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1372                                         PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityNoSpawnFunction, "QC function SV_OnEntityNoSpawnFunction is missing");
1373                                 }
1374                                 else
1375                                 {
1376                                         if (developer.integer) // don't confuse non-developers with errors
1377                                         {
1378                                                 Con_Print("No spawn function for:\n");
1379                                                 PRVM_ED_Print(ent, NULL);
1380                                         }
1381                                         PRVM_ED_Free (ent);
1382                                         continue; // not included in "inhibited" count
1383                                 }
1384                         }
1385                         else
1386                         {
1387                                 // self = ent
1388                                 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1389                                 PRVM_ExecuteProgram (func - prog->functions, "");
1390                         }
1391                 }
1392
1393                 if(!ent->priv.required->free)
1394                 if (prog->funcoffsets.SV_OnEntityPostSpawnFunction)
1395                 {
1396                         // self = ent
1397                         PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1398                         PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityPostSpawnFunction, "QC function SV_OnEntityPostSpawnFunction is missing");
1399                 }
1400
1401                 spawned++;
1402                 if (ent->priv.required->free)
1403                         died++;
1404         }
1405
1406         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);
1407 }
1408
1409 void PRVM_FindOffsets(void)
1410 {
1411         // field and global searches use -1 for NULL
1412         memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1413         memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1414         // functions use 0 for NULL
1415         memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1416
1417         // server and client qc use a lot of similar fields, so this is combined
1418         prog->fieldoffsets.SendEntity                     = PRVM_ED_FindFieldOffset("SendEntity");
1419         prog->fieldoffsets.SendFlags                      = PRVM_ED_FindFieldOffset("SendFlags");
1420         prog->fieldoffsets.Version                        = PRVM_ED_FindFieldOffset("Version");
1421         prog->fieldoffsets.alpha                          = PRVM_ED_FindFieldOffset("alpha");
1422         prog->fieldoffsets.ammo_cells1                    = PRVM_ED_FindFieldOffset("ammo_cells1");
1423         prog->fieldoffsets.ammo_lava_nails                = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1424         prog->fieldoffsets.ammo_multi_rockets             = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1425         prog->fieldoffsets.ammo_nails1                    = PRVM_ED_FindFieldOffset("ammo_nails1");
1426         prog->fieldoffsets.ammo_plasma                    = PRVM_ED_FindFieldOffset("ammo_plasma");
1427         prog->fieldoffsets.ammo_rockets1                  = PRVM_ED_FindFieldOffset("ammo_rockets1");
1428         prog->fieldoffsets.ammo_shells1                   = PRVM_ED_FindFieldOffset("ammo_shells1");
1429         prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
1430         prog->fieldoffsets.button3                        = PRVM_ED_FindFieldOffset("button3");
1431         prog->fieldoffsets.button4                        = PRVM_ED_FindFieldOffset("button4");
1432         prog->fieldoffsets.button5                        = PRVM_ED_FindFieldOffset("button5");
1433         prog->fieldoffsets.button6                        = PRVM_ED_FindFieldOffset("button6");
1434         prog->fieldoffsets.button7                        = PRVM_ED_FindFieldOffset("button7");
1435         prog->fieldoffsets.button8                        = PRVM_ED_FindFieldOffset("button8");
1436         prog->fieldoffsets.button9                        = PRVM_ED_FindFieldOffset("button9");
1437         prog->fieldoffsets.button10                       = PRVM_ED_FindFieldOffset("button10");
1438         prog->fieldoffsets.button11                       = PRVM_ED_FindFieldOffset("button11");
1439         prog->fieldoffsets.button12                       = PRVM_ED_FindFieldOffset("button12");
1440         prog->fieldoffsets.button13                       = PRVM_ED_FindFieldOffset("button13");
1441         prog->fieldoffsets.button14                       = PRVM_ED_FindFieldOffset("button14");
1442         prog->fieldoffsets.button15                       = PRVM_ED_FindFieldOffset("button15");
1443         prog->fieldoffsets.button16                       = PRVM_ED_FindFieldOffset("button16");
1444         prog->fieldoffsets.buttonchat                     = PRVM_ED_FindFieldOffset("buttonchat");
1445         prog->fieldoffsets.buttonuse                      = PRVM_ED_FindFieldOffset("buttonuse");
1446         prog->fieldoffsets.chain                          = PRVM_ED_FindFieldOffset("chain");
1447         prog->fieldoffsets.classname                      = PRVM_ED_FindFieldOffset("classname");
1448         prog->fieldoffsets.clientcamera                   = PRVM_ED_FindFieldOffset("clientcamera");
1449         prog->fieldoffsets.clientcolors                   = PRVM_ED_FindFieldOffset("clientcolors");
1450         prog->fieldoffsets.clientstatus                   = PRVM_ED_FindFieldOffset("clientstatus");
1451         prog->fieldoffsets.color                          = PRVM_ED_FindFieldOffset("color");
1452         prog->fieldoffsets.colormod                       = PRVM_ED_FindFieldOffset("colormod");
1453         prog->fieldoffsets.contentstransition             = PRVM_ED_FindFieldOffset("contentstransition");
1454         prog->fieldoffsets.cursor_active                  = PRVM_ED_FindFieldOffset("cursor_active");
1455         prog->fieldoffsets.cursor_screen                  = PRVM_ED_FindFieldOffset("cursor_screen");
1456         prog->fieldoffsets.cursor_trace_endpos            = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1457         prog->fieldoffsets.cursor_trace_ent               = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1458         prog->fieldoffsets.cursor_trace_start             = PRVM_ED_FindFieldOffset("cursor_trace_start");
1459         prog->fieldoffsets.customizeentityforclient       = PRVM_ED_FindFieldOffset("customizeentityforclient");
1460         prog->fieldoffsets.dimension_hit                  = PRVM_ED_FindFieldOffset("dimension_hit");
1461         prog->fieldoffsets.dimension_solid                = PRVM_ED_FindFieldOffset("dimension_solid");
1462         prog->fieldoffsets.disableclientprediction        = PRVM_ED_FindFieldOffset("disableclientprediction");
1463         prog->fieldoffsets.dphitcontentsmask              = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1464         prog->fieldoffsets.drawonlytoclient               = PRVM_ED_FindFieldOffset("drawonlytoclient");
1465         prog->fieldoffsets.exteriormodeltoclient          = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1466         prog->fieldoffsets.fatness                        = PRVM_ED_FindFieldOffset("fatness");
1467         prog->fieldoffsets.forceshader                    = PRVM_ED_FindFieldOffset("forceshader");
1468         prog->fieldoffsets.frame                          = PRVM_ED_FindFieldOffset("frame");
1469         prog->fieldoffsets.frame1time                     = PRVM_ED_FindFieldOffset("frame1time");
1470         prog->fieldoffsets.frame2                         = PRVM_ED_FindFieldOffset("frame2");
1471         prog->fieldoffsets.frame2time                     = PRVM_ED_FindFieldOffset("frame2time");
1472         prog->fieldoffsets.frame3                         = PRVM_ED_FindFieldOffset("frame3");
1473         prog->fieldoffsets.frame3time                     = PRVM_ED_FindFieldOffset("frame3time");
1474         prog->fieldoffsets.frame4                         = PRVM_ED_FindFieldOffset("frame4");
1475         prog->fieldoffsets.frame4time                     = PRVM_ED_FindFieldOffset("frame4time");
1476         prog->fieldoffsets.fullbright                     = PRVM_ED_FindFieldOffset("fullbright");
1477         prog->fieldoffsets.glow_color                     = PRVM_ED_FindFieldOffset("glow_color");
1478         prog->fieldoffsets.glow_size                      = PRVM_ED_FindFieldOffset("glow_size");
1479         prog->fieldoffsets.glow_trail                     = PRVM_ED_FindFieldOffset("glow_trail");
1480         prog->fieldoffsets.gravity                        = PRVM_ED_FindFieldOffset("gravity");
1481         prog->fieldoffsets.groundentity                   = PRVM_ED_FindFieldOffset("groundentity");
1482         prog->fieldoffsets.hull                           = PRVM_ED_FindFieldOffset("hull");
1483         prog->fieldoffsets.ideal_yaw                      = PRVM_ED_FindFieldOffset("ideal_yaw");
1484         prog->fieldoffsets.idealpitch                     = PRVM_ED_FindFieldOffset("idealpitch");
1485         prog->fieldoffsets.items2                         = PRVM_ED_FindFieldOffset("items2");
1486         prog->fieldoffsets.lerpfrac                       = PRVM_ED_FindFieldOffset("lerpfrac");
1487         prog->fieldoffsets.lerpfrac3                      = PRVM_ED_FindFieldOffset("lerpfrac3");
1488         prog->fieldoffsets.lerpfrac4                      = PRVM_ED_FindFieldOffset("lerpfrac4");
1489         prog->fieldoffsets.light_lev                      = PRVM_ED_FindFieldOffset("light_lev");
1490         prog->fieldoffsets.message                        = PRVM_ED_FindFieldOffset("message");
1491         prog->fieldoffsets.modelflags                     = PRVM_ED_FindFieldOffset("modelflags");
1492         prog->fieldoffsets.movement                       = PRVM_ED_FindFieldOffset("movement");
1493         prog->fieldoffsets.movetypesteplandevent          = PRVM_ED_FindFieldOffset("movetypesteplandevent");
1494         prog->fieldoffsets.netaddress                     = PRVM_ED_FindFieldOffset("netaddress");
1495         prog->fieldoffsets.nextthink                      = PRVM_ED_FindFieldOffset("nextthink");
1496         prog->fieldoffsets.nodrawtoclient                 = PRVM_ED_FindFieldOffset("nodrawtoclient");
1497         prog->fieldoffsets.pflags                         = PRVM_ED_FindFieldOffset("pflags");
1498         prog->fieldoffsets.ping                           = PRVM_ED_FindFieldOffset("ping");
1499         prog->fieldoffsets.pitch_speed                    = PRVM_ED_FindFieldOffset("pitch_speed");
1500         prog->fieldoffsets.playermodel                    = PRVM_ED_FindFieldOffset("playermodel");
1501         prog->fieldoffsets.playerskin                     = PRVM_ED_FindFieldOffset("playerskin");
1502         prog->fieldoffsets.pmodel                         = PRVM_ED_FindFieldOffset("pmodel");
1503         prog->fieldoffsets.punchvector                    = PRVM_ED_FindFieldOffset("punchvector");
1504         prog->fieldoffsets.renderamt                      = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1505         prog->fieldoffsets.renderflags                    = PRVM_ED_FindFieldOffset("renderflags");
1506         prog->fieldoffsets.rendermode                     = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1507         prog->fieldoffsets.scale                          = PRVM_ED_FindFieldOffset("scale");
1508         prog->fieldoffsets.shadertime                     = PRVM_ED_FindFieldOffset("shadertime");
1509         prog->fieldoffsets.style                          = PRVM_ED_FindFieldOffset("style");
1510         prog->fieldoffsets.tag_entity                     = PRVM_ED_FindFieldOffset("tag_entity");
1511         prog->fieldoffsets.tag_index                      = PRVM_ED_FindFieldOffset("tag_index");
1512         prog->fieldoffsets.think                          = PRVM_ED_FindFieldOffset("think");
1513         prog->fieldoffsets.viewmodelforclient             = PRVM_ED_FindFieldOffset("viewmodelforclient");
1514         prog->fieldoffsets.viewzoom                       = PRVM_ED_FindFieldOffset("viewzoom");
1515         prog->fieldoffsets.yaw_speed                      = PRVM_ED_FindFieldOffset("yaw_speed");
1516         prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1517         prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1518         prog->funcoffsets.CSQC_Ent_Spawn                  = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
1519         prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1520         prog->funcoffsets.CSQC_Event                      = PRVM_ED_FindFunctionOffset("CSQC_Event");
1521         prog->funcoffsets.CSQC_Event_Sound                = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
1522         prog->funcoffsets.CSQC_Init                       = PRVM_ED_FindFunctionOffset("CSQC_Init");
1523         prog->funcoffsets.CSQC_InputEvent                 = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1524         prog->funcoffsets.CSQC_Parse_CenterPrint          = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1525         prog->funcoffsets.CSQC_Parse_Print                = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1526         prog->funcoffsets.CSQC_Parse_StuffCmd             = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1527         prog->funcoffsets.CSQC_Parse_TempEntity           = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1528         prog->funcoffsets.CSQC_Shutdown                   = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1529         prog->funcoffsets.CSQC_UpdateView                 = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1530         prog->funcoffsets.EndFrame                        = PRVM_ED_FindFunctionOffset("EndFrame");
1531         prog->funcoffsets.GameCommand                     = PRVM_ED_FindFunctionOffset("GameCommand");
1532         prog->funcoffsets.Gecko_Query                     = PRVM_ED_FindFunctionOffset("Gecko_Query");
1533         prog->funcoffsets.RestoreGame                     = PRVM_ED_FindFunctionOffset("RestoreGame");
1534         prog->funcoffsets.SV_ChangeTeam                   = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1535         prog->funcoffsets.SV_OnEntityNoSpawnFunction      = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
1536         prog->funcoffsets.SV_OnEntityPostSpawnFunction    = PRVM_ED_FindFunctionOffset("SV_OnEntityPostSpawnFunction");
1537         prog->funcoffsets.SV_OnEntityPreSpawnFunction     = PRVM_ED_FindFunctionOffset("SV_OnEntityPreSpawnFunction");
1538         prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1539         prog->funcoffsets.SV_PausedTic                    = PRVM_ED_FindFunctionOffset("SV_PausedTic");
1540         prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1541         prog->funcoffsets.SV_Shutdown                     = PRVM_ED_FindFunctionOffset("SV_Shutdown");
1542         prog->funcoffsets.URI_Get_Callback                = PRVM_ED_FindFunctionOffset("URI_Get_Callback");
1543         prog->globaloffsets.SV_InitCmd                    = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1544         prog->globaloffsets.coop                          = PRVM_ED_FindGlobalOffset("coop");
1545         prog->globaloffsets.deathmatch                    = PRVM_ED_FindGlobalOffset("deathmatch");
1546         prog->globaloffsets.dmg_origin                    = PRVM_ED_FindGlobalOffset("dmg_origin");
1547         prog->globaloffsets.dmg_save                      = PRVM_ED_FindGlobalOffset("dmg_save");
1548         prog->globaloffsets.dmg_take                      = PRVM_ED_FindGlobalOffset("dmg_take");
1549         prog->globaloffsets.drawfont                      = PRVM_ED_FindGlobalOffset("drawfont");
1550         prog->globaloffsets.gettaginfo_forward            = PRVM_ED_FindGlobalOffset("gettaginfo_forward");
1551         prog->globaloffsets.gettaginfo_name               = PRVM_ED_FindGlobalOffset("gettaginfo_name");
1552         prog->globaloffsets.gettaginfo_offset             = PRVM_ED_FindGlobalOffset("gettaginfo_offset");
1553         prog->globaloffsets.gettaginfo_parent             = PRVM_ED_FindGlobalOffset("gettaginfo_parent");
1554         prog->globaloffsets.gettaginfo_right              = PRVM_ED_FindGlobalOffset("gettaginfo_right");
1555         prog->globaloffsets.gettaginfo_up                 = PRVM_ED_FindGlobalOffset("gettaginfo_up");
1556         prog->globaloffsets.intermission                  = PRVM_ED_FindGlobalOffset("intermission");
1557         prog->globaloffsets.require_spawnfunc_prefix      = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
1558         prog->globaloffsets.sb_showscores                 = PRVM_ED_FindGlobalOffset("sb_showscores");
1559         prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
1560         prog->globaloffsets.serverdeltatime               = PRVM_ED_FindGlobalOffset("serverdeltatime");
1561         prog->globaloffsets.serverprevtime                = PRVM_ED_FindGlobalOffset("serverprevtime");
1562         prog->globaloffsets.servertime                    = PRVM_ED_FindGlobalOffset("servertime");
1563         prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
1564         prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
1565         prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1566         prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1567         prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1568         prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1569         prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
1570         prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
1571         prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
1572         prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
1573         prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
1574         prog->globaloffsets.trace_networkentity           = PRVM_ED_FindGlobalOffset("trace_networkentity");
1575         prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1576         prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1577         prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
1578         prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
1579         prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
1580         prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
1581         prog->globaloffsets.view_angles                   = PRVM_ED_FindGlobalOffset("view_angles");
1582         prog->globaloffsets.worldstatus                   = PRVM_ED_FindGlobalOffset("worldstatus");
1583
1584         // menu qc only uses some functions, nothing else
1585         prog->funcoffsets.m_draw                          = PRVM_ED_FindFunctionOffset("m_draw");
1586         prog->funcoffsets.m_init                          = PRVM_ED_FindFunctionOffset("m_init");
1587         prog->funcoffsets.m_keydown                       = PRVM_ED_FindFunctionOffset("m_keydown");
1588         prog->funcoffsets.m_keyup                         = PRVM_ED_FindFunctionOffset("m_keyup");
1589         prog->funcoffsets.m_shutdown                      = PRVM_ED_FindFunctionOffset("m_shutdown");
1590         prog->funcoffsets.m_toggle                        = PRVM_ED_FindFunctionOffset("m_toggle");
1591 }
1592
1593 // not used
1594 /*
1595 typedef struct dpfield_s
1596 {
1597         int type;
1598         char *string;
1599 }
1600 dpfield_t;
1601
1602 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1603
1604 dpfield_t dpfields[] =
1605 {
1606 };
1607 */
1608
1609 /*
1610 ===============
1611 PRVM_ResetProg
1612 ===============
1613 */
1614
1615 void PRVM_LeakTest();
1616 void PRVM_ResetProg()
1617 {
1618         PRVM_LeakTest();
1619         PRVM_GCALL(reset_cmd)();
1620         Mem_FreePool(&prog->progs_mempool);
1621         memset(prog,0,sizeof(prvm_prog_t));
1622         prog->starttime = Sys_DoubleTime();
1623 }
1624
1625 /*
1626 ===============
1627 PRVM_LoadLNO
1628 ===============
1629 */
1630 void PRVM_LoadLNO( const char *progname ) {
1631         fs_offset_t filesize;
1632         unsigned char *lno;
1633         unsigned int *header;
1634         char filename[512];
1635
1636         FS_StripExtension( progname, filename, sizeof( filename ) );
1637         strlcat( filename, ".lno", sizeof( filename ) );
1638
1639         lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1640         if( !lno ) {
1641                 return;
1642         }
1643
1644 /*
1645 <Spike>    SafeWrite (h, &lnotype, sizeof(int));
1646 <Spike>    SafeWrite (h, &version, sizeof(int));
1647 <Spike>    SafeWrite (h, &numglobaldefs, sizeof(int));
1648 <Spike>    SafeWrite (h, &numpr_globals, sizeof(int));
1649 <Spike>    SafeWrite (h, &numfielddefs, sizeof(int));
1650 <Spike>    SafeWrite (h, &numstatements, sizeof(int));
1651 <Spike>    SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1652 */
1653         if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1654                 Mem_Free(lno);
1655                 return;
1656         }
1657
1658         header = (unsigned int *) lno;
1659         if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1660                 LittleLong( header[ 1 ] ) == 1 &&
1661                 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1662                 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1663                 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1664                 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1665         {
1666                 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1667                 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1668         }
1669         Mem_Free( lno );
1670 }
1671
1672 /*
1673 ===============
1674 PRVM_LoadProgs
1675 ===============
1676 */
1677 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1678 {
1679         int i;
1680         dstatement_t *st;
1681         ddef_t *infielddefs;
1682         dfunction_t *dfunctions;
1683         fs_offset_t filesize;
1684
1685         if( prog->loaded ) {
1686                 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1687         }
1688
1689         prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1690         if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1691                 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1692
1693         Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1694
1695         prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1696
1697 // byte swap the header
1698         for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1699                 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1700
1701         if (prog->progs->version != PROG_VERSION)
1702                 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1703         if (prog->progs->crc != prog->headercrc && prog->progs->crc != prog->headercrc2)
1704                 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);
1705
1706         //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1707         dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1708
1709         if (prog->progs->ofs_strings + prog->progs->numstrings >= (int)filesize)
1710                 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1711         prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1712         prog->stringssize = prog->progs->numstrings;
1713
1714         prog->numknownstrings = 0;
1715         prog->maxknownstrings = 0;
1716         prog->knownstrings = NULL;
1717         prog->knownstrings_freeable = NULL;
1718
1719         Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
1720
1721         prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1722
1723         // we need to expand the fielddefs list to include all the engine fields,
1724         // so allocate a new place for it
1725         infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1726         //                                                                                              ( + DPFIELDS                       )
1727         prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1728
1729         prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1730
1731         prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1732
1733         // moved edict_size calculation down below field adding code
1734
1735         //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1736         prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1737
1738 // byte swap the lumps
1739         for (i=0 ; i<prog->progs->numstatements ; i++)
1740         {
1741                 prog->statements[i].op = LittleShort(prog->statements[i].op);
1742                 prog->statements[i].a = LittleShort(prog->statements[i].a);
1743                 prog->statements[i].b = LittleShort(prog->statements[i].b);
1744                 prog->statements[i].c = LittleShort(prog->statements[i].c);
1745         }
1746
1747         prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1748         for (i = 0;i < prog->progs->numfunctions;i++)
1749         {
1750                 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1751                 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1752                 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1753                 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1754                 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1755                 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1756                 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1757         }
1758
1759         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1760         {
1761                 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1762                 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1763                 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1764         }
1765
1766         // copy the progs fields to the new fields list
1767         for (i = 0;i < prog->progs->numfielddefs;i++)
1768         {
1769                 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1770                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1771                         PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1772                 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1773                 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1774         }
1775
1776         // append the required fields
1777         for (i = 0;i < (int) numrequiredfields;i++)
1778         {
1779                 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1780                 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1781                 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1782                 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1783                         prog->progs->entityfields += 3;
1784                 else
1785                         prog->progs->entityfields++;
1786                 prog->progs->numfielddefs++;
1787         }
1788
1789         // check required functions
1790         for(i=0 ; i < numrequiredfunc ; i++)
1791                 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1792                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1793
1794         // check required globals
1795         for(i=0 ; i < numrequiredglobals ; i++)
1796                 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1797                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1798
1799         for (i=0 ; i<prog->progs->numglobals ; i++)
1800                 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1801
1802         // moved edict_size calculation down here, below field adding code
1803         // LordHavoc: this no longer includes the prvm_edict_t header
1804         prog->edict_size = prog->progs->entityfields * 4;
1805         prog->edictareasize = prog->edict_size * prog->limit_edicts;
1806
1807         // LordHavoc: bounds check anything static
1808         for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1809         {
1810                 switch (st->op)
1811                 {
1812                 case OP_IF:
1813                 case OP_IFNOT:
1814                         if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1815                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1816                         break;
1817                 case OP_GOTO:
1818                         if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1819                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1820                         break;
1821                 // global global global
1822                 case OP_ADD_F:
1823                 case OP_ADD_V:
1824                 case OP_SUB_F:
1825                 case OP_SUB_V:
1826                 case OP_MUL_F:
1827                 case OP_MUL_V:
1828                 case OP_MUL_FV:
1829                 case OP_MUL_VF:
1830                 case OP_DIV_F:
1831                 case OP_BITAND:
1832                 case OP_BITOR:
1833                 case OP_GE:
1834                 case OP_LE:
1835                 case OP_GT:
1836                 case OP_LT:
1837                 case OP_AND:
1838                 case OP_OR:
1839                 case OP_EQ_F:
1840                 case OP_EQ_V:
1841                 case OP_EQ_S:
1842                 case OP_EQ_E:
1843                 case OP_EQ_FNC:
1844                 case OP_NE_F:
1845                 case OP_NE_V:
1846                 case OP_NE_S:
1847                 case OP_NE_E:
1848                 case OP_NE_FNC:
1849                 case OP_ADDRESS:
1850                 case OP_LOAD_F:
1851                 case OP_LOAD_FLD:
1852                 case OP_LOAD_ENT:
1853                 case OP_LOAD_S:
1854                 case OP_LOAD_FNC:
1855                 case OP_LOAD_V:
1856                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1857                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1858                         break;
1859                 // global none global
1860                 case OP_NOT_F:
1861                 case OP_NOT_V:
1862                 case OP_NOT_S:
1863                 case OP_NOT_FNC:
1864                 case OP_NOT_ENT:
1865                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1866                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1867                         break;
1868                 // 2 globals
1869                 case OP_STOREP_F:
1870                 case OP_STOREP_ENT:
1871                 case OP_STOREP_FLD:
1872                 case OP_STOREP_S:
1873                 case OP_STOREP_FNC:
1874                 case OP_STORE_F:
1875                 case OP_STORE_ENT:
1876                 case OP_STORE_FLD:
1877                 case OP_STORE_S:
1878                 case OP_STORE_FNC:
1879                 case OP_STATE:
1880                 case OP_STOREP_V:
1881                 case OP_STORE_V:
1882                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1883                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1884                         break;
1885                 // 1 global
1886                 case OP_CALL0:
1887                 case OP_CALL1:
1888                 case OP_CALL2:
1889                 case OP_CALL3:
1890                 case OP_CALL4:
1891                 case OP_CALL5:
1892                 case OP_CALL6:
1893                 case OP_CALL7:
1894                 case OP_CALL8:
1895                 case OP_DONE:
1896                 case OP_RETURN:
1897                         if ((unsigned short) st->a >= prog->progs->numglobals)
1898                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1899                         break;
1900                 default:
1901                         Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1902                         break;
1903                 }
1904         }
1905
1906         PRVM_LoadLNO(filename);
1907
1908         PRVM_Init_Exec();
1909
1910         prog->loaded = TRUE;
1911
1912         // set flags & ddef_ts in prog
1913
1914         prog->flag = 0;
1915
1916         PRVM_FindOffsets();
1917
1918         PRVM_GCALL(init_cmd)();
1919
1920         // init mempools
1921         PRVM_MEM_Alloc();
1922 }
1923
1924
1925 void PRVM_Fields_f (void)
1926 {
1927         int i, j, ednum, used, usedamount;
1928         int *counts;
1929         char tempstring[MAX_INPUTLINE], tempstring2[260];
1930         const char *name;
1931         prvm_edict_t *ed;
1932         ddef_t *d;
1933         int *v;
1934
1935         // TODO
1936         /*
1937         if (!sv.active)
1938         {
1939                 Con_Print("no progs loaded\n");
1940                 return;
1941         }
1942         */
1943
1944         if(Cmd_Argc() != 2)
1945         {
1946                 Con_Print("prvm_fields <program name>\n");
1947                 return;
1948         }
1949
1950         PRVM_Begin;
1951         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1952                 return;
1953
1954         counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1955         for (ednum = 0;ednum < prog->max_edicts;ednum++)
1956         {
1957                 ed = PRVM_EDICT_NUM(ednum);
1958                 if (ed->priv.required->free)
1959                         continue;
1960                 for (i = 1;i < prog->progs->numfielddefs;i++)
1961                 {
1962                         d = &prog->fielddefs[i];
1963                         name = PRVM_GetString(d->s_name);
1964                         if (name[strlen(name)-2] == '_')
1965                                 continue;       // skip _x, _y, _z vars
1966                         v = (int *)((char *)ed->fields.vp + d->ofs*4);
1967                         // if the value is still all 0, skip the field
1968                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1969                         {
1970                                 if (v[j])
1971                                 {
1972                                         counts[i]++;
1973                                         break;
1974                                 }
1975                         }
1976                 }
1977         }
1978         used = 0;
1979         usedamount = 0;
1980         tempstring[0] = 0;
1981         for (i = 0;i < prog->progs->numfielddefs;i++)
1982         {
1983                 d = &prog->fielddefs[i];
1984                 name = PRVM_GetString(d->s_name);
1985                 if (name[strlen(name)-2] == '_')
1986                         continue;       // skip _x, _y, _z vars
1987                 switch(d->type & ~DEF_SAVEGLOBAL)
1988                 {
1989                 case ev_string:
1990                         strlcat(tempstring, "string   ", sizeof(tempstring));
1991                         break;
1992                 case ev_entity:
1993                         strlcat(tempstring, "entity   ", sizeof(tempstring));
1994                         break;
1995                 case ev_function:
1996                         strlcat(tempstring, "function ", sizeof(tempstring));
1997                         break;
1998                 case ev_field:
1999                         strlcat(tempstring, "field    ", sizeof(tempstring));
2000                         break;
2001                 case ev_void:
2002                         strlcat(tempstring, "void     ", sizeof(tempstring));
2003                         break;
2004                 case ev_float:
2005                         strlcat(tempstring, "float    ", sizeof(tempstring));
2006                         break;
2007                 case ev_vector:
2008                         strlcat(tempstring, "vector   ", sizeof(tempstring));
2009                         break;
2010                 case ev_pointer:
2011                         strlcat(tempstring, "pointer  ", sizeof(tempstring));
2012                         break;
2013                 default:
2014                         dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
2015                         strlcat(tempstring, tempstring2, sizeof(tempstring));
2016                         break;
2017                 }
2018                 if (strlen(name) > sizeof(tempstring2)-4)
2019                 {
2020                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
2021                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
2022                         tempstring2[sizeof(tempstring2)-1] = 0;
2023                         name = tempstring2;
2024                 }
2025                 strlcat(tempstring, name, sizeof(tempstring));
2026                 for (j = (int)strlen(name);j < 25;j++)
2027                         strlcat(tempstring, " ", sizeof(tempstring));
2028                 dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]);
2029                 strlcat(tempstring, tempstring2, sizeof(tempstring));
2030                 strlcat(tempstring, "\n", sizeof(tempstring));
2031                 if (strlen(tempstring) >= sizeof(tempstring)/2)
2032                 {
2033                         Con_Print(tempstring);
2034                         tempstring[0] = 0;
2035                 }
2036                 if (counts[i])
2037                 {
2038                         used++;
2039                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
2040                 }
2041         }
2042         Mem_Free(counts);
2043         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);
2044
2045         PRVM_End;
2046 }
2047
2048 void PRVM_Globals_f (void)
2049 {
2050         int i;
2051         const char *wildcard;
2052         int numculled;
2053                 numculled = 0;
2054         // TODO
2055         /*if (!sv.active)
2056         {
2057                 Con_Print("no progs loaded\n");
2058                 return;
2059         }*/
2060         if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
2061         {
2062                 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
2063                 return;
2064         }
2065
2066         PRVM_Begin;
2067         if(!PRVM_SetProgFromString (Cmd_Argv (1)))
2068                 return;
2069
2070         if( Cmd_Argc() == 3)
2071                 wildcard = Cmd_Argv(2);
2072         else
2073                 wildcard = NULL;
2074
2075         Con_Printf("%s :", PRVM_NAME);
2076
2077         for (i = 0;i < prog->progs->numglobaldefs;i++)
2078         {
2079                 if(wildcard)
2080                         if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
2081                         {
2082                                 numculled++;
2083                                 continue;
2084                         }
2085                 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
2086         }
2087         Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->progs->numglobals, numculled, prog->progs->numglobals * 4);
2088
2089         PRVM_End;
2090 }
2091
2092 /*
2093 ===============
2094 PRVM_Global
2095 ===============
2096 */
2097 void PRVM_Global_f(void)
2098 {
2099         ddef_t *global;
2100         if( Cmd_Argc() != 3 ) {
2101                 Con_Printf( "prvm_global <program name> <global name>\n" );
2102                 return;
2103         }
2104
2105         PRVM_Begin;
2106         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2107                 return;
2108
2109         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2110         if( !global )
2111                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2112         else
2113                 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
2114         PRVM_End;
2115 }
2116
2117 /*
2118 ===============
2119 PRVM_GlobalSet
2120 ===============
2121 */
2122 void PRVM_GlobalSet_f(void)
2123 {
2124         ddef_t *global;
2125         if( Cmd_Argc() != 4 ) {
2126                 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2127                 return;
2128         }
2129
2130         PRVM_Begin;
2131         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2132                 return;
2133
2134         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2135         if( !global )
2136                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2137         else
2138                 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3), true );
2139         PRVM_End;
2140 }
2141
2142 /*
2143 ===============
2144 PRVM_Init
2145 ===============
2146 */
2147 void PRVM_Init (void)
2148 {
2149         Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2150         Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2151         Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2152         Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2153         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)");
2154         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)");
2155         Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2156         Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2157         Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2158         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)");
2159         Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2160         Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2161         Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2162         Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2163
2164         // COMMANDLINEOPTION: PRVM: -noboundscheck disables the bounds checks (security hole if CSQC is in use!)
2165         prvm_boundscheck = !COM_CheckParm("-noboundscheck");
2166
2167         Cvar_RegisterVariable (&prvm_traceqc);
2168         Cvar_RegisterVariable (&prvm_statementprofiling);
2169         Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2170         Cvar_RegisterVariable (&prvm_leaktest);
2171         Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames);
2172         Cvar_RegisterVariable (&prvm_errordump);
2173
2174         // COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!)
2175         prvm_runawaycheck = !COM_CheckParm("-norunaway");
2176
2177         //VM_Cmd_Init();
2178 }
2179
2180 /*
2181 ===============
2182 PRVM_InitProg
2183 ===============
2184 */
2185 void PRVM_InitProg(int prognr)
2186 {
2187         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
2188                 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
2189
2190         prog = &prog_list[prognr];
2191
2192         if(prog->loaded)
2193                 PRVM_ResetProg();
2194
2195         memset(prog, 0, sizeof(prvm_prog_t));
2196         prog->starttime = Sys_DoubleTime();
2197
2198         prog->error_cmd = Host_Error;
2199         prog->leaktest_active = prvm_leaktest.integer;
2200 }
2201
2202 int PRVM_GetProgNr()
2203 {
2204         return prog - prog_list;
2205 }
2206
2207 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
2208 {
2209         return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
2210 }
2211
2212 void _PRVM_Free(void *buffer, const char *filename, int fileline)
2213 {
2214         _Mem_Free(buffer, filename, fileline);
2215 }
2216
2217 void _PRVM_FreeAll(const char *filename, int fileline)
2218 {
2219         prog->progs = NULL;
2220         prog->fielddefs = NULL;
2221         prog->functions = NULL;
2222         _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
2223 }
2224
2225 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2226 unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, char *filename, int fileline)
2227 {
2228         PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
2229         return 0;
2230 }
2231
2232 /*
2233 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
2234 {
2235         PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
2236         return 0;
2237 }
2238
2239 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
2240 {
2241         int n;
2242         n = e - prog->edicts;
2243         if ((unsigned int)n >= prog->limit_edicts)
2244                 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
2245         return n;
2246 }
2247
2248 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
2249 //{
2250 //      return e - prog->edicts;
2251 //}
2252
2253 //#define       PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
2254 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
2255 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
2256 {
2257         int n;
2258         n = e - prog->edicts;
2259         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2260                 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2261         return n;// EXPERIMENTAL
2262         //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2263 }
2264 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2265 {
2266         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2267                 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2268         return prog->edicts + n; // EXPERIMENTAL
2269         //return prog->edicts + ((n) / (progs->entityfields * 4));
2270 }
2271 */
2272
2273
2274 sizebuf_t vm_tempstringsbuf;
2275
2276 const char *PRVM_GetString(int num)
2277 {
2278         if (num >= 0)
2279         {
2280                 if (num < prog->stringssize)
2281                         return prog->strings + num;
2282                 else
2283 #if 1
2284                 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2285                 {
2286                         num -= prog->stringssize;
2287                         if (num < vm_tempstringsbuf.cursize)
2288                                 return (char *)vm_tempstringsbuf.data + num;
2289                         else
2290                         {
2291                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2292                                 return "";
2293                         }
2294                 }
2295                 else
2296 #endif
2297                 {
2298                         VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
2299                         return "";
2300                 }
2301         }
2302         else
2303         {
2304                 num = -1 - num;
2305 #if 0
2306                 if (num >= (1<<30))
2307                 {
2308                         // special range reserved for tempstrings
2309                         num -= (1<<30);
2310                         if (num < vm_tempstringsbuf.cursize)
2311                                 return (char *)vm_tempstringsbuf.data + num;
2312                         else
2313                         {
2314                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2315                                 return "";
2316                         }
2317                 }
2318                 else
2319 #endif
2320                 if (num < prog->numknownstrings)
2321                 {
2322                         if (!prog->knownstrings[num])
2323                                 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
2324                         return prog->knownstrings[num];
2325                 }
2326                 else
2327                 {
2328                         VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
2329                         return "";
2330                 }
2331         }
2332 }
2333
2334 int PRVM_SetEngineString(const char *s)
2335 {
2336         int i;
2337         if (!s)
2338                 return 0;
2339         if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2340                 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2341         // if it's in the tempstrings area, use a reserved range
2342         // (otherwise we'd get millions of useless string offsets cluttering the database)
2343         if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2344 #if 1
2345                 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2346 #else
2347                 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2348 #endif
2349         // see if it's a known string address
2350         for (i = 0;i < prog->numknownstrings;i++)
2351                 if (prog->knownstrings[i] == s)
2352                         return -1 - i;
2353         // new unknown engine string
2354         if (developer.integer >= 200)
2355                 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2356         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2357                 if (!prog->knownstrings[i])
2358                         break;
2359         if (i >= prog->numknownstrings)
2360         {
2361                 if (i >= prog->maxknownstrings)
2362                 {
2363                         const char **oldstrings = prog->knownstrings;
2364                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2365                         const char **oldstrings_origin = prog->knownstrings_origin;
2366                         prog->maxknownstrings += 128;
2367                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2368                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2369                         if(prog->leaktest_active)
2370                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2371                         if (prog->numknownstrings)
2372                         {
2373                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2374                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2375                                 if(prog->leaktest_active)
2376                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
2377                         }
2378                 }
2379                 prog->numknownstrings++;
2380         }
2381         prog->firstfreeknownstring = i + 1;
2382         prog->knownstrings[i] = s;
2383         prog->knownstrings_freeable[i] = false;
2384         if(prog->leaktest_active)
2385                 prog->knownstrings_origin[i] = NULL;
2386         return -1 - i;
2387 }
2388
2389 // temp string handling
2390
2391 // all tempstrings go into this buffer consecutively, and it is reset
2392 // whenever PRVM_ExecuteProgram returns to the engine
2393 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2394 //  restores it on return, so multiple recursive calls can share the same
2395 //  buffer)
2396 // the buffer size is automatically grown as needed
2397
2398 int PRVM_SetTempString(const char *s)
2399 {
2400         int size;
2401         char *t;
2402         if (!s)
2403                 return 0;
2404         size = (int)strlen(s) + 1;
2405         if (developer.integer >= 300)
2406                 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2407         if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2408         {
2409                 sizebuf_t old = vm_tempstringsbuf;
2410                 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2411                         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);
2412                 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2413                 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2414                         vm_tempstringsbuf.maxsize *= 2;
2415                 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2416                 {
2417                         if (developer.integer >= 100)
2418                                 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2419                         vm_tempstringsbuf.data = (unsigned char *) Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2420                         if (old.cursize)
2421                                 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2422                         if (old.data)
2423                                 Mem_Free(old.data);
2424                 }
2425         }
2426         t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2427         memcpy(t, s, size);
2428         vm_tempstringsbuf.cursize += size;
2429         return PRVM_SetEngineString(t);
2430 }
2431
2432 int PRVM_AllocString(size_t bufferlength, char **pointer)
2433 {
2434         int i;
2435         if (!bufferlength)
2436                 return 0;
2437         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2438                 if (!prog->knownstrings[i])
2439                         break;
2440         if (i >= prog->numknownstrings)
2441         {
2442                 if (i >= prog->maxknownstrings)
2443                 {
2444                         const char **oldstrings = prog->knownstrings;
2445                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2446                         const char **oldstrings_origin = prog->knownstrings_origin;
2447                         prog->maxknownstrings += 128;
2448                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2449                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2450                         if(prog->leaktest_active)
2451                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2452                         if (prog->numknownstrings)
2453                         {
2454                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2455                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2456                                 if(prog->leaktest_active)
2457                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
2458                         }
2459                         // TODO why not Mem_Free the old ones?
2460                 }
2461                 prog->numknownstrings++;
2462         }
2463         prog->firstfreeknownstring = i + 1;
2464         prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2465         prog->knownstrings_freeable[i] = true;
2466         if(prog->leaktest_active)
2467                 prog->knownstrings_origin[i] = PRVM_AllocationOrigin();
2468         if (pointer)
2469                 *pointer = (char *)(prog->knownstrings[i]);
2470         return -1 - i;
2471 }
2472
2473 void PRVM_FreeString(int num)
2474 {
2475         if (num == 0)
2476                 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2477         else if (num >= 0 && num < prog->stringssize)
2478                 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2479         else if (num < 0 && num >= -prog->numknownstrings)
2480         {
2481                 num = -1 - num;
2482                 if (!prog->knownstrings[num])
2483                         PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2484                 if (!prog->knownstrings_freeable[num])
2485                         PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2486                 PRVM_Free((char *)prog->knownstrings[num]);
2487                 if(prog->leaktest_active)
2488                         if(prog->knownstrings_origin[num])
2489                                 PRVM_Free((char *)prog->knownstrings_origin[num]);
2490                 prog->knownstrings[num] = NULL;
2491                 prog->knownstrings_freeable[num] = false;
2492                 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2493         }
2494         else
2495                 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);
2496 }
2497
2498 static qboolean PRVM_IsStringReferenced(string_t string)
2499 {
2500         int i, j;
2501
2502         for (i = 0;i < prog->progs->numglobaldefs;i++)
2503         {
2504                 ddef_t *d = &prog->globaldefs[i];
2505                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
2506                         continue;
2507                 if(string == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->string)
2508                         return true;
2509         }
2510
2511         for(j = 0; j < prog->num_edicts; ++j)
2512         {
2513                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2514                 if (ed->priv.required->free)
2515                         continue;
2516                 for (i=0; i<prog->progs->numfielddefs; ++i)
2517                 {
2518                         ddef_t *d = &prog->fielddefs[i];
2519                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
2520                                 continue;
2521                         if(string == ((prvm_eval_t *) &((float*)ed->fields.vp)[d->ofs])->string)
2522                                 return true;
2523                 }
2524         }
2525
2526         return false;
2527 }
2528
2529 static qboolean PRVM_IsEdictRelevant(prvm_edict_t *edict)
2530 {
2531         if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts)
2532                 return true; // world or clients
2533         switch(prog - prog_list)
2534         {
2535                 case PRVM_SERVERPROG:
2536                         {
2537                                 entvars_t *ev = edict->fields.server;
2538                                 if(ev->solid) // can block other stuff, or is a trigger?
2539                                         return true;
2540                                 if(ev->modelindex) // visible ent?
2541                                         return true;
2542                                 if(ev->effects) // particle effect?
2543                                         return true;
2544                                 if(ev->think) // has a think function?
2545                                         if(ev->nextthink > 0) // that actually will eventually run?
2546                                                 return true;
2547                                 if(ev->takedamage)
2548                                         return true;
2549                                 if(*prvm_leaktest_ignore_classnames.string)
2550                                 {
2551                                         if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(ev->classname))))
2552                                                 return true;
2553                                 }
2554                         }
2555                         break;
2556                 case PRVM_CLIENTPROG:
2557                         {
2558                                 // TODO someone add more stuff here
2559                                 cl_entvars_t *ev = edict->fields.client;
2560                                 if(ev->entnum) // csqc networked
2561                                         return true;
2562                                 if(ev->modelindex) // visible ent?
2563                                         return true;
2564                                 if(ev->effects) // particle effect?
2565                                         return true;
2566                                 if(ev->think) // has a think function?
2567                                         if(ev->nextthink > 0) // that actually will eventually run?
2568                                                 return true;
2569                                 if(*prvm_leaktest_ignore_classnames.string)
2570                                 {
2571                                         if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(ev->classname))))
2572                                                 return true;
2573                                 }
2574                         }
2575                         break;
2576                 case PRVM_MENUPROG:
2577                         // menu prog does not have classnames
2578                         break;
2579         }
2580         return false;
2581 }
2582
2583 static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
2584 {
2585         int i, j;
2586         int edictnum = PRVM_NUM_FOR_EDICT(edict);
2587         const char *targetname = NULL;
2588
2589         switch(prog - prog_list)
2590         {
2591                 case PRVM_SERVERPROG:
2592                         targetname = PRVM_GetString(edict->fields.server->targetname);
2593                         break;
2594         }
2595
2596         if(targetname)
2597                 if(!*targetname) // ""
2598                         targetname = NULL;
2599
2600         for (i = 0;i < prog->progs->numglobaldefs;i++)
2601         {
2602                 ddef_t *d = &prog->globaldefs[i];
2603                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
2604                         continue;
2605                 if(edictnum == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->edict)
2606                         return true;
2607         }
2608
2609         for(j = 0; j < prog->num_edicts; ++j)
2610         {
2611                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2612                 if (ed->priv.required->mark < mark)
2613                         continue;
2614                 if(ed == edict)
2615                         continue;
2616                 if(targetname)
2617                 {
2618                         const char *target = PRVM_GetString(ed->fields.server->target);
2619                         if(target)
2620                                 if(!strcmp(target, targetname))
2621                                         return true;
2622                 }
2623                 for (i=0; i<prog->progs->numfielddefs; ++i)
2624                 {
2625                         ddef_t *d = &prog->fielddefs[i];
2626                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
2627                                 continue;
2628                         if(edictnum == ((prvm_eval_t *) &((float*)ed->fields.vp)[d->ofs])->edict)
2629                                 return true;
2630                 }
2631         }
2632
2633         return false;
2634 }
2635
2636 static void PRVM_MarkReferencedEdicts()
2637 {
2638         int j;
2639         qboolean found_new;
2640         int stage;
2641
2642         for(j = 0; j < prog->num_edicts; ++j)
2643         {
2644                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2645                 if(ed->priv.required->free)
2646                         continue;
2647                 ed->priv.required->mark = PRVM_IsEdictRelevant(ed) ? 1 : 0;
2648         }
2649
2650         stage = 1;
2651         do
2652         {
2653                 found_new = false;
2654                 for(j = 0; j < prog->num_edicts; ++j)
2655                 {
2656                         prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2657                         if(ed->priv.required->free)
2658                                 continue;
2659                         if(ed->priv.required->mark)
2660                                 continue;
2661                         if(PRVM_IsEdictReferenced(ed, stage))
2662                         {
2663                                 ed->priv.required->mark = stage + 1;
2664                                 found_new = true;
2665                         }
2666                 }
2667                 ++stage;
2668         }
2669         while(found_new);
2670         Con_DPrintf("leak check used %d stages to find all references\n", stage);
2671 }
2672
2673 void PRVM_LeakTest()
2674 {
2675         int i, j;
2676         qboolean leaked = false;
2677
2678         if(!prog->leaktest_active)
2679                 return;
2680
2681         // 1. Strings
2682         for (i = 0; i < prog->numknownstrings; ++i)
2683         {
2684                 if(prog->knownstrings[i])
2685                 if(prog->knownstrings_freeable[i])
2686                 if(prog->knownstrings_origin[i])
2687                 if(!PRVM_IsStringReferenced(-1 - i))
2688                 {
2689                         Con_Printf("Unreferenced string found!\n  Value: %s\n  Origin: %s\n", prog->knownstrings[i], prog->knownstrings_origin[i]);
2690                         leaked = true;
2691                 }
2692         }
2693
2694         // 2. Edicts
2695         PRVM_MarkReferencedEdicts();
2696         for(j = 0; j < prog->num_edicts; ++j)
2697         {
2698                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2699                 if(ed->priv.required->free)
2700                         continue;
2701                 if(!ed->priv.required->mark)
2702                 if(ed->priv.required->allocation_origin)
2703                 {
2704                         Con_Printf("Unreferenced edict found!\n  Allocated at: %s\n", ed->priv.required->allocation_origin);
2705                         PRVM_ED_Print(ed, NULL);
2706                         Con_Print("\n");
2707                         leaked = true;
2708                 }
2709         }
2710
2711         for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i)
2712         {
2713                 prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
2714                 if(stringbuffer)
2715                 if(stringbuffer->origin)
2716                 {
2717                         Con_Printf("Open string buffer handle found!\n  Allocated at: %s\n", stringbuffer->origin);
2718                         leaked = true;
2719                 }
2720         }
2721
2722         for(i = 0; i < PRVM_MAX_OPENFILES; ++i)
2723         {
2724                 if(prog->openfiles[i])
2725                 if(prog->openfiles_origin[i])
2726                 {
2727                         Con_Printf("Open file handle found!\n  Allocated at: %s\n", prog->openfiles_origin[i]);
2728                         leaked = true;
2729                 }
2730         }
2731
2732         for(i = 0; i < PRVM_MAX_OPENSEARCHES; ++i)
2733         {
2734                 if(prog->opensearches[i])
2735                 if(prog->opensearches_origin[i])
2736                 {
2737                         Con_Printf("Open search handle found!\n  Allocated at: %s\n", prog->opensearches_origin[i]);
2738                         leaked = true;
2739                 }
2740         }
2741
2742         if(!leaked)
2743                 Con_Printf("Congratulations. No leaks found.\n");
2744 }