PageRenderTime 68ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/prvm_edict.c

https://gitlab.com/xonotic/darkplaces
C | 3442 lines | 2660 code | 315 blank | 467 comment | 623 complexity | 5de758c7fc3eb88bffae9d8eb3e51fab MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // AK new vm
  16. #include "quakedef.h"
  17. #include "progsvm.h"
  18. #include "csprogs.h"
  19. prvm_prog_t prvm_prog_list[PRVM_PROG_MAX];
  20. int prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
  21. prvm_eval_t prvm_badvalue; // used only for error returns
  22. cvar_t prvm_language = {CVAR_SAVE, "prvm_language", "", "when set, loads PROGSFILE.LANGUAGENAME.po and common.LANGUAGENAME.po for string translations; when set to dump, PROGSFILE.pot is written from the strings in the progs"};
  23. // LordHavoc: prints every opcode as it executes - warning: this is significant spew
  24. cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
  25. // LordHavoc: counts usage of each QuakeC statement
  26. 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)"};
  27. cvar_t prvm_timeprofiling = {0, "prvm_timeprofiling", "0", "counts how long each function has been executed, these counts are displayed in prvm_profile output (if enabled)"};
  28. cvar_t prvm_coverage = {0, "prvm_coverage", "0", "report and count coverage events (1: per-function, 2: coverage() builtin, 4: per-statement)"};
  29. cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"};
  30. cvar_t prvm_leaktest = {0, "prvm_leaktest", "0", "try to detect memory leaks in strings or entities"};
  31. cvar_t prvm_leaktest_follow_targetname = {0, "prvm_leaktest_follow_targetname", "0", "if set, target/targetname links are considered when leak testing; this should normally not be required, as entities created during startup - e.g. info_notnull - are never considered leaky"};
  32. 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)"};
  33. cvar_t prvm_errordump = {0, "prvm_errordump", "0", "write a savegame on crash to crash-server.dmp"};
  34. cvar_t prvm_breakpointdump = {0, "prvm_breakpointdump", "0", "write a savegame on breakpoint to breakpoint-server.dmp"};
  35. cvar_t prvm_reuseedicts_startuptime = {0, "prvm_reuseedicts_startuptime", "2", "allows immediate re-use of freed entity slots during start of new level (value in seconds)"};
  36. cvar_t prvm_reuseedicts_neverinsameframe = {0, "prvm_reuseedicts_neverinsameframe", "1", "never allows re-use of freed entity slots during same frame"};
  37. static double prvm_reuseedicts_always_allow = 0;
  38. qboolean prvm_runawaycheck = true;
  39. //============================================================================
  40. // mempool handling
  41. /*
  42. ===============
  43. PRVM_MEM_Alloc
  44. ===============
  45. */
  46. static void PRVM_MEM_Alloc(prvm_prog_t *prog)
  47. {
  48. int i;
  49. // reserve space for the null entity aka world
  50. // check bound of max_edicts
  51. prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
  52. prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
  53. // edictprivate_size has to be min as big prvm_edict_private_t
  54. prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
  55. // alloc edicts
  56. prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
  57. // alloc edict private space
  58. prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
  59. // alloc edict fields
  60. prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
  61. prog->edictsfields = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(prvm_vec_t));
  62. // set edict pointers
  63. for(i = 0; i < prog->max_edicts; i++)
  64. {
  65. prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
  66. prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields;
  67. }
  68. }
  69. /*
  70. ===============
  71. PRVM_MEM_IncreaseEdicts
  72. ===============
  73. */
  74. void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog)
  75. {
  76. int i;
  77. if(prog->max_edicts >= prog->limit_edicts)
  78. return;
  79. prog->begin_increase_edicts(prog);
  80. // increase edicts
  81. prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
  82. prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
  83. prog->edictsfields = (prvm_vec_t*)Mem_Realloc(prog->progs_mempool, (void *)prog->edictsfields, prog->entityfieldsarea * sizeof(prvm_vec_t));
  84. prog->edictprivate = (void *)Mem_Realloc(prog->progs_mempool, (void *)prog->edictprivate, prog->max_edicts * prog->edictprivate_size);
  85. //set e and v pointers
  86. for(i = 0; i < prog->max_edicts; i++)
  87. {
  88. prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
  89. prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields;
  90. }
  91. prog->end_increase_edicts(prog);
  92. }
  93. //============================================================================
  94. // normal prvm
  95. int PRVM_ED_FindFieldOffset(prvm_prog_t *prog, const char *field)
  96. {
  97. ddef_t *d;
  98. d = PRVM_ED_FindField(prog, field);
  99. if (!d)
  100. return -1;
  101. return d->ofs;
  102. }
  103. int PRVM_ED_FindGlobalOffset(prvm_prog_t *prog, const char *global)
  104. {
  105. ddef_t *d;
  106. d = PRVM_ED_FindGlobal(prog, global);
  107. if (!d)
  108. return -1;
  109. return d->ofs;
  110. }
  111. func_t PRVM_ED_FindFunctionOffset(prvm_prog_t *prog, const char *function)
  112. {
  113. mfunction_t *f;
  114. f = PRVM_ED_FindFunction(prog, function);
  115. if (!f)
  116. return 0;
  117. return (func_t)(f - prog->functions);
  118. }
  119. /*
  120. =================
  121. PRVM_ProgFromString
  122. =================
  123. */
  124. prvm_prog_t *PRVM_ProgFromString(const char *str)
  125. {
  126. if (!strcmp(str, "server"))
  127. return SVVM_prog;
  128. if (!strcmp(str, "client"))
  129. return CLVM_prog;
  130. #ifdef CONFIG_MENU
  131. if (!strcmp(str, "menu"))
  132. return MVM_prog;
  133. #endif
  134. return NULL;
  135. }
  136. /*
  137. =================
  138. PRVM_FriendlyProgFromString
  139. =================
  140. */
  141. prvm_prog_t *PRVM_FriendlyProgFromString(const char *str)
  142. {
  143. prvm_prog_t *prog = PRVM_ProgFromString(str);
  144. if (!prog)
  145. {
  146. Con_Printf("%s: unknown program name\n", str);
  147. return NULL;
  148. }
  149. if (!prog->loaded)
  150. {
  151. Con_Printf("%s: program is not loaded\n", str);
  152. return NULL;
  153. }
  154. return prog;
  155. }
  156. /*
  157. =================
  158. PRVM_ED_ClearEdict
  159. Sets everything to NULL.
  160. Nota bene: this also marks the entity as allocated if it has been previously
  161. freed and sets the allocation origin.
  162. =================
  163. */
  164. void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e)
  165. {
  166. memset(e->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
  167. e->priv.required->free = false;
  168. e->priv.required->freetime = realtime;
  169. if(e->priv.required->allocation_origin)
  170. Mem_Free((char *)e->priv.required->allocation_origin);
  171. e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog);
  172. // AK: Let the init_edict function determine if something needs to be initialized
  173. prog->init_edict(prog, e);
  174. }
  175. const char *PRVM_AllocationOrigin(prvm_prog_t *prog)
  176. {
  177. char *buf = NULL;
  178. if(prog->leaktest_active)
  179. if(prog->depth > 0) // actually in QC code and not just parsing the entities block of a map/savegame
  180. {
  181. buf = (char *)PRVM_Alloc(256);
  182. PRVM_ShortStackTrace(prog, buf, 256);
  183. }
  184. return buf;
  185. }
  186. /*
  187. =================
  188. PRVM_ED_CanAlloc
  189. Returns if this particular edict could get allocated by PRVM_ED_Alloc
  190. =================
  191. */
  192. qboolean PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e)
  193. {
  194. if(!e->priv.required->free)
  195. return false;
  196. if(prvm_reuseedicts_always_allow == realtime)
  197. return true;
  198. if(realtime <= e->priv.required->freetime + 0.1 && prvm_reuseedicts_neverinsameframe.integer)
  199. return false; // never allow reuse in same frame (causes networking trouble)
  200. if(e->priv.required->freetime < prog->starttime + prvm_reuseedicts_startuptime.value)
  201. return true;
  202. if(realtime > e->priv.required->freetime + 1)
  203. return true;
  204. return false; // entity slot still blocked because the entity was freed less than one second ago
  205. }
  206. /*
  207. =================
  208. PRVM_ED_Alloc
  209. Either finds a free edict, or allocates a new one.
  210. Try to avoid reusing an entity that was recently freed, because it
  211. can cause the client to think the entity morphed into something else
  212. instead of being removed and recreated, which can cause interpolated
  213. angles and bad trails.
  214. =================
  215. */
  216. prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog)
  217. {
  218. int i;
  219. prvm_edict_t *e;
  220. // the client qc dont need maxclients
  221. // thus it doesnt need to use svs.maxclients
  222. // AK: changed i=svs.maxclients+1
  223. // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
  224. // although the menu/client has no world
  225. for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
  226. {
  227. e = PRVM_EDICT_NUM(i);
  228. if(PRVM_ED_CanAlloc(prog, e))
  229. {
  230. PRVM_ED_ClearEdict (prog, e);
  231. return e;
  232. }
  233. }
  234. if (i == prog->limit_edicts)
  235. prog->error_cmd("%s: PRVM_ED_Alloc: no free edicts", prog->name);
  236. prog->num_edicts++;
  237. if (prog->num_edicts >= prog->max_edicts)
  238. PRVM_MEM_IncreaseEdicts(prog);
  239. e = PRVM_EDICT_NUM(i);
  240. PRVM_ED_ClearEdict(prog, e);
  241. return e;
  242. }
  243. /*
  244. =================
  245. PRVM_ED_Free
  246. Marks the edict as free
  247. FIXME: walk all entities and NULL out references to this entity
  248. =================
  249. */
  250. void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed)
  251. {
  252. // dont delete the null entity (world) or reserved edicts
  253. if (ed - prog->edicts <= prog->reserved_edicts)
  254. return;
  255. prog->free_edict(prog, ed);
  256. ed->priv.required->free = true;
  257. ed->priv.required->freetime = realtime;
  258. if(ed->priv.required->allocation_origin)
  259. {
  260. Mem_Free((char *)ed->priv.required->allocation_origin);
  261. ed->priv.required->allocation_origin = NULL;
  262. }
  263. }
  264. //===========================================================================
  265. /*
  266. ============
  267. PRVM_ED_GlobalAtOfs
  268. ============
  269. */
  270. static ddef_t *PRVM_ED_GlobalAtOfs (prvm_prog_t *prog, int ofs)
  271. {
  272. ddef_t *def;
  273. int i;
  274. for (i = 0;i < prog->numglobaldefs;i++)
  275. {
  276. def = &prog->globaldefs[i];
  277. if (def->ofs == ofs)
  278. return def;
  279. }
  280. return NULL;
  281. }
  282. /*
  283. ============
  284. PRVM_ED_FieldAtOfs
  285. ============
  286. */
  287. ddef_t *PRVM_ED_FieldAtOfs (prvm_prog_t *prog, int ofs)
  288. {
  289. ddef_t *def;
  290. int i;
  291. for (i = 0;i < prog->numfielddefs;i++)
  292. {
  293. def = &prog->fielddefs[i];
  294. if (def->ofs == ofs)
  295. return def;
  296. }
  297. return NULL;
  298. }
  299. /*
  300. ============
  301. PRVM_ED_FindField
  302. ============
  303. */
  304. ddef_t *PRVM_ED_FindField (prvm_prog_t *prog, const char *name)
  305. {
  306. ddef_t *def;
  307. int i;
  308. for (i = 0;i < prog->numfielddefs;i++)
  309. {
  310. def = &prog->fielddefs[i];
  311. if (!strcmp(PRVM_GetString(prog, def->s_name), name))
  312. return def;
  313. }
  314. return NULL;
  315. }
  316. /*
  317. ============
  318. PRVM_ED_FindGlobal
  319. ============
  320. */
  321. ddef_t *PRVM_ED_FindGlobal (prvm_prog_t *prog, const char *name)
  322. {
  323. ddef_t *def;
  324. int i;
  325. for (i = 0;i < prog->numglobaldefs;i++)
  326. {
  327. def = &prog->globaldefs[i];
  328. if (!strcmp(PRVM_GetString(prog, def->s_name), name))
  329. return def;
  330. }
  331. return NULL;
  332. }
  333. /*
  334. ============
  335. PRVM_ED_FindFunction
  336. ============
  337. */
  338. mfunction_t *PRVM_ED_FindFunction (prvm_prog_t *prog, const char *name)
  339. {
  340. mfunction_t *func;
  341. int i;
  342. for (i = 0;i < prog->numfunctions;i++)
  343. {
  344. func = &prog->functions[i];
  345. if (!strcmp(PRVM_GetString(prog, func->s_name), name))
  346. return func;
  347. }
  348. return NULL;
  349. }
  350. /*
  351. ============
  352. PRVM_ValueString
  353. Returns a string describing *data in a type specific manner
  354. =============
  355. */
  356. static char *PRVM_ValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength)
  357. {
  358. ddef_t *def;
  359. mfunction_t *f;
  360. int n;
  361. type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
  362. switch (type)
  363. {
  364. case ev_string:
  365. strlcpy (line, PRVM_GetString (prog, val->string), linelength);
  366. break;
  367. case ev_entity:
  368. n = val->edict;
  369. if (n < 0 || n >= prog->max_edicts)
  370. dpsnprintf (line, linelength, "entity %i (invalid!)", n);
  371. else
  372. dpsnprintf (line, linelength, "entity %i", n);
  373. break;
  374. case ev_function:
  375. f = prog->functions + val->function;
  376. dpsnprintf (line, linelength, "%s()", PRVM_GetString(prog, f->s_name));
  377. break;
  378. case ev_field:
  379. def = PRVM_ED_FieldAtOfs ( prog, val->_int );
  380. dpsnprintf (line, linelength, ".%s", PRVM_GetString(prog, def->s_name));
  381. break;
  382. case ev_void:
  383. dpsnprintf (line, linelength, "void");
  384. break;
  385. case ev_float:
  386. // LordHavoc: changed from %5.1f to %10.4f
  387. dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float);
  388. break;
  389. case ev_vector:
  390. // LordHavoc: changed from %5.1f to %10.4f
  391. dpsnprintf (line, linelength, "'" VECTOR_LOSSLESS_FORMAT "'", val->vector[0], val->vector[1], val->vector[2]);
  392. break;
  393. case ev_pointer:
  394. dpsnprintf (line, linelength, "pointer");
  395. break;
  396. default:
  397. dpsnprintf (line, linelength, "bad type %i", (int) type);
  398. break;
  399. }
  400. return line;
  401. }
  402. /*
  403. ============
  404. PRVM_UglyValueString
  405. Returns a string describing *data in a type specific manner
  406. Easier to parse than PR_ValueString
  407. =============
  408. */
  409. char *PRVM_UglyValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength)
  410. {
  411. int i;
  412. const char *s;
  413. ddef_t *def;
  414. mfunction_t *f;
  415. type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
  416. switch (type)
  417. {
  418. case ev_string:
  419. // Parse the string a bit to turn special characters
  420. // (like newline, specifically) into escape codes,
  421. // this fixes saving games from various mods
  422. s = PRVM_GetString (prog, val->string);
  423. for (i = 0;i < (int)linelength - 2 && *s;)
  424. {
  425. if (*s == '\n')
  426. {
  427. line[i++] = '\\';
  428. line[i++] = 'n';
  429. }
  430. else if (*s == '\r')
  431. {
  432. line[i++] = '\\';
  433. line[i++] = 'r';
  434. }
  435. else if (*s == '\\')
  436. {
  437. line[i++] = '\\';
  438. line[i++] = '\\';
  439. }
  440. else if (*s == '"')
  441. {
  442. line[i++] = '\\';
  443. line[i++] = '"';
  444. }
  445. else
  446. line[i++] = *s;
  447. s++;
  448. }
  449. line[i] = '\0';
  450. break;
  451. case ev_entity:
  452. dpsnprintf (line, linelength, "%i", val->edict);
  453. break;
  454. case ev_function:
  455. f = prog->functions + val->function;
  456. strlcpy (line, PRVM_GetString (prog, f->s_name), linelength);
  457. break;
  458. case ev_field:
  459. def = PRVM_ED_FieldAtOfs ( prog, val->_int );
  460. dpsnprintf (line, linelength, ".%s", PRVM_GetString(prog, def->s_name));
  461. break;
  462. case ev_void:
  463. dpsnprintf (line, linelength, "void");
  464. break;
  465. case ev_float:
  466. dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float);
  467. break;
  468. case ev_vector:
  469. dpsnprintf (line, linelength, VECTOR_LOSSLESS_FORMAT, val->vector[0], val->vector[1], val->vector[2]);
  470. break;
  471. default:
  472. dpsnprintf (line, linelength, "bad type %i", type);
  473. break;
  474. }
  475. return line;
  476. }
  477. /*
  478. ============
  479. PRVM_GlobalString
  480. Returns a string with a description and the contents of a global,
  481. padded to 20 field width
  482. ============
  483. */
  484. char *PRVM_GlobalString (prvm_prog_t *prog, int ofs, char *line, size_t linelength)
  485. {
  486. char *s;
  487. //size_t i;
  488. ddef_t *def;
  489. prvm_eval_t *val;
  490. char valuebuf[MAX_INPUTLINE];
  491. val = (prvm_eval_t *)&prog->globals.fp[ofs];
  492. def = PRVM_ED_GlobalAtOfs(prog, ofs);
  493. if (!def)
  494. dpsnprintf (line, linelength, "GLOBAL%i", ofs);
  495. else
  496. {
  497. s = PRVM_ValueString (prog, (etype_t)def->type, val, valuebuf, sizeof(valuebuf));
  498. dpsnprintf (line, linelength, "%s (=%s)", PRVM_GetString(prog, def->s_name), s);
  499. }
  500. //i = strlen(line);
  501. //for ( ; i<20 ; i++)
  502. // strcat (line," ");
  503. //strcat (line," ");
  504. return line;
  505. }
  506. char *PRVM_GlobalStringNoContents (prvm_prog_t *prog, int ofs, char *line, size_t linelength)
  507. {
  508. //size_t i;
  509. ddef_t *def;
  510. def = PRVM_ED_GlobalAtOfs(prog, ofs);
  511. if (!def)
  512. dpsnprintf (line, linelength, "GLOBAL%i", ofs);
  513. else
  514. dpsnprintf (line, linelength, "%s", PRVM_GetString(prog, def->s_name));
  515. //i = strlen(line);
  516. //for ( ; i<20 ; i++)
  517. // strcat (line," ");
  518. //strcat (line," ");
  519. return line;
  520. }
  521. /*
  522. =============
  523. PRVM_ED_Print
  524. For debugging
  525. =============
  526. */
  527. // LordHavoc: optimized this to print out much more quickly (tempstring)
  528. // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
  529. void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fieldname)
  530. {
  531. size_t l;
  532. ddef_t *d;
  533. prvm_eval_t *val;
  534. int i, j;
  535. const char *name;
  536. int type;
  537. char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
  538. char valuebuf[MAX_INPUTLINE];
  539. if (ed->priv.required->free)
  540. {
  541. Con_Printf("%s: FREE\n",prog->name);
  542. return;
  543. }
  544. tempstring[0] = 0;
  545. dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", prog->name, PRVM_NUM_FOR_EDICT(ed));
  546. for (i = 1;i < prog->numfielddefs;i++)
  547. {
  548. d = &prog->fielddefs[i];
  549. name = PRVM_GetString(prog, d->s_name);
  550. if(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
  551. continue; // skip _x, _y, _z vars
  552. // Check Field Name Wildcard
  553. if(wildcard_fieldname)
  554. if( !matchpattern(name, wildcard_fieldname, 1) )
  555. // Didn't match; skip
  556. continue;
  557. val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
  558. // if the value is still all 0, skip the field
  559. type = d->type & ~DEF_SAVEGLOBAL;
  560. for (j=0 ; j<prvm_type_size[type] ; j++)
  561. if (val->ivector[j])
  562. break;
  563. if (j == prvm_type_size[type])
  564. continue;
  565. if (strlen(name) > sizeof(tempstring2)-4)
  566. {
  567. memcpy (tempstring2, name, sizeof(tempstring2)-4);
  568. tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
  569. tempstring2[sizeof(tempstring2)-1] = 0;
  570. name = tempstring2;
  571. }
  572. strlcat(tempstring, name, sizeof(tempstring));
  573. for (l = strlen(name);l < 14;l++)
  574. strlcat(tempstring, " ", sizeof(tempstring));
  575. strlcat(tempstring, " ", sizeof(tempstring));
  576. name = PRVM_ValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf));
  577. if (strlen(name) > sizeof(tempstring2)-4)
  578. {
  579. memcpy (tempstring2, name, sizeof(tempstring2)-4);
  580. tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
  581. tempstring2[sizeof(tempstring2)-1] = 0;
  582. name = tempstring2;
  583. }
  584. strlcat(tempstring, name, sizeof(tempstring));
  585. strlcat(tempstring, "\n", sizeof(tempstring));
  586. if (strlen(tempstring) >= sizeof(tempstring)/2)
  587. {
  588. Con_Print(tempstring);
  589. tempstring[0] = 0;
  590. }
  591. }
  592. if (tempstring[0])
  593. Con_Print(tempstring);
  594. }
  595. /*
  596. =============
  597. PRVM_ED_Write
  598. For savegames
  599. =============
  600. */
  601. extern cvar_t developer_entityparsing;
  602. void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed)
  603. {
  604. ddef_t *d;
  605. prvm_eval_t *val;
  606. int i, j;
  607. const char *name;
  608. int type;
  609. char vabuf[1024];
  610. char valuebuf[MAX_INPUTLINE];
  611. FS_Print(f, "{\n");
  612. if (ed->priv.required->free)
  613. {
  614. FS_Print(f, "}\n");
  615. return;
  616. }
  617. for (i = 1;i < prog->numfielddefs;i++)
  618. {
  619. d = &prog->fielddefs[i];
  620. name = PRVM_GetString(prog, d->s_name);
  621. if(developer_entityparsing.integer)
  622. Con_Printf("PRVM_ED_Write: at entity %d field %s\n", PRVM_NUM_FOR_EDICT(ed), name);
  623. //if(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
  624. if(strlen(name) > 1 && name[strlen(name)-2] == '_')
  625. continue; // skip _x, _y, _z vars, and ALSO other _? vars as some mods expect them to be never saved (TODO: a gameplayfix for using the "more precise" condition above?)
  626. val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
  627. // if the value is still all 0, skip the field
  628. type = d->type & ~DEF_SAVEGLOBAL;
  629. for (j=0 ; j<prvm_type_size[type] ; j++)
  630. if (val->ivector[j])
  631. break;
  632. if (j == prvm_type_size[type])
  633. continue;
  634. FS_Printf(f,"\"%s\" ",name);
  635. prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_Write, ent=%d, name=%s", i, name);
  636. FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf)));
  637. prog->statestring = NULL;
  638. }
  639. FS_Print(f, "}\n");
  640. }
  641. void PRVM_ED_PrintNum (prvm_prog_t *prog, int ent, const char *wildcard_fieldname)
  642. {
  643. PRVM_ED_Print(prog, PRVM_EDICT_NUM(ent), wildcard_fieldname);
  644. }
  645. /*
  646. =============
  647. PRVM_ED_PrintEdicts_f
  648. For debugging, prints all the entities in the current server
  649. =============
  650. */
  651. void PRVM_ED_PrintEdicts_f (void)
  652. {
  653. prvm_prog_t *prog;
  654. int i;
  655. const char *wildcard_fieldname;
  656. if(Cmd_Argc() < 2 || Cmd_Argc() > 3)
  657. {
  658. Con_Print("prvm_edicts <program name> <optional field name wildcard>\n");
  659. return;
  660. }
  661. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  662. return;
  663. if( Cmd_Argc() == 3)
  664. wildcard_fieldname = Cmd_Argv(2);
  665. else
  666. wildcard_fieldname = NULL;
  667. Con_Printf("%s: %i entities\n", prog->name, prog->num_edicts);
  668. for (i=0 ; i<prog->num_edicts ; i++)
  669. PRVM_ED_PrintNum (prog, i, wildcard_fieldname);
  670. }
  671. /*
  672. =============
  673. PRVM_ED_PrintEdict_f
  674. For debugging, prints a single edict
  675. =============
  676. */
  677. static void PRVM_ED_PrintEdict_f (void)
  678. {
  679. prvm_prog_t *prog;
  680. int i;
  681. const char *wildcard_fieldname;
  682. if(Cmd_Argc() < 3 || Cmd_Argc() > 4)
  683. {
  684. Con_Print("prvm_edict <program name> <edict number> <optional field name wildcard>\n");
  685. return;
  686. }
  687. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  688. return;
  689. i = atoi (Cmd_Argv(2));
  690. if (i >= prog->num_edicts)
  691. {
  692. Con_Print("Bad edict number\n");
  693. return;
  694. }
  695. if( Cmd_Argc() == 4)
  696. // Optional Wildcard Provided
  697. wildcard_fieldname = Cmd_Argv(3);
  698. else
  699. // Use All
  700. wildcard_fieldname = NULL;
  701. PRVM_ED_PrintNum (prog, i, wildcard_fieldname);
  702. }
  703. /*
  704. =============
  705. PRVM_ED_Count
  706. For debugging
  707. =============
  708. */
  709. // 2 possibilities : 1. just displaying the active edict count
  710. // 2. making a function pointer [x]
  711. static void PRVM_ED_Count_f (void)
  712. {
  713. prvm_prog_t *prog;
  714. if(Cmd_Argc() != 2)
  715. {
  716. Con_Print("prvm_count <program name>\n");
  717. return;
  718. }
  719. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  720. return;
  721. prog->count_edicts(prog);
  722. }
  723. /*
  724. ==============================================================================
  725. ARCHIVING GLOBALS
  726. FIXME: need to tag constants, doesn't really work
  727. ==============================================================================
  728. */
  729. /*
  730. =============
  731. PRVM_ED_WriteGlobals
  732. =============
  733. */
  734. void PRVM_ED_WriteGlobals (prvm_prog_t *prog, qfile_t *f)
  735. {
  736. ddef_t *def;
  737. int i;
  738. const char *name;
  739. int type;
  740. char vabuf[1024];
  741. char valuebuf[MAX_INPUTLINE];
  742. FS_Print(f,"{\n");
  743. for (i = 0;i < prog->numglobaldefs;i++)
  744. {
  745. def = &prog->globaldefs[i];
  746. type = def->type;
  747. if ( !(def->type & DEF_SAVEGLOBAL) )
  748. continue;
  749. type &= ~DEF_SAVEGLOBAL;
  750. if (type != ev_string && type != ev_float && type != ev_entity)
  751. continue;
  752. name = PRVM_GetString(prog, def->s_name);
  753. if(developer_entityparsing.integer)
  754. Con_Printf("PRVM_ED_WriteGlobals: at global %s\n", name);
  755. prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_WriteGlobals, name=%s", name);
  756. FS_Printf(f,"\"%s\" ", name);
  757. FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)type, (prvm_eval_t *)&prog->globals.fp[def->ofs], valuebuf, sizeof(valuebuf)));
  758. prog->statestring = NULL;
  759. }
  760. FS_Print(f,"}\n");
  761. }
  762. /*
  763. =============
  764. PRVM_ED_ParseGlobals
  765. =============
  766. */
  767. void PRVM_ED_ParseGlobals (prvm_prog_t *prog, const char *data)
  768. {
  769. char keyname[MAX_INPUTLINE];
  770. ddef_t *key;
  771. while (1)
  772. {
  773. // parse key
  774. if (!COM_ParseToken_Simple(&data, false, false, true))
  775. prog->error_cmd("PRVM_ED_ParseGlobals: EOF without closing brace");
  776. if (com_token[0] == '}')
  777. break;
  778. if (developer_entityparsing.integer)
  779. Con_Printf("Key: \"%s\"", com_token);
  780. strlcpy (keyname, com_token, sizeof(keyname));
  781. // parse value
  782. if (!COM_ParseToken_Simple(&data, false, true, true))
  783. prog->error_cmd("PRVM_ED_ParseGlobals: EOF without closing brace");
  784. if (developer_entityparsing.integer)
  785. Con_Printf(" \"%s\"\n", com_token);
  786. if (com_token[0] == '}')
  787. prog->error_cmd("PRVM_ED_ParseGlobals: closing brace without data");
  788. key = PRVM_ED_FindGlobal (prog, keyname);
  789. if (!key)
  790. {
  791. Con_DPrintf("'%s' is not a global on %s\n", keyname, prog->name);
  792. continue;
  793. }
  794. if (!PRVM_ED_ParseEpair(prog, NULL, key, com_token, true))
  795. prog->error_cmd("PRVM_ED_ParseGlobals: parse error");
  796. }
  797. }
  798. //============================================================================
  799. /*
  800. =============
  801. PRVM_ED_ParseEval
  802. Can parse either fields or globals
  803. returns false if error
  804. =============
  805. */
  806. qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
  807. {
  808. int i, l;
  809. char *new_p;
  810. ddef_t *def;
  811. prvm_eval_t *val;
  812. mfunction_t *func;
  813. if (ent)
  814. val = (prvm_eval_t *)(ent->fields.fp + key->ofs);
  815. else
  816. val = (prvm_eval_t *)(prog->globals.fp + key->ofs);
  817. switch (key->type & ~DEF_SAVEGLOBAL)
  818. {
  819. case ev_string:
  820. l = (int)strlen(s) + 1;
  821. val->string = PRVM_AllocString(prog, l, &new_p);
  822. for (i = 0;i < l;i++)
  823. {
  824. if (s[i] == '\\' && s[i+1] && parsebackslash)
  825. {
  826. i++;
  827. if (s[i] == 'n')
  828. *new_p++ = '\n';
  829. else if (s[i] == 'r')
  830. *new_p++ = '\r';
  831. else
  832. *new_p++ = s[i];
  833. }
  834. else
  835. *new_p++ = s[i];
  836. }
  837. break;
  838. case ev_float:
  839. while (*s && ISWHITESPACE(*s))
  840. s++;
  841. val->_float = atof(s);
  842. break;
  843. case ev_vector:
  844. for (i = 0;i < 3;i++)
  845. {
  846. while (*s && ISWHITESPACE(*s))
  847. s++;
  848. if (!*s)
  849. break;
  850. val->vector[i] = atof(s);
  851. while (!ISWHITESPACE(*s))
  852. s++;
  853. if (!*s)
  854. break;
  855. }
  856. break;
  857. case ev_entity:
  858. while (*s && ISWHITESPACE(*s))
  859. s++;
  860. i = atoi(s);
  861. if (i >= prog->limit_edicts)
  862. Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (unsigned int)i, prog->limit_edicts, prog->name);
  863. while (i >= prog->max_edicts)
  864. PRVM_MEM_IncreaseEdicts(prog);
  865. // if IncreaseEdicts was called the base pointer needs to be updated
  866. if (ent)
  867. val = (prvm_eval_t *)(ent->fields.fp + key->ofs);
  868. val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
  869. break;
  870. case ev_field:
  871. if (*s != '.')
  872. {
  873. Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, prog->name);
  874. return false;
  875. }
  876. def = PRVM_ED_FindField(prog, s + 1);
  877. if (!def)
  878. {
  879. Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, prog->name);
  880. return false;
  881. }
  882. val->_int = def->ofs;
  883. break;
  884. case ev_function:
  885. func = PRVM_ED_FindFunction(prog, s);
  886. if (!func)
  887. {
  888. Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, prog->name);
  889. return false;
  890. }
  891. val->function = func - prog->functions;
  892. break;
  893. default:
  894. Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(prog, key->s_name), prog->name);
  895. return false;
  896. }
  897. return true;
  898. }
  899. /*
  900. =============
  901. PRVM_GameCommand_f
  902. Console command to send a string to QC function GameCommand of the
  903. indicated progs
  904. Usage:
  905. sv_cmd adminmsg 3 "do not teamkill"
  906. cl_cmd someclientcommand
  907. menu_cmd somemenucommand
  908. All progs can support this extension; sg calls it in server QC, cg in client
  909. QC, mg in menu QC.
  910. =============
  911. */
  912. static void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
  913. {
  914. prvm_prog_t *prog;
  915. if(Cmd_Argc() < 1)
  916. {
  917. Con_Printf("%s text...\n", whichcmd);
  918. return;
  919. }
  920. if (!(prog = PRVM_FriendlyProgFromString(whichprogs)))
  921. return;
  922. if(!PRVM_allfunction(GameCommand))
  923. {
  924. Con_Printf("%s program do not support GameCommand!\n", whichprogs);
  925. }
  926. else
  927. {
  928. int restorevm_tempstringsbuf_cursize;
  929. const char *s;
  930. s = Cmd_Args();
  931. restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
  932. PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, s ? s : "");
  933. prog->ExecuteProgram(prog, PRVM_allfunction(GameCommand), "QC function GameCommand is missing");
  934. prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
  935. }
  936. }
  937. static void PRVM_GameCommand_Server_f(void)
  938. {
  939. PRVM_GameCommand("server", "sv_cmd");
  940. }
  941. static void PRVM_GameCommand_Client_f(void)
  942. {
  943. PRVM_GameCommand("client", "cl_cmd");
  944. }
  945. static void PRVM_GameCommand_Menu_f(void)
  946. {
  947. PRVM_GameCommand("menu", "menu_cmd");
  948. }
  949. /*
  950. =============
  951. PRVM_ED_EdictGet_f
  952. Console command to load a field of a specified edict
  953. =============
  954. */
  955. static void PRVM_ED_EdictGet_f(void)
  956. {
  957. prvm_prog_t *prog;
  958. prvm_edict_t *ed;
  959. ddef_t *key;
  960. const char *s;
  961. prvm_eval_t *v;
  962. char valuebuf[MAX_INPUTLINE];
  963. if(Cmd_Argc() != 4 && Cmd_Argc() != 5)
  964. {
  965. Con_Print("prvm_edictget <program name> <edict number> <field> [<cvar>]\n");
  966. return;
  967. }
  968. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  969. return;
  970. ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
  971. if((key = PRVM_ED_FindField(prog, Cmd_Argv(3))) == 0)
  972. {
  973. Con_Printf("Key %s not found !\n", Cmd_Argv(3));
  974. goto fail;
  975. }
  976. v = (prvm_eval_t *)(ed->fields.fp + key->ofs);
  977. s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf));
  978. if(Cmd_Argc() == 5)
  979. {
  980. cvar_t *cvar = Cvar_FindVar(Cmd_Argv(4));
  981. if (cvar && cvar->flags & CVAR_READONLY)
  982. {
  983. Con_Printf("prvm_edictget: %s is read-only\n", cvar->name);
  984. goto fail;
  985. }
  986. Cvar_Get(Cmd_Argv(4), s, 0, NULL);
  987. }
  988. else
  989. Con_Printf("%s\n", s);
  990. fail:
  991. ;
  992. }
  993. static void PRVM_ED_GlobalGet_f(void)
  994. {
  995. prvm_prog_t *prog;
  996. ddef_t *key;
  997. const char *s;
  998. prvm_eval_t *v;
  999. char valuebuf[MAX_INPUTLINE];
  1000. if(Cmd_Argc() != 3 && Cmd_Argc() != 4)
  1001. {
  1002. Con_Print("prvm_globalget <program name> <global> [<cvar>]\n");
  1003. return;
  1004. }
  1005. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  1006. return;
  1007. key = PRVM_ED_FindGlobal(prog, Cmd_Argv(2));
  1008. if(!key)
  1009. {
  1010. Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
  1011. goto fail;
  1012. }
  1013. v = (prvm_eval_t *) &prog->globals.fp[key->ofs];
  1014. s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf));
  1015. if(Cmd_Argc() == 4)
  1016. {
  1017. cvar_t *cvar = Cvar_FindVar(Cmd_Argv(3));
  1018. if (cvar && cvar->flags & CVAR_READONLY)
  1019. {
  1020. Con_Printf("prvm_globalget: %s is read-only\n", cvar->name);
  1021. goto fail;
  1022. }
  1023. Cvar_Get(Cmd_Argv(3), s, 0, NULL);
  1024. }
  1025. else
  1026. Con_Printf("%s\n", s);
  1027. fail:
  1028. ;
  1029. }
  1030. /*
  1031. =============
  1032. PRVM_ED_EdictSet_f
  1033. Console command to set a field of a specified edict
  1034. =============
  1035. */
  1036. static void PRVM_ED_EdictSet_f(void)
  1037. {
  1038. prvm_prog_t *prog;
  1039. prvm_edict_t *ed;
  1040. ddef_t *key;
  1041. if(Cmd_Argc() != 5)
  1042. {
  1043. Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
  1044. return;
  1045. }
  1046. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  1047. return;
  1048. ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
  1049. if((key = PRVM_ED_FindField(prog, Cmd_Argv(3))) == 0)
  1050. Con_Printf("Key %s not found !\n", Cmd_Argv(3));
  1051. else
  1052. PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(4), true);
  1053. }
  1054. /*
  1055. ====================
  1056. PRVM_ED_ParseEdict
  1057. Parses an edict out of the given string, returning the new position
  1058. ed should be a properly initialized empty edict.
  1059. Used for initial level load and for savegames.
  1060. ====================
  1061. */
  1062. const char *PRVM_ED_ParseEdict (prvm_prog_t *prog, const char *data, prvm_edict_t *ent)
  1063. {
  1064. ddef_t *key;
  1065. qboolean anglehack;
  1066. qboolean init;
  1067. char keyname[256];
  1068. size_t n;
  1069. init = false;
  1070. // go through all the dictionary pairs
  1071. while (1)
  1072. {
  1073. // parse key
  1074. if (!COM_ParseToken_Simple(&data, false, false, true))
  1075. prog->error_cmd("PRVM_ED_ParseEdict: EOF without closing brace");
  1076. if (developer_entityparsing.integer)
  1077. Con_Printf("Key: \"%s\"", com_token);
  1078. if (com_token[0] == '}')
  1079. break;
  1080. // anglehack is to allow QuakeEd to write single scalar angles
  1081. // and allow them to be turned into vectors. (FIXME...)
  1082. if (!strcmp(com_token, "angle"))
  1083. {
  1084. strlcpy (com_token, "angles", sizeof(com_token));
  1085. anglehack = true;
  1086. }
  1087. else
  1088. anglehack = false;
  1089. // FIXME: change light to _light to get rid of this hack
  1090. if (!strcmp(com_token, "light"))
  1091. strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def
  1092. strlcpy (keyname, com_token, sizeof(keyname));
  1093. // another hack to fix keynames with trailing spaces
  1094. n = strlen(keyname);
  1095. while (n && keyname[n-1] == ' ')
  1096. {
  1097. keyname[n-1] = 0;
  1098. n--;
  1099. }
  1100. // parse value
  1101. if (!COM_ParseToken_Simple(&data, false, false, true))
  1102. prog->error_cmd("PRVM_ED_ParseEdict: EOF without closing brace");
  1103. if (developer_entityparsing.integer)
  1104. Con_Printf(" \"%s\"\n", com_token);
  1105. if (com_token[0] == '}')
  1106. prog->error_cmd("PRVM_ED_ParseEdict: closing brace without data");
  1107. init = true;
  1108. // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
  1109. if (!keyname[0])
  1110. continue;
  1111. // keynames with a leading underscore are used for utility comments,
  1112. // and are immediately discarded by quake
  1113. if (keyname[0] == '_')
  1114. continue;
  1115. key = PRVM_ED_FindField (prog, keyname);
  1116. if (!key)
  1117. {
  1118. Con_DPrintf("%s: '%s' is not a field\n", prog->name, keyname);
  1119. continue;
  1120. }
  1121. if (anglehack)
  1122. {
  1123. char temp[32];
  1124. strlcpy (temp, com_token, sizeof(temp));
  1125. dpsnprintf (com_token, sizeof(com_token), "0 %s 0", temp);
  1126. }
  1127. if (!PRVM_ED_ParseEpair(prog, ent, key, com_token, strcmp(keyname, "wad") != 0))
  1128. prog->error_cmd("PRVM_ED_ParseEdict: parse error");
  1129. }
  1130. if (!init) {
  1131. ent->priv.required->free = true;
  1132. ent->priv.required->freetime = realtime;
  1133. }
  1134. return data;
  1135. }
  1136. /*
  1137. ================
  1138. PRVM_ED_LoadFromFile
  1139. The entities are directly placed in the array, rather than allocated with
  1140. PRVM_ED_Alloc, because otherwise an error loading the map would have entity
  1141. number references out of order.
  1142. Creates a server's entity / program execution context by
  1143. parsing textual entity definitions out of an ent file.
  1144. Used for both fresh maps and savegame loads. A fresh map would also need
  1145. to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
  1146. ================
  1147. */
  1148. void PRVM_ED_LoadFromFile (prvm_prog_t *prog, const char *data)
  1149. {
  1150. prvm_edict_t *ent;
  1151. int parsed, inhibited, spawned, died;
  1152. const char *funcname;
  1153. mfunction_t *func;
  1154. char vabuf[1024];
  1155. parsed = 0;
  1156. inhibited = 0;
  1157. spawned = 0;
  1158. died = 0;
  1159. prvm_reuseedicts_always_allow = realtime;
  1160. // parse ents
  1161. while (1)
  1162. {
  1163. // parse the opening brace
  1164. if (!COM_ParseToken_Simple(&data, false, false, true))
  1165. break;
  1166. if (com_token[0] != '{')
  1167. prog->error_cmd("PRVM_ED_LoadFromFile: %s: found %s when expecting {", prog->name, com_token);
  1168. // CHANGED: this is not conform to PR_LoadFromFile
  1169. if(prog->loadintoworld)
  1170. {
  1171. prog->loadintoworld = false;
  1172. ent = PRVM_EDICT_NUM(0);
  1173. }
  1174. else
  1175. ent = PRVM_ED_Alloc(prog);
  1176. // clear it
  1177. if (ent != prog->edicts) // hack
  1178. memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
  1179. data = PRVM_ED_ParseEdict (prog, data, ent);
  1180. parsed++;
  1181. // remove the entity ?
  1182. if(!prog->load_edict(prog, ent))
  1183. {
  1184. PRVM_ED_Free(prog, ent);
  1185. inhibited++;
  1186. continue;
  1187. }
  1188. if (PRVM_serverfunction(SV_OnEntityPreSpawnFunction))
  1189. {
  1190. // self = ent
  1191. PRVM_serverglobalfloat(time) = sv.time;
  1192. PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
  1193. prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityPreSpawnFunction), "QC function SV_OnEntityPreSpawnFunction is missing");
  1194. }
  1195. if(ent->priv.required->free)
  1196. {
  1197. inhibited++;
  1198. continue;
  1199. }
  1200. //
  1201. // immediately call spawn function, but only if there is a self global and a classname
  1202. //
  1203. if(!ent->priv.required->free)
  1204. {
  1205. if (!PRVM_alledictstring(ent, classname))
  1206. {
  1207. Con_Print("No classname for:\n");
  1208. PRVM_ED_Print(prog, ent, NULL);
  1209. PRVM_ED_Free (prog, ent);
  1210. continue;
  1211. }
  1212. // look for the spawn function
  1213. funcname = PRVM_GetString(prog, PRVM_alledictstring(ent, classname));
  1214. func = PRVM_ED_FindFunction (prog, va(vabuf, sizeof(vabuf), "spawnfunc_%s", funcname));
  1215. if(!func)
  1216. if(!PRVM_allglobalfloat(require_spawnfunc_prefix))
  1217. func = PRVM_ED_FindFunction (prog, funcname);
  1218. if (!func)
  1219. {
  1220. // check for OnEntityNoSpawnFunction
  1221. if (PRVM_serverfunction(SV_OnEntityNoSpawnFunction))
  1222. {
  1223. // self = ent
  1224. PRVM_serverglobalfloat(time) = sv.time;
  1225. PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
  1226. prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityNoSpawnFunction), "QC function SV_OnEntityNoSpawnFunction is missing");
  1227. }
  1228. else
  1229. {
  1230. if (developer.integer > 0) // don't confuse non-developers with errors
  1231. {
  1232. Con_Print("No spawn function for:\n");
  1233. PRVM_ED_Print(prog, ent, NULL);
  1234. }
  1235. PRVM_ED_Free (prog, ent);
  1236. continue; // not included in "inhibited" count
  1237. }
  1238. }
  1239. else
  1240. {
  1241. // self = ent
  1242. PRVM_serverglobalfloat(time) = sv.time;
  1243. PRVM_allglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
  1244. prog->ExecuteProgram(prog, func - prog->functions, "");
  1245. }
  1246. }
  1247. if(!ent->priv.required->free)
  1248. if (PRVM_serverfunction(SV_OnEntityPostSpawnFunction))
  1249. {
  1250. // self = ent
  1251. PRVM_serverglobalfloat(time) = sv.time;
  1252. PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
  1253. prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityPostSpawnFunction), "QC function SV_OnEntityPostSpawnFunction is missing");
  1254. }
  1255. spawned++;
  1256. if (ent->priv.required->free)
  1257. died++;
  1258. }
  1259. Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", prog->name, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died);
  1260. prvm_reuseedicts_always_allow = 0;
  1261. }
  1262. static void PRVM_FindOffsets(prvm_prog_t *prog)
  1263. {
  1264. // field and global searches use -1 for NULL
  1265. memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
  1266. memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
  1267. // function searches use 0 for NULL
  1268. memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
  1269. #define PRVM_DECLARE_serverglobalfloat(x)
  1270. #define PRVM_DECLARE_serverglobalvector(x)
  1271. #define PRVM_DECLARE_serverglobalstring(x)
  1272. #define PRVM_DECLARE_serverglobaledict(x)
  1273. #define PRVM_DECLARE_serverglobalfunction(x)
  1274. #define PRVM_DECLARE_clientglobalfloat(x)
  1275. #define PRVM_DECLARE_clientglobalvector(x)
  1276. #define PRVM_DECLARE_clientglobalstring(x)
  1277. #define PRVM_DECLARE_clientglobaledict(x)
  1278. #define PRVM_DECLARE_clientglobalfunction(x)
  1279. #define PRVM_DECLARE_menuglobalfloat(x)
  1280. #define PRVM_DECLARE_menuglobalvector(x)
  1281. #define PRVM_DECLARE_menuglobalstring(x)
  1282. #define PRVM_DECLARE_menuglobaledict(x)
  1283. #define PRVM_DECLARE_menuglobalfunction(x)
  1284. #define PRVM_DECLARE_serverfieldfloat(x)
  1285. #define PRVM_DECLARE_serverfieldvector(x)
  1286. #define PRVM_DECLARE_serverfieldstring(x)
  1287. #define PRVM_DECLARE_serverfieldedict(x)
  1288. #define PRVM_DECLARE_serverfieldfunction(x)
  1289. #define PRVM_DECLARE_clientfieldfloat(x)
  1290. #define PRVM_DECLARE_clientfieldvector(x)
  1291. #define PRVM_DECLARE_clientfieldstring(x)
  1292. #define PRVM_DECLARE_clientfieldedict(x)
  1293. #define PRVM_DECLARE_clientfieldfunction(x)
  1294. #define PRVM_DECLARE_menufieldfloat(x)
  1295. #define PRVM_DECLARE_menufieldvector(x)
  1296. #define PRVM_DECLARE_menufieldstring(x)
  1297. #define PRVM_DECLARE_menufieldedict(x)
  1298. #define PRVM_DECLARE_menufieldfunction(x)
  1299. #define PRVM_DECLARE_serverfunction(x)
  1300. #define PRVM_DECLARE_clientfunction(x)
  1301. #define PRVM_DECLARE_menufunction(x)
  1302. #define PRVM_DECLARE_field(x) prog->fieldoffsets.x = PRVM_ED_FindFieldOffset(prog, #x);
  1303. #define PRVM_DECLARE_global(x) prog->globaloffsets.x = PRVM_ED_FindGlobalOffset(prog, #x);
  1304. #define PRVM_DECLARE_function(x) prog->funcoffsets.x = PRVM_ED_FindFunctionOffset(prog, #x);
  1305. #include "prvm_offsets.h"
  1306. #undef PRVM_DECLARE_serverglobalfloat
  1307. #undef PRVM_DECLARE_serverglobalvector
  1308. #undef PRVM_DECLARE_serverglobalstring
  1309. #undef PRVM_DECLARE_serverglobaledict
  1310. #undef PRVM_DECLARE_serverglobalfunction
  1311. #undef PRVM_DECLARE_clientglobalfloat
  1312. #undef PRVM_DECLARE_clientglobalvector
  1313. #undef PRVM_DECLARE_clientglobalstring
  1314. #undef PRVM_DECLARE_clientglobaledict
  1315. #undef PRVM_DECLARE_clientglobalfunction
  1316. #undef PRVM_DECLARE_menuglobalfloat
  1317. #undef PRVM_DECLARE_menuglobalvector
  1318. #undef PRVM_DECLARE_menuglobalstring
  1319. #undef PRVM_DECLARE_menuglobaledict
  1320. #undef PRVM_DECLARE_menuglobalfunction
  1321. #undef PRVM_DECLARE_serverfieldfloat
  1322. #undef PRVM_DECLARE_serverfieldvector
  1323. #undef PRVM_DECLARE_serverfieldstring
  1324. #undef PRVM_DECLARE_serverfieldedict
  1325. #undef PRVM_DECLARE_serverfieldfunction
  1326. #undef PRVM_DECLARE_clientfieldfloat
  1327. #undef PRVM_DECLARE_clientfieldvector
  1328. #undef PRVM_DECLARE_clientfieldstring
  1329. #undef PRVM_DECLARE_clientfieldedict
  1330. #undef PRVM_DECLARE_clientfieldfunction
  1331. #undef PRVM_DECLARE_menufieldfloat
  1332. #undef PRVM_DECLARE_menufieldvector
  1333. #undef PRVM_DECLARE_menufieldstring
  1334. #undef PRVM_DECLARE_menufieldedict
  1335. #undef PRVM_DECLARE_menufieldfunction
  1336. #undef PRVM_DECLARE_serverfunction
  1337. #undef PRVM_DECLARE_clientfunction
  1338. #undef PRVM_DECLARE_menufunction
  1339. #undef PRVM_DECLARE_field
  1340. #undef PRVM_DECLARE_global
  1341. #undef PRVM_DECLARE_function
  1342. }
  1343. // not used
  1344. /*
  1345. typedef struct dpfield_s
  1346. {
  1347. int type;
  1348. char *string;
  1349. }
  1350. dpfield_t;
  1351. #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
  1352. dpfield_t dpfields[] =
  1353. {
  1354. };
  1355. */
  1356. /*
  1357. ===============
  1358. PRVM_ResetProg
  1359. ===============
  1360. */
  1361. #define PO_HASHSIZE 16384
  1362. typedef struct po_string_s
  1363. {
  1364. char *key, *value;
  1365. struct po_string_s *nextonhashchain;
  1366. }
  1367. po_string_t;
  1368. typedef struct po_s
  1369. {
  1370. po_string_t *hashtable[PO_HASHSIZE];
  1371. }
  1372. po_t;
  1373. static void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize)
  1374. {
  1375. for(;;)
  1376. {
  1377. switch(*in)
  1378. {
  1379. case 0:
  1380. *out++ = 0;
  1381. return;
  1382. case '\a': if(outsize >= 2) { *out++ = '\\'; *out++ = 'a'; outsize -= 2; } break;
  1383. case '\b': if(outsize >= 2) { *out++ = '\\'; *out++ = 'b'; outsize -= 2; } break;
  1384. case '\t': if(outsize >= 2) { *out++ = '\\'; *out++ = 't'; outsize -= 2; } break;
  1385. case '\r': if(outsize >= 2) { *out++ = '\\'; *out++ = 'r'; outsize -= 2; } break;
  1386. case '\n': if(outsize >= 2) { *out++ = '\\'; *out++ = 'n'; outsize -= 2; } break;
  1387. case '\\': if(outsize >= 2) { *out++ = '\\'; *out++ = '\\'; outsize -= 2; } break;
  1388. case '"': if(outsize >= 2) { *out++ = '\\'; *out++ = '"'; outsize -= 2; } break;
  1389. default:
  1390. if(*in >= 0 && *in <= 0x1F)
  1391. {
  1392. if(outsize >= 4)
  1393. {
  1394. *out++ = '\\';
  1395. *out++ = '0' + ((*in & 0700) >> 6);
  1396. *out++ = '0' + ((*in & 0070) >> 3);
  1397. *out++ = '0' + (*in & 0007) ;
  1398. outsize -= 4;
  1399. }
  1400. }
  1401. else
  1402. {
  1403. if(outsize >= 1)
  1404. {
  1405. *out++ = *in;
  1406. outsize -= 1;
  1407. }
  1408. }
  1409. break;
  1410. }
  1411. ++in;
  1412. }
  1413. }
  1414. static void PRVM_PO_ParseString(char *out, const char *in, size_t outsize)
  1415. {
  1416. for(;;)
  1417. {
  1418. switch(*in)
  1419. {
  1420. case 0:
  1421. *out++ = 0;
  1422. return;
  1423. case '\\':
  1424. ++in;
  1425. switch(*in)
  1426. {
  1427. case 'a': if(outsize > 0) { *out++ = '\a'; --outsize; } break;
  1428. case 'b': if(outsize > 0) { *out++ = '\b'; --outsize; } break;
  1429. case 't': if(outsize > 0) { *out++ = '\t'; --outsize; } break;
  1430. case 'r': if(outsize > 0) { *out++ = '\r'; --outsize; } break;
  1431. case 'n': if(outsize > 0) { *out++ = '\n'; --outsize; } break;
  1432. case '\\': if(outsize > 0) { *out++ = '\\'; --outsize; } break;
  1433. case '"': if(outsize > 0) { *out++ = '"'; --outsize; } break;
  1434. case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
  1435. if(outsize > 0)
  1436. *out = *in - '0';
  1437. ++in;
  1438. if(*in >= '0' && *in <= '7')
  1439. {
  1440. if(outsize > 0)
  1441. *out = (*out << 3) | (*in - '0');
  1442. ++in;
  1443. }
  1444. if(*in >= '0' && *in <= '7')
  1445. {
  1446. if(outsize > 0)
  1447. *out = (*out << 3) | (*in - '0');
  1448. ++in;
  1449. }
  1450. --in;
  1451. if(outsize > 0)
  1452. {
  1453. ++out;
  1454. --outsize;
  1455. }
  1456. break;
  1457. default:
  1458. if(outsize > 0) { *out++ = *in; --outsize; }
  1459. break;
  1460. }
  1461. break;
  1462. default:
  1463. if(outsize > 0)
  1464. {
  1465. *out++ = *in;
  1466. --outsize;
  1467. }
  1468. break;
  1469. }
  1470. ++in;
  1471. }
  1472. }
  1473. static po_t *PRVM_PO_Load(const char *filename, const char *filename2, mempool_t *pool)
  1474. {
  1475. po_t *po = NULL;
  1476. const char *p, *q;
  1477. int mode;
  1478. char inbuf[MAX_INPUTLINE];
  1479. char decodedbuf[MAX_INPUTLINE];
  1480. size_t decodedpos;
  1481. int hashindex;
  1482. po_string_t thisstr;
  1483. int i;
  1484. for (i = 0; i < 2; ++i)
  1485. {
  1486. const char *buf = (const char *)
  1487. FS_LoadFile((i > 0 ? filename : filename2), pool, true, NULL);
  1488. // first read filename2, then read filename
  1489. // so that progs.dat.de.po wins over common.de.po
  1490. // and within file, last item wins
  1491. if(!buf)
  1492. continue;
  1493. if (!po)
  1494. {
  1495. po = (po_t *)Mem_Alloc(pool, sizeof(*po));
  1496. memset(po, 0, sizeof(*po));
  1497. }
  1498. memset(&thisstr, 0, sizeof(thisstr)); // hush compiler warning
  1499. p = buf;
  1500. while(*p)
  1501. {
  1502. if(*p == '#')
  1503. {
  1504. // skip to newline
  1505. p = strchr(p, '\n');
  1506. if(!p)
  1507. break;
  1508. ++p;
  1509. continue;
  1510. }
  1511. if(*p == '\r' || *p == '\n')
  1512. {
  1513. ++p;
  1514. continue;
  1515. }
  1516. if(!strncmp(p, "msgid \"", 7))
  1517. {
  1518. mode = 0;
  1519. p += 6;
  1520. }
  1521. else if(!strncmp(p, "msgstr \"", 8))
  1522. {
  1523. mode = 1;
  1524. p += 7;
  1525. }
  1526. else
  1527. {
  1528. p = strchr(p, '\n');
  1529. if(!p)
  1530. break;
  1531. ++p;
  1532. continue;
  1533. }
  1534. decodedpos = 0;
  1535. while(*p == '"')
  1536. {
  1537. ++p;
  1538. q = strchr(p, '\n');
  1539. if(!q)
  1540. break;
  1541. if(*(q-1) == '\r')
  1542. --q;
  1543. if(*(q-1) != '"')
  1544. break;
  1545. if((size_t)(q - p) >= (size_t) sizeof(inbuf))
  1546. break;
  1547. strlcpy(inbuf, p, q - p); // not - 1, because this adds a NUL
  1548. PRVM_PO_ParseString(decodedbuf + decodedpos, inbuf, sizeof(decodedbuf) - decodedpos);
  1549. decodedpos += strlen(decodedbuf + decodedpos);
  1550. if(*q == '\r')
  1551. ++q;
  1552. if(*q == '\n')
  1553. ++q;
  1554. p = q;
  1555. }
  1556. if(mode == 0)
  1557. {
  1558. if(thisstr.key)
  1559. Mem_Free(thisstr.key);
  1560. thisstr.key = (char *)Mem_Alloc(pool, decodedpos + 1);
  1561. memcpy(thisstr.key, decodedbuf, decodedpos + 1);
  1562. }
  1563. else if(decodedpos > 0 && thisstr.key) // skip empty translation results
  1564. {
  1565. thisstr.value = (char *)Mem_Alloc(pool, decodedpos + 1);
  1566. memcpy(thisstr.value, decodedbuf, decodedpos + 1);
  1567. hashindex = CRC_Block((const unsigned char *) thisstr.key, strlen(thisstr.key)) % PO_HASHSIZE;
  1568. thisstr.nextonhashchain = po->hashtable[hashindex];
  1569. po->hashtable[hashindex] = (po_string_t *)Mem_Alloc(pool, sizeof(thisstr));
  1570. memcpy(po->hashtable[hashindex], &thisstr, sizeof(thisstr));
  1571. memset(&thisstr, 0, sizeof(thisstr));
  1572. }
  1573. }
  1574. Mem_Free((char *) buf);
  1575. }
  1576. return po;
  1577. }
  1578. static const char *PRVM_PO_Lookup(po_t *po, const char *str)
  1579. {
  1580. int hashindex = CRC_Block((const unsigned char *) str, strlen(str)) % PO_HASHSIZE;
  1581. po_string_t *p = po->hashtable[hashindex];
  1582. while(p)
  1583. {
  1584. if(!strcmp(str, p->key))
  1585. return p->value;
  1586. p = p->nextonhashchain;
  1587. }
  1588. return NULL;
  1589. }
  1590. static void PRVM_PO_Destroy(po_t *po)
  1591. {
  1592. int i;
  1593. for(i = 0; i < PO_HASHSIZE; ++i)
  1594. {
  1595. po_string_t *p = po->hashtable[i];
  1596. while(p)
  1597. {
  1598. po_string_t *q = p;
  1599. p = p->nextonhashchain;
  1600. Mem_Free(q->key);
  1601. Mem_Free(q->value);
  1602. Mem_Free(q);
  1603. }
  1604. }
  1605. Mem_Free(po);
  1606. }
  1607. void PRVM_LeakTest(prvm_prog_t *prog);
  1608. void PRVM_Prog_Reset(prvm_prog_t *prog)
  1609. {
  1610. if (prog->loaded)
  1611. {
  1612. PRVM_LeakTest(prog);
  1613. prog->reset_cmd(prog);
  1614. Mem_FreePool(&prog->progs_mempool);
  1615. if(prog->po)
  1616. PRVM_PO_Destroy((po_t *) prog->po);
  1617. }
  1618. memset(prog,0,sizeof(prvm_prog_t));
  1619. prog->break_statement = -1;
  1620. prog->watch_global_type = ev_void;
  1621. prog->watch_field_type = ev_void;
  1622. }
  1623. /*
  1624. ===============
  1625. PRVM_LoadLNO
  1626. ===============
  1627. */
  1628. static void PRVM_LoadLNO( prvm_prog_t *prog, const char *progname ) {
  1629. fs_offset_t filesize;
  1630. unsigned char *lno;
  1631. unsigned int *header;
  1632. char filename[512];
  1633. FS_StripExtension( progname, filename, sizeof( filename ) );
  1634. strlcat( filename, ".lno", sizeof( filename ) );
  1635. lno = FS_LoadFile( filename, tempmempool, false, &filesize );
  1636. if( !lno ) {
  1637. return;
  1638. }
  1639. /*
  1640. <Spike> SafeWrite (h, &lnotype, sizeof(int));
  1641. <Spike> SafeWrite (h, &version, sizeof(int));
  1642. <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
  1643. <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
  1644. <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
  1645. <Spike> SafeWrite (h, &numstatements, sizeof(int));
  1646. <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
  1647. */
  1648. if ((unsigned int)filesize < (6 + prog->progs_numstatements) * sizeof(int))
  1649. {
  1650. Mem_Free(lno);
  1651. return;
  1652. }
  1653. header = (unsigned int *) lno;
  1654. if( header[ 0 ] == *(unsigned int *) "LNOF" &&
  1655. LittleLong( header[ 1 ] ) == 1 &&
  1656. (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs_numglobaldefs &&
  1657. (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs_numglobals &&
  1658. (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs_numfielddefs &&
  1659. (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs_numstatements )
  1660. {
  1661. prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof( int ) );
  1662. memcpy( prog->statement_linenums, header + 6, prog->progs_numstatements * sizeof( int ) );
  1663. /* gmqcc suports columnums */
  1664. if ((unsigned int)filesize > ((6 + 2 * prog->progs_numstatements) * sizeof( int )))
  1665. {
  1666. prog->statement_columnnums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof( int ) );
  1667. memcpy( prog->statement_columnnums, header + 6 + prog->progs_numstatements, prog->progs_numstatements * sizeof( int ) );
  1668. }
  1669. }
  1670. Mem_Free( lno );
  1671. }
  1672. /*
  1673. ===============
  1674. PRVM_LoadProgs
  1675. ===============
  1676. */
  1677. static void PRVM_UpdateBreakpoints(prvm_prog_t *prog);
  1678. void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * data, fs_offset_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global)
  1679. {
  1680. int i;
  1681. dprograms_t *dprograms;
  1682. dstatement_t *instatements;
  1683. ddef_t *infielddefs;
  1684. ddef_t *inglobaldefs;
  1685. int *inglobals;
  1686. dfunction_t *infunctions;
  1687. char *instrings;
  1688. fs_offset_t filesize;
  1689. int requiredglobalspace;
  1690. opcode_t op;
  1691. int a;
  1692. int b;
  1693. int c;
  1694. union
  1695. {
  1696. unsigned int i;
  1697. float f;
  1698. }
  1699. u;
  1700. unsigned int d;
  1701. char vabuf[1024];
  1702. char vabuf2[1024];
  1703. cvar_t *cvar;
  1704. if (prog->loaded)
  1705. prog->error_cmd("PRVM_LoadProgs: there is already a %s program loaded!", prog->name );
  1706. Host_LockSession(); // all progs can use the session cvar
  1707. Crypto_LoadKeys(); // all progs might use the keys at init time
  1708. if (data)
  1709. {
  1710. dprograms = (dprograms_t *) data;
  1711. filesize = size;
  1712. }
  1713. else
  1714. dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
  1715. if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
  1716. prog->error_cmd("PRVM_LoadProgs: couldn't load %s for %s", filename, prog->name);
  1717. // TODO bounds check header fields (e.g. numstatements), they must never go behind end of file
  1718. prog->profiletime = Sys_DirtyTime();
  1719. prog->starttime = realtime;
  1720. Con_DPrintf("%s programs occupy %iK.\n", prog->name, (int)(filesize/1024));
  1721. requiredglobalspace = 0;
  1722. for (i = 0;i < numrequiredglobals;i++)
  1723. requiredglobalspace += required_global[i].type == ev_vector ? 3 : 1;
  1724. prog->filecrc = CRC_Block((unsigned char *)dprograms, filesize);
  1725. // byte swap the header
  1726. prog->progs_version = LittleLong(dprograms->version);
  1727. prog->progs_crc = LittleLong(dprograms->crc);
  1728. if (prog->progs_version != PROG_VERSION)
  1729. prog->error_cmd("%s: %s has wrong version number (%i should be %i)", prog->name, filename, prog->progs_version, PROG_VERSION);
  1730. instatements = (dstatement_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_statements));
  1731. prog->progs_numstatements = LittleLong(dprograms->numstatements);
  1732. inglobaldefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globaldefs));
  1733. prog->progs_numglobaldefs = LittleLong(dprograms->numglobaldefs);
  1734. infielddefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_fielddefs));
  1735. prog->progs_numfielddefs = LittleLong(dprograms->numfielddefs);
  1736. infunctions = (dfunction_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_functions));
  1737. prog->progs_numfunctions = LittleLong(dprograms->numfunctions);
  1738. instrings = (char *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_strings));
  1739. prog->progs_numstrings = LittleLong(dprograms->numstrings);
  1740. inglobals = (int *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals));
  1741. prog->progs_numglobals = LittleLong(dprograms->numglobals);
  1742. prog->progs_entityfields = LittleLong(dprograms->entityfields);
  1743. prog->numstatements = prog->progs_numstatements;
  1744. prog->numglobaldefs = prog->progs_numglobaldefs;
  1745. prog->numfielddefs = prog->progs_numfielddefs;
  1746. prog->numfunctions = prog->progs_numfunctions;
  1747. prog->numstrings = prog->progs_numstrings;
  1748. prog->numglobals = prog->progs_numglobals;
  1749. prog->entityfields = prog->progs_entityfields;
  1750. if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings > (int)filesize)
  1751. prog->error_cmd("%s: %s strings go past end of file", prog->name, filename);
  1752. prog->strings = (char *)Mem_Alloc(prog->progs_mempool, prog->progs_numstrings);
  1753. memcpy(prog->strings, instrings, prog->progs_numstrings);
  1754. prog->stringssize = prog->progs_numstrings;
  1755. prog->numknownstrings = 0;
  1756. prog->maxknownstrings = 0;
  1757. prog->knownstrings = NULL;
  1758. prog->knownstrings_freeable = NULL;
  1759. Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
  1760. // we need to expand the globaldefs and fielddefs to include engine defs
  1761. prog->globaldefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobaldefs + numrequiredglobals) * sizeof(ddef_t));
  1762. prog->globals.fp = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace + 2) * sizeof(prvm_vec_t));
  1763. // + 2 is because of an otherwise occurring overrun in RETURN instruction
  1764. // when trying to return the last or second-last global
  1765. // (RETURN always returns a vector, there is no RETURN_F instruction)
  1766. prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numfielddefs + numrequiredfields) * sizeof(ddef_t));
  1767. // we need to convert the statements to our memory format
  1768. prog->statements = (mstatement_t *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(mstatement_t));
  1769. // allocate space for profiling statement usage
  1770. prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
  1771. prog->explicit_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
  1772. // functions need to be converted to the memory format
  1773. prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs_numfunctions);
  1774. for (i = 0;i < prog->progs_numfunctions;i++)
  1775. {
  1776. prog->functions[i].first_statement = LittleLong(infunctions[i].first_statement);
  1777. prog->functions[i].parm_start = LittleLong(infunctions[i].parm_start);
  1778. prog->functions[i].s_name = LittleLong(infunctions[i].s_name);
  1779. prog->functions[i].s_file = LittleLong(infunctions[i].s_file);
  1780. prog->functions[i].numparms = LittleLong(infunctions[i].numparms);
  1781. prog->functions[i].locals = LittleLong(infunctions[i].locals);
  1782. memcpy(prog->functions[i].parm_size, infunctions[i].parm_size, sizeof(infunctions[i].parm_size));
  1783. if(prog->functions[i].first_statement >= prog->numstatements)
  1784. prog->error_cmd("PRVM_LoadProgs: out of bounds function statement (function %d) in %s", i, prog->name);
  1785. // TODO bounds check parm_start, s_name, s_file, numparms, locals, parm_size
  1786. }
  1787. // copy the globaldefs to the new globaldefs list
  1788. for (i=0 ; i<prog->numglobaldefs ; i++)
  1789. {
  1790. prog->globaldefs[i].type = LittleShort(inglobaldefs[i].type);
  1791. prog->globaldefs[i].ofs = LittleShort(inglobaldefs[i].ofs);
  1792. prog->globaldefs[i].s_name = LittleLong(inglobaldefs[i].s_name);
  1793. // TODO bounds check ofs, s_name
  1794. }
  1795. // append the required globals
  1796. for (i = 0;i < numrequiredglobals;i++)
  1797. {
  1798. prog->globaldefs[prog->numglobaldefs].type = required_global[i].type;
  1799. prog->globaldefs[prog->numglobaldefs].ofs = prog->numglobals;
  1800. prog->globaldefs[prog->numglobaldefs].s_name = PRVM_SetEngineString(prog, required_global[i].name);
  1801. if (prog->globaldefs[prog->numglobaldefs].type == ev_vector)
  1802. prog->numglobals += 3;
  1803. else
  1804. prog->numglobals++;
  1805. prog->numglobaldefs++;
  1806. }
  1807. // copy the progs fields to the new fields list
  1808. for (i = 0;i < prog->numfielddefs;i++)
  1809. {
  1810. prog->fielddefs[i].type = LittleShort(infielddefs[i].type);
  1811. if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
  1812. prog->error_cmd("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", prog->name);
  1813. prog->fielddefs[i].ofs = LittleShort(infielddefs[i].ofs);
  1814. prog->fielddefs[i].s_name = LittleLong(infielddefs[i].s_name);
  1815. // TODO bounds check ofs, s_name
  1816. }
  1817. // append the required fields
  1818. for (i = 0;i < numrequiredfields;i++)
  1819. {
  1820. prog->fielddefs[prog->numfielddefs].type = required_field[i].type;
  1821. prog->fielddefs[prog->numfielddefs].ofs = prog->entityfields;
  1822. prog->fielddefs[prog->numfielddefs].s_name = PRVM_SetEngineString(prog, required_field[i].name);
  1823. if (prog->fielddefs[prog->numfielddefs].type == ev_vector)
  1824. prog->entityfields += 3;
  1825. else
  1826. prog->entityfields++;
  1827. prog->numfielddefs++;
  1828. }
  1829. // LordHavoc: TODO: reorder globals to match engine struct
  1830. // LordHavoc: TODO: reorder fields to match engine struct
  1831. #define remapglobal(index) (index)
  1832. #define remapfield(index) (index)
  1833. // copy globals
  1834. // FIXME: LordHavoc: this uses a crude way to identify integer constants, rather than checking for matching globaldefs and checking their type
  1835. for (i = 0;i < prog->progs_numglobals;i++)
  1836. {
  1837. u.i = LittleLong(inglobals[i]);
  1838. // most globals are 0, we only need to deal with the ones that are not
  1839. if (u.i)
  1840. {
  1841. d = u.i & 0xFF800000;
  1842. if ((d == 0xFF800000) || (d == 0))
  1843. {
  1844. // Looks like an integer (expand to int64)
  1845. prog->globals.ip[remapglobal(i)] = u.i;
  1846. }
  1847. else
  1848. {
  1849. // Looks like a float (expand to double)
  1850. prog->globals.fp[remapglobal(i)] = u.f;
  1851. }
  1852. }
  1853. }
  1854. // LordHavoc: TODO: support 32bit progs statement formats
  1855. // copy, remap globals in statements, bounds check
  1856. for (i = 0;i < prog->progs_numstatements;i++)
  1857. {
  1858. op = (opcode_t)LittleShort(instatements[i].op);
  1859. a = (unsigned short)LittleShort(instatements[i].a);
  1860. b = (unsigned short)LittleShort(instatements[i].b);
  1861. c = (unsigned short)LittleShort(instatements[i].c);
  1862. switch (op)
  1863. {
  1864. case OP_IF:
  1865. case OP_IFNOT:
  1866. b = (short)b;
  1867. if (a >= prog->progs_numglobals || b + i < 0 || b + i >= prog->progs_numstatements)
  1868. prog->error_cmd("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, prog->name);
  1869. prog->statements[i].op = op;
  1870. prog->statements[i].operand[0] = remapglobal(a);
  1871. prog->statements[i].operand[1] = -1;
  1872. prog->statements[i].operand[2] = -1;
  1873. prog->statements[i].jumpabsolute = i + b;
  1874. break;
  1875. case OP_GOTO:
  1876. a = (short)a;
  1877. if (a + i < 0 || a + i >= prog->progs_numstatements)
  1878. prog->error_cmd("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, prog->name);
  1879. prog->statements[i].op = op;
  1880. prog->statements[i].operand[0] = -1;
  1881. prog->statements[i].operand[1] = -1;
  1882. prog->statements[i].operand[2] = -1;
  1883. prog->statements[i].jumpabsolute = i + a;
  1884. break;
  1885. default:
  1886. Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", (int)op, i, prog->name);
  1887. break;
  1888. // global global global
  1889. case OP_ADD_F:
  1890. case OP_ADD_V:
  1891. case OP_SUB_F:
  1892. case OP_SUB_V:
  1893. case OP_MUL_F:
  1894. case OP_MUL_V:
  1895. case OP_MUL_FV:
  1896. case OP_MUL_VF:
  1897. case OP_DIV_F:
  1898. case OP_BITAND:
  1899. case OP_BITOR:
  1900. case OP_GE:
  1901. case OP_LE:
  1902. case OP_GT:
  1903. case OP_LT:
  1904. case OP_AND:
  1905. case OP_OR:
  1906. case OP_EQ_F:
  1907. case OP_EQ_V:
  1908. case OP_EQ_S:
  1909. case OP_EQ_E:
  1910. case OP_EQ_FNC:
  1911. case OP_NE_F:
  1912. case OP_NE_V:
  1913. case OP_NE_S:
  1914. case OP_NE_E:
  1915. case OP_NE_FNC:
  1916. case OP_ADDRESS:
  1917. case OP_LOAD_F:
  1918. case OP_LOAD_FLD:
  1919. case OP_LOAD_ENT:
  1920. case OP_LOAD_S:
  1921. case OP_LOAD_FNC:
  1922. case OP_LOAD_V:
  1923. if (a >= prog->progs_numglobals || b >= prog->progs_numglobals || c >= prog->progs_numglobals)
  1924. prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
  1925. prog->statements[i].op = op;
  1926. prog->statements[i].operand[0] = remapglobal(a);
  1927. prog->statements[i].operand[1] = remapglobal(b);
  1928. prog->statements[i].operand[2] = remapglobal(c);
  1929. prog->statements[i].jumpabsolute = -1;
  1930. break;
  1931. // global none global
  1932. case OP_NOT_F:
  1933. case OP_NOT_V:
  1934. case OP_NOT_S:
  1935. case OP_NOT_FNC:
  1936. case OP_NOT_ENT:
  1937. if (a >= prog->progs_numglobals || c >= prog->progs_numglobals)
  1938. prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
  1939. prog->statements[i].op = op;
  1940. prog->statements[i].operand[0] = remapglobal(a);
  1941. prog->statements[i].operand[1] = -1;
  1942. prog->statements[i].operand[2] = remapglobal(c);
  1943. prog->statements[i].jumpabsolute = -1;
  1944. break;
  1945. // 2 globals
  1946. case OP_STOREP_F:
  1947. case OP_STOREP_ENT:
  1948. case OP_STOREP_FLD:
  1949. case OP_STOREP_S:
  1950. case OP_STOREP_FNC:
  1951. case OP_STORE_F:
  1952. case OP_STORE_ENT:
  1953. case OP_STORE_FLD:
  1954. case OP_STORE_S:
  1955. case OP_STORE_FNC:
  1956. case OP_STATE:
  1957. case OP_STOREP_V:
  1958. case OP_STORE_V:
  1959. if (a >= prog->progs_numglobals || b >= prog->progs_numglobals)
  1960. prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
  1961. prog->statements[i].op = op;
  1962. prog->statements[i].operand[0] = remapglobal(a);
  1963. prog->statements[i].operand[1] = remapglobal(b);
  1964. prog->statements[i].operand[2] = -1;
  1965. prog->statements[i].jumpabsolute = -1;
  1966. break;
  1967. // 1 global
  1968. case OP_CALL0:
  1969. if ( a < prog->progs_numglobals)
  1970. if ( prog->globals.ip[remapglobal(a)] >= 0 )
  1971. if ( prog->globals.ip[remapglobal(a)] < prog->progs_numfunctions )
  1972. if ( prog->functions[prog->globals.ip[remapglobal(a)]].first_statement == -642 )
  1973. ++prog->numexplicitcoveragestatements;
  1974. case OP_CALL1:
  1975. case OP_CALL2:
  1976. case OP_CALL3:
  1977. case OP_CALL4:
  1978. case OP_CALL5:
  1979. case OP_CALL6:
  1980. case OP_CALL7:
  1981. case OP_CALL8:
  1982. case OP_DONE:
  1983. case OP_RETURN:
  1984. if ( a >= prog->progs_numglobals)
  1985. prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
  1986. prog->statements[i].op = op;
  1987. prog->statements[i].operand[0] = remapglobal(a);
  1988. prog->statements[i].operand[1] = -1;
  1989. prog->statements[i].operand[2] = -1;
  1990. prog->statements[i].jumpabsolute = -1;
  1991. break;
  1992. }
  1993. }
  1994. if(prog->numstatements < 1)
  1995. {
  1996. prog->error_cmd("PRVM_LoadProgs: empty program in %s", prog->name);
  1997. }
  1998. else switch(prog->statements[prog->numstatements - 1].op)
  1999. {
  2000. case OP_RETURN:
  2001. case OP_GOTO:
  2002. case OP_DONE:
  2003. break;
  2004. default:
  2005. prog->error_cmd("PRVM_LoadProgs: program may fall off the edge (does not end with RETURN, GOTO or DONE) in %s", prog->name);
  2006. break;
  2007. }
  2008. // we're done with the file now
  2009. if(!data)
  2010. Mem_Free(dprograms);
  2011. dprograms = NULL;
  2012. // check required functions
  2013. for(i=0 ; i < numrequiredfunc ; i++)
  2014. if(PRVM_ED_FindFunction(prog, required_func[i]) == 0)
  2015. prog->error_cmd("%s: %s not found in %s",prog->name, required_func[i], filename);
  2016. PRVM_LoadLNO(prog, filename);
  2017. PRVM_Init_Exec(prog);
  2018. if(*prvm_language.string)
  2019. // in CSQC we really shouldn't be able to change how stuff works... sorry for now
  2020. // later idea: include a list of authorized .po file checksums with the csprogs
  2021. {
  2022. qboolean deftrans = prog == CLVM_prog;
  2023. const char *realfilename = (prog != CLVM_prog ? filename : csqc_progname.string);
  2024. if(deftrans) // once we have dotranslate_ strings, ALWAYS use the opt-in method!
  2025. {
  2026. for (i=0 ; i<prog->numglobaldefs ; i++)
  2027. {
  2028. const char *name;
  2029. name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
  2030. if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
  2031. if(name && !strncmp(name, "dotranslate_", 12))
  2032. {
  2033. deftrans = false;
  2034. break;
  2035. }
  2036. }
  2037. }
  2038. if(!strcmp(prvm_language.string, "dump"))
  2039. {
  2040. qfile_t *f = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.pot", realfilename), "w", false);
  2041. Con_Printf("Dumping to %s.pot\n", realfilename);
  2042. if(f)
  2043. {
  2044. for (i=0 ; i<prog->numglobaldefs ; i++)
  2045. {
  2046. const char *name;
  2047. name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
  2048. if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12)))
  2049. if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
  2050. {
  2051. prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
  2052. const char *value = PRVM_GetString(prog, val->string);
  2053. if(*value)
  2054. {
  2055. char buf[MAX_INPUTLINE];
  2056. PRVM_PO_UnparseString(buf, value, sizeof(buf));
  2057. FS_Printf(f, "msgid \"%s\"\nmsgstr \"\"\n\n", buf);
  2058. }
  2059. }
  2060. }
  2061. FS_Close(f);
  2062. }
  2063. }
  2064. else
  2065. {
  2066. po_t *po = PRVM_PO_Load(
  2067. va(vabuf, sizeof(vabuf), "%s.%s.po", realfilename, prvm_language.string),
  2068. va(vabuf2, sizeof(vabuf2), "common.%s.po", prvm_language.string),
  2069. prog->progs_mempool);
  2070. if(po)
  2071. {
  2072. for (i=0 ; i<prog->numglobaldefs ; i++)
  2073. {
  2074. const char *name;
  2075. name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
  2076. if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12)))
  2077. if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
  2078. {
  2079. prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
  2080. const char *value = PRVM_GetString(prog, val->string);
  2081. if(*value)
  2082. {
  2083. value = PRVM_PO_Lookup(po, value);
  2084. if(value)
  2085. val->string = PRVM_SetEngineString(prog, value);
  2086. }
  2087. }
  2088. }
  2089. }
  2090. }
  2091. }
  2092. for (cvar = cvar_vars; cvar; cvar = cvar->next)
  2093. cvar->globaldefindex[prog - prvm_prog_list] = -1;
  2094. for (i=0 ; i<prog->numglobaldefs ; i++)
  2095. {
  2096. const char *name;
  2097. name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
  2098. //Con_Printf("found var %s\n", name);
  2099. if(name
  2100. && !strncmp(name, "autocvar_", 9)
  2101. && !(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
  2102. )
  2103. {
  2104. prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
  2105. cvar = Cvar_FindVar(name + 9);
  2106. //Con_Printf("PRVM_LoadProgs: autocvar global %s in %s, processing...\n", name, prog->name);
  2107. if(!cvar)
  2108. {
  2109. const char *value;
  2110. char buf[64];
  2111. Con_DPrintf("PRVM_LoadProgs: no cvar for autocvar global %s in %s, creating...\n", name, prog->name);
  2112. switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL)
  2113. {
  2114. case ev_float:
  2115. if((float)((int)(val->_float)) == val->_float)
  2116. dpsnprintf(buf, sizeof(buf), "%i", (int)(val->_float));
  2117. else
  2118. dpsnprintf(buf, sizeof(buf), "%.9g", val->_float);
  2119. value = buf;
  2120. break;
  2121. case ev_vector:
  2122. dpsnprintf(buf, sizeof(buf), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); value = buf;
  2123. break;
  2124. case ev_string:
  2125. value = PRVM_GetString(prog, val->string);
  2126. break;
  2127. default:
  2128. Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name);
  2129. goto fail;
  2130. }
  2131. cvar = Cvar_Get(name + 9, value, 0, NULL);
  2132. if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
  2133. {
  2134. val->string = PRVM_SetEngineString(prog, cvar->string);
  2135. cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string;
  2136. }
  2137. if(!cvar)
  2138. prog->error_cmd("PRVM_LoadProgs: could not create cvar for autocvar global %s in %s", name, prog->name);
  2139. cvar->globaldefindex[prog - prvm_prog_list] = i;
  2140. }
  2141. else if((cvar->flags & CVAR_PRIVATE) == 0)
  2142. {
  2143. // MUST BE SYNCED WITH cvar.c Cvar_Set
  2144. int j;
  2145. const char *s;
  2146. switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL)
  2147. {
  2148. case ev_float:
  2149. val->_float = cvar->value;
  2150. break;
  2151. case ev_vector:
  2152. s = cvar->string;
  2153. VectorClear(val->vector);
  2154. for (j = 0;j < 3;j++)
  2155. {
  2156. while (*s && ISWHITESPACE(*s))
  2157. s++;
  2158. if (!*s)
  2159. break;
  2160. val->vector[j] = atof(s);
  2161. while (!ISWHITESPACE(*s))
  2162. s++;
  2163. if (!*s)
  2164. break;
  2165. }
  2166. break;
  2167. case ev_string:
  2168. val->string = PRVM_SetEngineString(prog, cvar->string);
  2169. cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string;
  2170. break;
  2171. default:
  2172. Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name);
  2173. goto fail;
  2174. }
  2175. cvar->globaldefindex[prog - prvm_prog_list] = i;
  2176. }
  2177. else
  2178. Con_Printf("PRVM_LoadProgs: private cvar for autocvar global %s in %s\n", name, prog->name);
  2179. }
  2180. fail:
  2181. ;
  2182. }
  2183. prog->loaded = TRUE;
  2184. PRVM_UpdateBreakpoints(prog);
  2185. // set flags & ddef_ts in prog
  2186. prog->flag = 0;
  2187. PRVM_FindOffsets(prog);
  2188. prog->init_cmd(prog);
  2189. // init mempools
  2190. PRVM_MEM_Alloc(prog);
  2191. // Inittime is at least the time when this function finished. However,
  2192. // later events may bump it.
  2193. prog->inittime = realtime;
  2194. }
  2195. static void PRVM_Fields_f (void)
  2196. {
  2197. prvm_prog_t *prog;
  2198. int i, j, ednum, used, usedamount;
  2199. int *counts;
  2200. char tempstring[MAX_INPUTLINE], tempstring2[260];
  2201. const char *name;
  2202. prvm_edict_t *ed;
  2203. ddef_t *d;
  2204. prvm_eval_t *val;
  2205. // TODO
  2206. /*
  2207. if (!sv.active)
  2208. {
  2209. Con_Print("no progs loaded\n");
  2210. return;
  2211. }
  2212. */
  2213. if(Cmd_Argc() != 2)
  2214. {
  2215. Con_Print("prvm_fields <program name>\n");
  2216. return;
  2217. }
  2218. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  2219. return;
  2220. counts = (int *)Mem_Alloc(tempmempool, prog->numfielddefs * sizeof(int));
  2221. for (ednum = 0;ednum < prog->max_edicts;ednum++)
  2222. {
  2223. ed = PRVM_EDICT_NUM(ednum);
  2224. if (ed->priv.required->free)
  2225. continue;
  2226. for (i = 1;i < prog->numfielddefs;i++)
  2227. {
  2228. d = &prog->fielddefs[i];
  2229. name = PRVM_GetString(prog, d->s_name);
  2230. if (name[strlen(name)-2] == '_')
  2231. continue; // skip _x, _y, _z vars
  2232. val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
  2233. // if the value is still all 0, skip the field
  2234. for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
  2235. {
  2236. if (val->ivector[j])
  2237. {
  2238. counts[i]++;
  2239. break;
  2240. }
  2241. }
  2242. }
  2243. }
  2244. used = 0;
  2245. usedamount = 0;
  2246. tempstring[0] = 0;
  2247. for (i = 0;i < prog->numfielddefs;i++)
  2248. {
  2249. d = &prog->fielddefs[i];
  2250. name = PRVM_GetString(prog, d->s_name);
  2251. if (name[strlen(name)-2] == '_')
  2252. continue; // skip _x, _y, _z vars
  2253. switch(d->type & ~DEF_SAVEGLOBAL)
  2254. {
  2255. case ev_string:
  2256. strlcat(tempstring, "string ", sizeof(tempstring));
  2257. break;
  2258. case ev_entity:
  2259. strlcat(tempstring, "entity ", sizeof(tempstring));
  2260. break;
  2261. case ev_function:
  2262. strlcat(tempstring, "function ", sizeof(tempstring));
  2263. break;
  2264. case ev_field:
  2265. strlcat(tempstring, "field ", sizeof(tempstring));
  2266. break;
  2267. case ev_void:
  2268. strlcat(tempstring, "void ", sizeof(tempstring));
  2269. break;
  2270. case ev_float:
  2271. strlcat(tempstring, "float ", sizeof(tempstring));
  2272. break;
  2273. case ev_vector:
  2274. strlcat(tempstring, "vector ", sizeof(tempstring));
  2275. break;
  2276. case ev_pointer:
  2277. strlcat(tempstring, "pointer ", sizeof(tempstring));
  2278. break;
  2279. default:
  2280. dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
  2281. strlcat(tempstring, tempstring2, sizeof(tempstring));
  2282. break;
  2283. }
  2284. if (strlen(name) > sizeof(tempstring2)-4)
  2285. {
  2286. memcpy (tempstring2, name, sizeof(tempstring2)-4);
  2287. tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
  2288. tempstring2[sizeof(tempstring2)-1] = 0;
  2289. name = tempstring2;
  2290. }
  2291. strlcat(tempstring, name, sizeof(tempstring));
  2292. for (j = (int)strlen(name);j < 25;j++)
  2293. strlcat(tempstring, " ", sizeof(tempstring));
  2294. dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]);
  2295. strlcat(tempstring, tempstring2, sizeof(tempstring));
  2296. strlcat(tempstring, "\n", sizeof(tempstring));
  2297. if (strlen(tempstring) >= sizeof(tempstring)/2)
  2298. {
  2299. Con_Print(tempstring);
  2300. tempstring[0] = 0;
  2301. }
  2302. if (counts[i])
  2303. {
  2304. used++;
  2305. usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
  2306. }
  2307. }
  2308. Mem_Free(counts);
  2309. 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", prog->name, prog->entityfields, used, prog->entityfields * 4, usedamount * 4, prog->max_edicts, prog->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts);
  2310. }
  2311. static void PRVM_Globals_f (void)
  2312. {
  2313. prvm_prog_t *prog;
  2314. int i;
  2315. const char *wildcard;
  2316. int numculled;
  2317. numculled = 0;
  2318. // TODO
  2319. /*if (!sv.active)
  2320. {
  2321. Con_Print("no progs loaded\n");
  2322. return;
  2323. }*/
  2324. if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
  2325. {
  2326. Con_Print("prvm_globals <program name> <optional name wildcard>\n");
  2327. return;
  2328. }
  2329. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  2330. return;
  2331. if( Cmd_Argc() == 3)
  2332. wildcard = Cmd_Argv(2);
  2333. else
  2334. wildcard = NULL;
  2335. Con_Printf("%s :", prog->name);
  2336. for (i = 0;i < prog->numglobaldefs;i++)
  2337. {
  2338. if(wildcard)
  2339. if( !matchpattern( PRVM_GetString(prog, prog->globaldefs[i].s_name), wildcard, 1) )
  2340. {
  2341. numculled++;
  2342. continue;
  2343. }
  2344. Con_Printf("%s\n", PRVM_GetString(prog, prog->globaldefs[i].s_name));
  2345. }
  2346. Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->numglobals, numculled, prog->numglobals * 4);
  2347. }
  2348. /*
  2349. ===============
  2350. PRVM_Global
  2351. ===============
  2352. */
  2353. static void PRVM_Global_f(void)
  2354. {
  2355. prvm_prog_t *prog;
  2356. ddef_t *global;
  2357. char valuebuf[MAX_INPUTLINE];
  2358. if( Cmd_Argc() != 3 ) {
  2359. Con_Printf( "prvm_global <program name> <global name>\n" );
  2360. return;
  2361. }
  2362. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  2363. return;
  2364. global = PRVM_ED_FindGlobal( prog, Cmd_Argv(2) );
  2365. if( !global )
  2366. Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
  2367. else
  2368. Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( prog, (etype_t)global->type, PRVM_GLOBALFIELDVALUE(global->ofs), valuebuf, sizeof(valuebuf) ) );
  2369. }
  2370. /*
  2371. ===============
  2372. PRVM_GlobalSet
  2373. ===============
  2374. */
  2375. static void PRVM_GlobalSet_f(void)
  2376. {
  2377. prvm_prog_t *prog;
  2378. ddef_t *global;
  2379. if( Cmd_Argc() != 4 ) {
  2380. Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
  2381. return;
  2382. }
  2383. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  2384. return;
  2385. global = PRVM_ED_FindGlobal( prog, Cmd_Argv(2) );
  2386. if( !global )
  2387. Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
  2388. else
  2389. PRVM_ED_ParseEpair( prog, NULL, global, Cmd_Argv(3), true );
  2390. }
  2391. /*
  2392. ======================
  2393. Break- and Watchpoints
  2394. ======================
  2395. */
  2396. typedef struct
  2397. {
  2398. char break_statement[256];
  2399. char watch_global[256];
  2400. int watch_edict;
  2401. char watch_field[256];
  2402. }
  2403. debug_data_t;
  2404. static debug_data_t debug_data[PRVM_PROG_MAX];
  2405. void PRVM_Breakpoint(prvm_prog_t *prog, int stack_index, const char *text)
  2406. {
  2407. char vabuf[1024];
  2408. Con_Printf("PRVM_Breakpoint: %s\n", text);
  2409. PRVM_PrintState(prog, stack_index);
  2410. if (prvm_breakpointdump.integer)
  2411. Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "breakpoint-%s.dmp", prog->name));
  2412. }
  2413. void PRVM_Watchpoint(prvm_prog_t *prog, int stack_index, const char *text, etype_t type, prvm_eval_t *o, prvm_eval_t *n)
  2414. {
  2415. size_t sz = sizeof(prvm_vec_t) * ((type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
  2416. if (memcmp(o, n, sz))
  2417. {
  2418. char buf[1024];
  2419. char valuebuf_o[128];
  2420. char valuebuf_n[128];
  2421. PRVM_UglyValueString(prog, type, o, valuebuf_o, sizeof(valuebuf_o));
  2422. PRVM_UglyValueString(prog, type, n, valuebuf_n, sizeof(valuebuf_n));
  2423. dpsnprintf(buf, sizeof(buf), "%s: %s -> %s", text, valuebuf_o, valuebuf_n);
  2424. PRVM_Breakpoint(prog, stack_index, buf);
  2425. memcpy(o, n, sz);
  2426. }
  2427. }
  2428. static void PRVM_UpdateBreakpoints(prvm_prog_t *prog)
  2429. {
  2430. debug_data_t *debug = &debug_data[prog - prvm_prog_list];
  2431. if (!prog->loaded)
  2432. return;
  2433. if (debug->break_statement[0])
  2434. {
  2435. if (debug->break_statement[0] >= '0' && debug->break_statement[0] <= '9')
  2436. {
  2437. prog->break_statement = atoi(debug->break_statement);
  2438. prog->break_stack_index = 0;
  2439. }
  2440. else
  2441. {
  2442. mfunction_t *func;
  2443. func = PRVM_ED_FindFunction (prog, debug->break_statement);
  2444. if (!func)
  2445. {
  2446. Con_Printf("%s progs: no function or statement named %s to break on!\n", prog->name, debug->break_statement);
  2447. prog->break_statement = -1;
  2448. }
  2449. else
  2450. {
  2451. prog->break_statement = func->first_statement;
  2452. prog->break_stack_index = 1;
  2453. }
  2454. }
  2455. if (prog->break_statement >= -1)
  2456. Con_Printf("%s progs: breakpoint is at statement %d\n", prog->name, prog->break_statement);
  2457. }
  2458. else
  2459. prog->break_statement = -1;
  2460. if (debug->watch_global[0])
  2461. {
  2462. ddef_t *global = PRVM_ED_FindGlobal( prog, debug->watch_global );
  2463. if( !global )
  2464. {
  2465. Con_Printf( "%s progs: no global named '%s' to watch!\n", prog->name, debug->watch_global );
  2466. prog->watch_global_type = ev_void;
  2467. }
  2468. else
  2469. {
  2470. size_t sz = sizeof(prvm_vec_t) * ((global->type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
  2471. prog->watch_global = global->ofs;
  2472. prog->watch_global_type = (etype_t)global->type;
  2473. memcpy(&prog->watch_global_value, PRVM_GLOBALFIELDVALUE(prog->watch_global), sz);
  2474. }
  2475. if (prog->watch_global_type != ev_void)
  2476. Con_Printf("%s progs: global watchpoint is at global index %d\n", prog->name, prog->watch_global);
  2477. }
  2478. else
  2479. prog->watch_global_type = ev_void;
  2480. if (debug->watch_field[0])
  2481. {
  2482. ddef_t *field = PRVM_ED_FindField( prog, debug->watch_field );
  2483. if( !field )
  2484. {
  2485. Con_Printf( "%s progs: no field named '%s' to watch!\n", prog->name, debug->watch_field );
  2486. prog->watch_field_type = ev_void;
  2487. }
  2488. else
  2489. {
  2490. size_t sz = sizeof(prvm_vec_t) * ((field->type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
  2491. prog->watch_edict = debug->watch_edict;
  2492. prog->watch_field = field->ofs;
  2493. prog->watch_field_type = (etype_t)field->type;
  2494. if (prog->watch_edict < prog->num_edicts)
  2495. memcpy(&prog->watch_edictfield_value, PRVM_EDICTFIELDVALUE(PRVM_EDICT_NUM(prog->watch_edict), prog->watch_field), sz);
  2496. else
  2497. memset(&prog->watch_edictfield_value, 0, sz);
  2498. }
  2499. if (prog->watch_edict != ev_void)
  2500. Con_Printf("%s progs: edict field watchpoint is at edict %d field index %d\n", prog->name, prog->watch_edict, prog->watch_field);
  2501. }
  2502. else
  2503. prog->watch_field_type = ev_void;
  2504. }
  2505. static void PRVM_Breakpoint_f(void)
  2506. {
  2507. prvm_prog_t *prog;
  2508. if( Cmd_Argc() == 2 ) {
  2509. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  2510. return;
  2511. {
  2512. debug_data_t *debug = &debug_data[prog - prvm_prog_list];
  2513. debug->break_statement[0] = 0;
  2514. }
  2515. PRVM_UpdateBreakpoints(prog);
  2516. return;
  2517. }
  2518. if( Cmd_Argc() != 3 ) {
  2519. Con_Printf( "prvm_breakpoint <program name> <function name | statement>\n" );
  2520. return;
  2521. }
  2522. if (!(prog = PRVM_ProgFromString(Cmd_Argv(1))))
  2523. return;
  2524. {
  2525. debug_data_t *debug = &debug_data[prog - prvm_prog_list];
  2526. strlcpy(debug->break_statement, Cmd_Argv(2), sizeof(debug->break_statement));
  2527. }
  2528. PRVM_UpdateBreakpoints(prog);
  2529. }
  2530. static void PRVM_GlobalWatchpoint_f(void)
  2531. {
  2532. prvm_prog_t *prog;
  2533. if( Cmd_Argc() == 2 ) {
  2534. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  2535. return;
  2536. {
  2537. debug_data_t *debug = &debug_data[prog - prvm_prog_list];
  2538. debug->watch_global[0] = 0;
  2539. }
  2540. PRVM_UpdateBreakpoints(prog);
  2541. return;
  2542. }
  2543. if( Cmd_Argc() != 3 ) {
  2544. Con_Printf( "prvm_globalwatchpoint <program name> <global name>\n" );
  2545. return;
  2546. }
  2547. if (!(prog = PRVM_ProgFromString(Cmd_Argv(1))))
  2548. return;
  2549. {
  2550. debug_data_t *debug = &debug_data[prog - prvm_prog_list];
  2551. strlcpy(debug->watch_global, Cmd_Argv(2), sizeof(debug->watch_global));
  2552. }
  2553. PRVM_UpdateBreakpoints(prog);
  2554. }
  2555. static void PRVM_EdictWatchpoint_f(void)
  2556. {
  2557. prvm_prog_t *prog;
  2558. if( Cmd_Argc() == 2 ) {
  2559. if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
  2560. return;
  2561. {
  2562. debug_data_t *debug = &debug_data[prog - prvm_prog_list];
  2563. debug->watch_field[0] = 0;
  2564. }
  2565. PRVM_UpdateBreakpoints(prog);
  2566. return;
  2567. }
  2568. if( Cmd_Argc() != 4 ) {
  2569. Con_Printf( "prvm_edictwatchpoint <program name> <edict number> <field name>\n" );
  2570. return;
  2571. }
  2572. if (!(prog = PRVM_ProgFromString(Cmd_Argv(1))))
  2573. return;
  2574. {
  2575. debug_data_t *debug = &debug_data[prog - prvm_prog_list];
  2576. debug->watch_edict = atoi(Cmd_Argv(2));
  2577. strlcpy(debug->watch_field, Cmd_Argv(3), sizeof(debug->watch_field));
  2578. }
  2579. PRVM_UpdateBreakpoints(prog);
  2580. }
  2581. /*
  2582. ===============
  2583. PRVM_Init
  2584. ===============
  2585. */
  2586. void PRVM_Init (void)
  2587. {
  2588. Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
  2589. Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
  2590. Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
  2591. Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
  2592. Cmd_AddCommand ("prvm_childprofile", PRVM_ChildProfile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu), sorted by time taken in function with child calls");
  2593. 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)");
  2594. 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)");
  2595. Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
  2596. Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
  2597. Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
  2598. 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)");
  2599. Cmd_AddCommand ("prvm_edictget", PRVM_ED_EdictGet_f, "retrieves the value of a specified property of a specified entity in the selected VM (server, client menu) into a cvar or to the console");
  2600. Cmd_AddCommand ("prvm_globalget", PRVM_ED_GlobalGet_f, "retrieves the value of a specified global variable in the selected VM (server, client menu) into a cvar or to the console");
  2601. Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
  2602. Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
  2603. Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
  2604. Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
  2605. Cmd_AddCommand ("prvm_breakpoint", PRVM_Breakpoint_f, "marks a statement or function as breakpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear breakpoint");
  2606. Cmd_AddCommand ("prvm_globalwatchpoint", PRVM_GlobalWatchpoint_f, "marks a global as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint");
  2607. Cmd_AddCommand ("prvm_edictwatchpoint", PRVM_EdictWatchpoint_f, "marks an entity field as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint");
  2608. Cvar_RegisterVariable (&prvm_language);
  2609. Cvar_RegisterVariable (&prvm_traceqc);
  2610. Cvar_RegisterVariable (&prvm_statementprofiling);
  2611. Cvar_RegisterVariable (&prvm_timeprofiling);
  2612. Cvar_RegisterVariable (&prvm_coverage);
  2613. Cvar_RegisterVariable (&prvm_backtraceforwarnings);
  2614. Cvar_RegisterVariable (&prvm_leaktest);
  2615. Cvar_RegisterVariable (&prvm_leaktest_follow_targetname);
  2616. Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames);
  2617. Cvar_RegisterVariable (&prvm_errordump);
  2618. Cvar_RegisterVariable (&prvm_breakpointdump);
  2619. Cvar_RegisterVariable (&prvm_reuseedicts_startuptime);
  2620. Cvar_RegisterVariable (&prvm_reuseedicts_neverinsameframe);
  2621. // COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!)
  2622. prvm_runawaycheck = !COM_CheckParm("-norunaway");
  2623. //VM_Cmd_Init();
  2624. }
  2625. /*
  2626. ===============
  2627. PRVM_InitProg
  2628. ===============
  2629. */
  2630. void PRVM_Prog_Init(prvm_prog_t *prog)
  2631. {
  2632. PRVM_Prog_Reset(prog);
  2633. prog->leaktest_active = prvm_leaktest.integer != 0;
  2634. }
  2635. // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
  2636. unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline)
  2637. {
  2638. prog->error_cmd("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", prog->name, n, filename, fileline);
  2639. return 0;
  2640. }
  2641. #define PRVM_KNOWNSTRINGBASE 0x40000000
  2642. const char *PRVM_GetString(prvm_prog_t *prog, int num)
  2643. {
  2644. if (num < 0)
  2645. {
  2646. // invalid
  2647. VM_Warning(prog, "PRVM_GetString: Invalid string offset (%i < 0)\n", num);
  2648. return "";
  2649. }
  2650. else if (num < prog->stringssize)
  2651. {
  2652. // constant string from progs.dat
  2653. return prog->strings + num;
  2654. }
  2655. else if (num <= prog->stringssize + prog->tempstringsbuf.maxsize)
  2656. {
  2657. // tempstring returned by engine to QC (becomes invalid after returning to engine)
  2658. num -= prog->stringssize;
  2659. if (num < prog->tempstringsbuf.cursize)
  2660. return (char *)prog->tempstringsbuf.data + num;
  2661. else
  2662. {
  2663. VM_Warning(prog, "PRVM_GetString: Invalid temp-string offset (%i >= %i prog->tempstringsbuf.cursize)\n", num, prog->tempstringsbuf.cursize);
  2664. return "";
  2665. }
  2666. }
  2667. else if (num & PRVM_KNOWNSTRINGBASE)
  2668. {
  2669. // allocated string
  2670. num = num - PRVM_KNOWNSTRINGBASE;
  2671. if (num >= 0 && num < prog->numknownstrings)
  2672. {
  2673. if (!prog->knownstrings[num])
  2674. {
  2675. VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
  2676. return "";
  2677. }
  2678. return prog->knownstrings[num];
  2679. }
  2680. else
  2681. {
  2682. VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
  2683. return "";
  2684. }
  2685. }
  2686. else
  2687. {
  2688. // invalid string offset
  2689. VM_Warning(prog, "PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
  2690. return "";
  2691. }
  2692. }
  2693. const char *PRVM_ChangeEngineString(prvm_prog_t *prog, int i, const char *s)
  2694. {
  2695. const char *old;
  2696. i = i - PRVM_KNOWNSTRINGBASE;
  2697. if(i < 0 || i >= prog->numknownstrings)
  2698. prog->error_cmd("PRVM_ChangeEngineString: s is not an engine string");
  2699. old = prog->knownstrings[i];
  2700. prog->knownstrings[i] = s;
  2701. return old;
  2702. }
  2703. int PRVM_SetEngineString(prvm_prog_t *prog, const char *s)
  2704. {
  2705. int i;
  2706. if (!s)
  2707. return 0;
  2708. if (s >= prog->strings && s <= prog->strings + prog->stringssize)
  2709. prog->error_cmd("PRVM_SetEngineString: s in prog->strings area");
  2710. // if it's in the tempstrings area, use a reserved range
  2711. // (otherwise we'd get millions of useless string offsets cluttering the database)
  2712. if (s >= (char *)prog->tempstringsbuf.data && s < (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.maxsize)
  2713. return prog->stringssize + (s - (char *)prog->tempstringsbuf.data);
  2714. // see if it's a known string address
  2715. for (i = 0;i < prog->numknownstrings;i++)
  2716. if (prog->knownstrings[i] == s)
  2717. return PRVM_KNOWNSTRINGBASE + i;
  2718. // new unknown engine string
  2719. if (developer_insane.integer)
  2720. Con_DPrintf("new engine string %p = \"%s\"\n", s, s);
  2721. for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
  2722. if (!prog->knownstrings[i])
  2723. break;
  2724. if (i >= prog->numknownstrings)
  2725. {
  2726. if (i >= prog->maxknownstrings)
  2727. {
  2728. const char **oldstrings = prog->knownstrings;
  2729. const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
  2730. const char **oldstrings_origin = prog->knownstrings_origin;
  2731. prog->maxknownstrings += 128;
  2732. prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
  2733. prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
  2734. if(prog->leaktest_active)
  2735. prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
  2736. if (prog->numknownstrings)
  2737. {
  2738. memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
  2739. memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
  2740. if(prog->leaktest_active)
  2741. memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
  2742. }
  2743. }
  2744. prog->numknownstrings++;
  2745. }
  2746. prog->firstfreeknownstring = i + 1;
  2747. prog->knownstrings[i] = s;
  2748. prog->knownstrings_freeable[i] = false;
  2749. if(prog->leaktest_active)
  2750. prog->knownstrings_origin[i] = NULL;
  2751. return PRVM_KNOWNSTRINGBASE + i;
  2752. }
  2753. // temp string handling
  2754. // all tempstrings go into this buffer consecutively, and it is reset
  2755. // whenever PRVM_ExecuteProgram returns to the engine
  2756. // (technically each PRVM_ExecuteProgram call saves the cursize value and
  2757. // restores it on return, so multiple recursive calls can share the same
  2758. // buffer)
  2759. // the buffer size is automatically grown as needed
  2760. int PRVM_SetTempString(prvm_prog_t *prog, const char *s)
  2761. {
  2762. int size;
  2763. char *t;
  2764. if (!s)
  2765. return 0;
  2766. size = (int)strlen(s) + 1;
  2767. if (developer_insane.integer)
  2768. Con_DPrintf("PRVM_SetTempString: cursize %i, size %i\n", prog->tempstringsbuf.cursize, size);
  2769. if (prog->tempstringsbuf.maxsize < prog->tempstringsbuf.cursize + size)
  2770. {
  2771. sizebuf_t old = prog->tempstringsbuf;
  2772. if (prog->tempstringsbuf.cursize + size >= 1<<28)
  2773. prog->error_cmd("PRVM_SetTempString: ran out of tempstring memory! (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", prog->tempstringsbuf.cursize, size);
  2774. prog->tempstringsbuf.maxsize = max(prog->tempstringsbuf.maxsize, 65536);
  2775. while (prog->tempstringsbuf.maxsize < prog->tempstringsbuf.cursize + size)
  2776. prog->tempstringsbuf.maxsize *= 2;
  2777. if (prog->tempstringsbuf.maxsize != old.maxsize || prog->tempstringsbuf.data == NULL)
  2778. {
  2779. Con_DPrintf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, prog->tempstringsbuf.maxsize/1024);
  2780. prog->tempstringsbuf.data = (unsigned char *) Mem_Alloc(prog->progs_mempool, prog->tempstringsbuf.maxsize);
  2781. if (old.data)
  2782. {
  2783. if (old.cursize)
  2784. memcpy(prog->tempstringsbuf.data, old.data, old.cursize);
  2785. Mem_Free(old.data);
  2786. }
  2787. }
  2788. }
  2789. t = (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.cursize;
  2790. memcpy(t, s, size);
  2791. prog->tempstringsbuf.cursize += size;
  2792. return PRVM_SetEngineString(prog, t);
  2793. }
  2794. int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer)
  2795. {
  2796. int i;
  2797. if (!bufferlength)
  2798. {
  2799. if (pointer)
  2800. *pointer = NULL;
  2801. return 0;
  2802. }
  2803. for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
  2804. if (!prog->knownstrings[i])
  2805. break;
  2806. if (i >= prog->numknownstrings)
  2807. {
  2808. if (i >= prog->maxknownstrings)
  2809. {
  2810. const char **oldstrings = prog->knownstrings;
  2811. const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
  2812. const char **oldstrings_origin = prog->knownstrings_origin;
  2813. prog->maxknownstrings += 128;
  2814. prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
  2815. prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
  2816. if(prog->leaktest_active)
  2817. prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
  2818. if (prog->numknownstrings)
  2819. {
  2820. memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
  2821. memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
  2822. if(prog->leaktest_active)
  2823. memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
  2824. }
  2825. if (oldstrings)
  2826. Mem_Free((char **)oldstrings);
  2827. if (oldstrings_freeable)
  2828. Mem_Free((unsigned char *)oldstrings_freeable);
  2829. if (oldstrings_origin)
  2830. Mem_Free((char **)oldstrings_origin);
  2831. }
  2832. prog->numknownstrings++;
  2833. }
  2834. prog->firstfreeknownstring = i + 1;
  2835. prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
  2836. prog->knownstrings_freeable[i] = true;
  2837. if(prog->leaktest_active)
  2838. prog->knownstrings_origin[i] = PRVM_AllocationOrigin(prog);
  2839. if (pointer)
  2840. *pointer = (char *)(prog->knownstrings[i]);
  2841. return PRVM_KNOWNSTRINGBASE + i;
  2842. }
  2843. void PRVM_FreeString(prvm_prog_t *prog, int num)
  2844. {
  2845. if (num == 0)
  2846. prog->error_cmd("PRVM_FreeString: attempt to free a NULL string");
  2847. else if (num >= 0 && num < prog->stringssize)
  2848. prog->error_cmd("PRVM_FreeString: attempt to free a constant string");
  2849. else if (num >= PRVM_KNOWNSTRINGBASE && num < PRVM_KNOWNSTRINGBASE + prog->numknownstrings)
  2850. {
  2851. num = num - PRVM_KNOWNSTRINGBASE;
  2852. if (!prog->knownstrings[num])
  2853. prog->error_cmd("PRVM_FreeString: attempt to free a non-existent or already freed string");
  2854. if (!prog->knownstrings_freeable[num])
  2855. prog->error_cmd("PRVM_FreeString: attempt to free a string owned by the engine");
  2856. PRVM_Free((char *)prog->knownstrings[num]);
  2857. if(prog->leaktest_active)
  2858. if(prog->knownstrings_origin[num])
  2859. PRVM_Free((char *)prog->knownstrings_origin[num]);
  2860. prog->knownstrings[num] = NULL;
  2861. prog->knownstrings_freeable[num] = false;
  2862. prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
  2863. }
  2864. else
  2865. prog->error_cmd("PRVM_FreeString: invalid string offset %i", num);
  2866. }
  2867. static qboolean PRVM_IsStringReferenced(prvm_prog_t *prog, string_t string)
  2868. {
  2869. int i, j;
  2870. for (i = 0;i < prog->numglobaldefs;i++)
  2871. {
  2872. ddef_t *d = &prog->globaldefs[i];
  2873. if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
  2874. continue;
  2875. if(string == PRVM_GLOBALFIELDSTRING(d->ofs))
  2876. return true;
  2877. }
  2878. for(j = 0; j < prog->num_edicts; ++j)
  2879. {
  2880. prvm_edict_t *ed = PRVM_EDICT_NUM(j);
  2881. if (ed->priv.required->free)
  2882. continue;
  2883. for (i=0; i<prog->numfielddefs; ++i)
  2884. {
  2885. ddef_t *d = &prog->fielddefs[i];
  2886. if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
  2887. continue;
  2888. if(string == PRVM_EDICTFIELDSTRING(ed, d->ofs))
  2889. return true;
  2890. }
  2891. }
  2892. return false;
  2893. }
  2894. static qboolean PRVM_IsEdictRelevant(prvm_prog_t *prog, prvm_edict_t *edict)
  2895. {
  2896. char vabuf[1024];
  2897. char vabuf2[1024];
  2898. if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts)
  2899. return true; // world or clients
  2900. if (edict->priv.required->freetime <= prog->inittime)
  2901. return true; // created during startup
  2902. if (prog == SVVM_prog)
  2903. {
  2904. if(PRVM_serveredictfloat(edict, solid)) // can block other stuff, or is a trigger?
  2905. return true;
  2906. if(PRVM_serveredictfloat(edict, modelindex)) // visible ent?
  2907. return true;
  2908. if(PRVM_serveredictfloat(edict, effects)) // particle effect?
  2909. return true;
  2910. if(PRVM_serveredictfunction(edict, think)) // has a think function?
  2911. if(PRVM_serveredictfloat(edict, nextthink) > 0) // that actually will eventually run?
  2912. return true;
  2913. if(PRVM_serveredictfloat(edict, takedamage))
  2914. return true;
  2915. if(*prvm_leaktest_ignore_classnames.string)
  2916. {
  2917. if(strstr(va(vabuf, sizeof(vabuf), " %s ", prvm_leaktest_ignore_classnames.string), va(vabuf2, sizeof(vabuf2), " %s ", PRVM_GetString(prog, PRVM_serveredictstring(edict, classname)))))
  2918. return true;
  2919. }
  2920. }
  2921. else if (prog == CLVM_prog)
  2922. {
  2923. // TODO someone add more stuff here
  2924. if(PRVM_clientedictfloat(edict, entnum)) // csqc networked
  2925. return true;
  2926. if(PRVM_clientedictfloat(edict, modelindex)) // visible ent?
  2927. return true;
  2928. if(PRVM_clientedictfloat(edict, effects)) // particle effect?
  2929. return true;
  2930. if(PRVM_clientedictfunction(edict, think)) // has a think function?
  2931. if(PRVM_clientedictfloat(edict, nextthink) > 0) // that actually will eventually run?
  2932. return true;
  2933. if(*prvm_leaktest_ignore_classnames.string)
  2934. {
  2935. if(strstr(va(vabuf, sizeof(vabuf), " %s ", prvm_leaktest_ignore_classnames.string), va(vabuf2, sizeof(vabuf2), " %s ", PRVM_GetString(prog, PRVM_clientedictstring(edict, classname)))))
  2936. return true;
  2937. }
  2938. }
  2939. else
  2940. {
  2941. // menu prog does not have classnames
  2942. }
  2943. return false;
  2944. }
  2945. static qboolean PRVM_IsEdictReferenced(prvm_prog_t *prog, prvm_edict_t *edict, int mark)
  2946. {
  2947. int i, j;
  2948. int edictnum = PRVM_NUM_FOR_EDICT(edict);
  2949. const char *targetname = NULL;
  2950. if (prog == SVVM_prog && prvm_leaktest_follow_targetname.integer)
  2951. targetname = PRVM_GetString(prog, PRVM_serveredictstring(edict, targetname));
  2952. if(targetname)
  2953. if(!*targetname) // ""
  2954. targetname = NULL;
  2955. for(j = 0; j < prog->num_edicts; ++j)
  2956. {
  2957. prvm_edict_t *ed = PRVM_EDICT_NUM(j);
  2958. if (ed->priv.required->mark < mark)
  2959. continue;
  2960. if(ed == edict)
  2961. continue;
  2962. if(targetname)
  2963. {
  2964. const char *target = PRVM_GetString(prog, PRVM_serveredictstring(ed, target));
  2965. if(target)
  2966. if(!strcmp(target, targetname))
  2967. return true;
  2968. }
  2969. for (i=0; i<prog->numfielddefs; ++i)
  2970. {
  2971. ddef_t *d = &prog->fielddefs[i];
  2972. if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
  2973. continue;
  2974. if(edictnum == PRVM_EDICTFIELDEDICT(ed, d->ofs))
  2975. return true;
  2976. }
  2977. }
  2978. return false;
  2979. }
  2980. static void PRVM_MarkReferencedEdicts(prvm_prog_t *prog)
  2981. {
  2982. int i, j;
  2983. qboolean found_new;
  2984. int stage;
  2985. // Stage 1: world, all entities that are relevant, and all entities that are referenced by globals.
  2986. stage = 1;
  2987. for(j = 0; j < prog->num_edicts; ++j)
  2988. {
  2989. prvm_edict_t *ed = PRVM_EDICT_NUM(j);
  2990. if(ed->priv.required->free)
  2991. continue;
  2992. ed->priv.required->mark = PRVM_IsEdictRelevant(prog, ed) ? stage : 0;
  2993. }
  2994. for (i = 0;i < prog->numglobaldefs;i++)
  2995. {
  2996. ddef_t *d = &prog->globaldefs[i];
  2997. prvm_edict_t *ed;
  2998. if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
  2999. continue;
  3000. j = PRVM_GLOBALFIELDEDICT(d->ofs);
  3001. if (i < 0 || j >= prog->max_edicts) {
  3002. Con_Printf("Invalid entity reference from global %s.\n", PRVM_GetString(prog, d->s_name));
  3003. continue;
  3004. }
  3005. ed = PRVM_EDICT_NUM(j);;
  3006. ed->priv.required->mark = stage;
  3007. }
  3008. // Future stages: all entities that are referenced by an entity of the previous stage.
  3009. do
  3010. {
  3011. found_new = false;
  3012. for(j = 0; j < prog->num_edicts; ++j)
  3013. {
  3014. prvm_edict_t *ed = PRVM_EDICT_NUM(j);
  3015. if(ed->priv.required->free)
  3016. continue;
  3017. if(ed->priv.required->mark)
  3018. continue;
  3019. if(PRVM_IsEdictReferenced(prog, ed, stage))
  3020. {
  3021. ed->priv.required->mark = stage + 1;
  3022. found_new = true;
  3023. }
  3024. }
  3025. ++stage;
  3026. }
  3027. while(found_new);
  3028. Con_DPrintf("leak check used %d stages to find all references\n", stage);
  3029. }
  3030. void PRVM_LeakTest(prvm_prog_t *prog)
  3031. {
  3032. int i, j;
  3033. qboolean leaked = false;
  3034. if(!prog->leaktest_active)
  3035. return;
  3036. // 1. Strings
  3037. for (i = 0; i < prog->numknownstrings; ++i)
  3038. {
  3039. if(prog->knownstrings[i])
  3040. if(prog->knownstrings_freeable[i])
  3041. if(prog->knownstrings_origin[i])
  3042. if(!PRVM_IsStringReferenced(prog, PRVM_KNOWNSTRINGBASE + i))
  3043. {
  3044. Con_Printf("Unreferenced string found!\n Value: %s\n Origin: %s\n", prog->knownstrings[i], prog->knownstrings_origin[i]);
  3045. leaked = true;
  3046. }
  3047. }
  3048. // 2. Edicts
  3049. PRVM_MarkReferencedEdicts(prog);
  3050. for(j = 0; j < prog->num_edicts; ++j)
  3051. {
  3052. prvm_edict_t *ed = PRVM_EDICT_NUM(j);
  3053. if(ed->priv.required->free)
  3054. continue;
  3055. if(!ed->priv.required->mark)
  3056. if(ed->priv.required->allocation_origin)
  3057. {
  3058. Con_Printf("Unreferenced edict found!\n Allocated at: %s\n", ed->priv.required->allocation_origin);
  3059. PRVM_ED_Print(prog, ed, NULL);
  3060. Con_Print("\n");
  3061. leaked = true;
  3062. }
  3063. ed->priv.required->mark = 0; // clear marks again when done
  3064. }
  3065. for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i)
  3066. {
  3067. prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
  3068. if(stringbuffer)
  3069. if(stringbuffer->origin)
  3070. {
  3071. Con_Printf("Open string buffer handle found!\n Allocated at: %s\n", stringbuffer->origin);
  3072. leaked = true;
  3073. }
  3074. }
  3075. for(i = 0; i < PRVM_MAX_OPENFILES; ++i)
  3076. {
  3077. if(prog->openfiles[i])
  3078. if(prog->openfiles_origin[i])
  3079. {
  3080. Con_Printf("Open file handle found!\n Allocated at: %s\n", prog->openfiles_origin[i]);
  3081. leaked = true;
  3082. }
  3083. }
  3084. for(i = 0; i < PRVM_MAX_OPENSEARCHES; ++i)
  3085. {
  3086. if(prog->opensearches[i])
  3087. if(prog->opensearches_origin[i])
  3088. {
  3089. Con_Printf("Open search handle found!\n Allocated at: %s\n", prog->opensearches_origin[i]);
  3090. leaked = true;
  3091. }
  3092. }
  3093. if(!leaked)
  3094. Con_Printf("Congratulations. No leaks found.\n");
  3095. }