TypeInfo.cpp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. // This is real evil but allows the code to inspect arbitrary class variables.
  21. #define private public
  22. #define protected public
  23. #include "../../idlib/precompiled.h"
  24. #pragma hdrstop
  25. #include "../Game_local.h"
  26. #ifdef ID_DEBUG_MEMORY
  27. #include "GameTypeInfo.h" // Make sure this is up to date!
  28. #else
  29. #include "NoGameTypeInfo.h"
  30. #endif
  31. // disabled because it's adds about 64MB to state dumps and takes a really long time
  32. //#define DUMP_GAMELOCAL
  33. typedef void (*WriteVariableType_t)( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize );
  34. class idTypeInfoTools {
  35. public:
  36. static const classTypeInfo_t * FindClassInfo( const char *typeName );
  37. static const enumTypeInfo_t * FindEnumInfo( const char *typeName );
  38. static bool IsSubclassOf( const char *typeName, const char *superType );
  39. static void PrintType( const void *typePtr, const char *typeName );
  40. static void WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName );
  41. static void InitTypeVariables( const void *typePtr, const char *typeName, int value );
  42. static void WriteGameState( const char *fileName );
  43. static void CompareGameState( const char *fileName );
  44. private:
  45. static idFile * fp;
  46. static int initValue;
  47. static WriteVariableType_t Write;
  48. static idLexer * src;
  49. static bool typeError;
  50. static const char * OutputString( const char *string );
  51. static bool ParseTemplateArguments( idLexer &src, idStr &arguments );
  52. static void PrintVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize );
  53. static void WriteVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize );
  54. static void WriteGameStateVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize );
  55. static void InitVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize );
  56. static void VerifyVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize );
  57. static int WriteVariable_r( const void *varPtr, const char *varName, const char *varType, const char *scope, const char *prefix, const int pointerDepth );
  58. static void WriteClass_r( const void *classPtr, const char *className, const char *classType, const char *scope, const char *prefix, const int pointerDepth );
  59. };
  60. idFile * idTypeInfoTools::fp = NULL;
  61. int idTypeInfoTools::initValue = 0;
  62. WriteVariableType_t idTypeInfoTools::Write = NULL;
  63. idLexer * idTypeInfoTools::src = NULL;
  64. bool idTypeInfoTools::typeError = false;
  65. /*
  66. ================
  67. GetTypeVariableName
  68. ================
  69. */
  70. const char *GetTypeVariableName( const char *typeName, int offset ) {
  71. static char varName[1024];
  72. int i;
  73. for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
  74. if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) {
  75. if ( classTypeInfo[i].variables[0].name != NULL && offset >= classTypeInfo[i].variables[0].offset ) {
  76. break;
  77. }
  78. typeName = classTypeInfo[i].superType;
  79. if ( *typeName == '\0' ) {
  80. return "<unknown>";
  81. }
  82. i = -1;
  83. }
  84. }
  85. const classTypeInfo_t &classInfo = classTypeInfo[i];
  86. for ( i = 0; classInfo.variables[i].name != NULL; i++ ) {
  87. if ( offset <= classInfo.variables[i].offset ) {
  88. break;
  89. }
  90. }
  91. if ( i == 0 ) {
  92. idStr::snPrintf( varName, sizeof( varName ), "%s::<unknown>", classInfo.typeName );
  93. } else {
  94. idStr::snPrintf( varName, sizeof( varName ), "%s::%s", classInfo.typeName, classInfo.variables[i-1].name );
  95. }
  96. return varName;
  97. }
  98. /*
  99. ================
  100. idTypeInfoTools::FindClassInfo
  101. ================
  102. */
  103. const classTypeInfo_t *idTypeInfoTools::FindClassInfo( const char *typeName ) {
  104. int i;
  105. for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
  106. if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) {
  107. return &classTypeInfo[i];
  108. }
  109. }
  110. return NULL;
  111. }
  112. /*
  113. ================
  114. idTypeInfoTools::FindEnumInfo
  115. ================
  116. */
  117. const enumTypeInfo_t *idTypeInfoTools::FindEnumInfo( const char *typeName ) {
  118. int i;
  119. for ( i = 0; enumTypeInfo[i].typeName != NULL; i++ ) {
  120. if ( idStr::Cmp( typeName, enumTypeInfo[i].typeName ) == 0 ) {
  121. return &enumTypeInfo[i];
  122. }
  123. }
  124. return NULL;
  125. }
  126. /*
  127. ================
  128. idTypeInfoTools::IsSubclassOf
  129. ================
  130. */
  131. bool idTypeInfoTools::IsSubclassOf( const char *typeName, const char *superType ) {
  132. int i;
  133. while( *typeName != '\0' ) {
  134. if ( idStr::Cmp( typeName, superType ) == 0 ) {
  135. return true;
  136. }
  137. for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
  138. if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) {
  139. typeName = classTypeInfo[i].superType;
  140. break;
  141. }
  142. }
  143. if ( classTypeInfo[i].typeName == NULL ) {
  144. common->Warning( "super class %s not found", typeName );
  145. break;
  146. }
  147. }
  148. return false;
  149. }
  150. /*
  151. ================
  152. idTypeInfoTools::OutputString
  153. ================
  154. */
  155. const char *idTypeInfoTools::OutputString( const char *string ) {
  156. static int index = 0;
  157. static char buffers[4][16384];
  158. char *out;
  159. int i, c;
  160. out = buffers[index];
  161. index = ( index + 1 ) & 3;
  162. if ( string == NULL ) {
  163. return NULL;
  164. }
  165. for ( i = 0; i < sizeof( buffers[0] ) - 2; i++ ) {
  166. c = *string++;
  167. switch( c ) {
  168. case '\0': out[i] = '\0'; return out;
  169. case '\\': out[i++] = '\\'; out[i] = '\\'; break;
  170. case '\n': out[i++] = '\\'; out[i] = 'n'; break;
  171. case '\r': out[i++] = '\\'; out[i] = 'r'; break;
  172. case '\t': out[i++] = '\\'; out[i] = 't'; break;
  173. case '\v': out[i++] = '\\'; out[i] = 'v'; break;
  174. default: out[i] = c; break;
  175. }
  176. }
  177. out[i] = '\0';
  178. return out;
  179. }
  180. /*
  181. ================
  182. idTypeInfoTools::ParseTemplateArguments
  183. ================
  184. */
  185. bool idTypeInfoTools::ParseTemplateArguments( idLexer &src, idStr &arguments ) {
  186. int indent;
  187. idToken token;
  188. arguments = "";
  189. if ( !src.ExpectTokenString( "<" ) ) {
  190. return false;
  191. }
  192. indent = 1;
  193. while( indent ) {
  194. if ( !src.ReadToken( &token ) ) {
  195. break;
  196. }
  197. if ( token == "<" ) {
  198. indent++;
  199. } else if ( token == ">" ) {
  200. indent--;
  201. } else {
  202. if ( arguments.Length() ) {
  203. arguments += " ";
  204. }
  205. arguments += token;
  206. }
  207. }
  208. return true;
  209. }
  210. /*
  211. ================
  212. idTypeInfoTools::PrintType
  213. ================
  214. */
  215. void idTypeInfoTools::PrintType( const void *typePtr, const char *typeName ) {
  216. idTypeInfoTools::fp = NULL;
  217. idTypeInfoTools::initValue = 0;
  218. idTypeInfoTools::Write = PrintVariable;
  219. WriteClass_r( typePtr, "", typeName, "", "", 0 );
  220. }
  221. /*
  222. ================
  223. idTypeInfoTools::WriteTypeToFile
  224. ================
  225. */
  226. void idTypeInfoTools::WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName ) {
  227. idTypeInfoTools::fp = fp;
  228. idTypeInfoTools::initValue = 0;
  229. idTypeInfoTools::Write = WriteVariable;
  230. WriteClass_r( typePtr, "", typeName, "", "", 0 );
  231. }
  232. /*
  233. ================
  234. idTypeInfoTools::InitTypeVariables
  235. ================
  236. */
  237. void idTypeInfoTools::InitTypeVariables( const void *typePtr, const char *typeName, int value ) {
  238. idTypeInfoTools::fp = NULL;
  239. idTypeInfoTools::initValue = value;
  240. idTypeInfoTools::Write = InitVariable;
  241. WriteClass_r( typePtr, "", typeName, "", "", 0 );
  242. }
  243. /*
  244. ================
  245. IsAllowedToChangedFromSaveGames
  246. ================
  247. */
  248. bool IsAllowedToChangedFromSaveGames( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value ) {
  249. if ( idStr::Icmp( scope, "idAnimator" ) == 0 ) {
  250. if ( idStr::Icmp( varName, "forceUpdate" ) == 0 ) {
  251. return true;
  252. }
  253. if ( idStr::Icmp( varName, "lastTransformTime" ) == 0 ) {
  254. return true;
  255. }
  256. if ( idStr::Icmp( varName, "AFPoseTime" ) == 0 ) {
  257. return true;
  258. }
  259. if ( idStr::Icmp( varName, "frameBounds" ) == 0 ) {
  260. return true;
  261. }
  262. } else if ( idStr::Icmp( scope, "idClipModel" ) == 0 ) {
  263. if ( idStr::Icmp( varName, "touchCount" ) == 0 ) {
  264. return true;
  265. }
  266. } else if ( idStr::Icmp( scope, "idEntity" ) == 0 ) {
  267. if ( idStr::Icmp( varName, "numPVSAreas" ) == 0 ) {
  268. return true;
  269. }
  270. if ( idStr::Icmp( varName, "renderView" ) == 0 ) {
  271. return true;
  272. }
  273. } else if ( idStr::Icmp( scope, "idBrittleFracture" ) == 0 ) {
  274. if ( idStr::Icmp( varName, "changed" ) == 0 ) {
  275. return true;
  276. }
  277. } else if ( idStr::Icmp( scope, "idPhysics_AF" ) == 0 ) {
  278. return true;
  279. } else if ( idStr::Icmp( scope, "renderEntity_t" ) == 0 ) {
  280. // These get fixed up when UpdateVisuals is called
  281. if ( idStr::Icmp( varName, "origin" ) == 0 ) {
  282. return true;
  283. }
  284. if ( idStr::Icmp( varName, "axis" ) == 0 ) {
  285. return true;
  286. }
  287. if ( idStr::Icmp( varName, "bounds" ) == 0 ) {
  288. return true;
  289. }
  290. }
  291. if ( idStr::Icmpn( prefix, "idAFEntity_Base::af.idAF::physicsObj.idPhysics_AF", 49) == 0 ) {
  292. return true;
  293. }
  294. return false;
  295. }
  296. /*
  297. ================
  298. IsRenderHandleVariable
  299. ================
  300. */
  301. bool IsRenderHandleVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value ) {
  302. if ( idStr::Icmp( scope, "idClipModel" ) == 0 ) {
  303. if ( idStr::Icmp( varName, "renderModelHandle" ) == 0 ) {
  304. return true;
  305. }
  306. } else if ( idStr::Icmp( scope, "idFXLocalAction" ) == 0 ) {
  307. if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) {
  308. return true;
  309. }
  310. if ( idStr::Icmp( varName, "modelDefHandle" ) == 0 ) {
  311. return true;
  312. }
  313. } else if ( idStr::Icmp( scope, "idEntity" ) == 0 ) {
  314. if ( idStr::Icmp( varName, "modelDefHandle" ) == 0 ) {
  315. return true;
  316. }
  317. } else if ( idStr::Icmp( scope, "idLight" ) == 0 ) {
  318. if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) {
  319. return true;
  320. }
  321. } else if ( idStr::Icmp( scope, "idAFEntity_Gibbable" ) == 0 ) {
  322. if ( idStr::Icmp( varName, "skeletonModelDefHandle" ) == 0 ) {
  323. return true;
  324. }
  325. } else if ( idStr::Icmp( scope, "idAFEntity_SteamPipe" ) == 0 ) {
  326. if ( idStr::Icmp( varName, "steamModelHandle" ) == 0 ) {
  327. return true;
  328. }
  329. } else if ( idStr::Icmp( scope, "idItem" ) == 0 ) {
  330. if ( idStr::Icmp( varName, "itemShellHandle" ) == 0 ) {
  331. return true;
  332. }
  333. } else if ( idStr::Icmp( scope, "idExplodingBarrel" ) == 0 ) {
  334. if ( idStr::Icmp( varName, "particleModelDefHandle" ) == 0 ) {
  335. return true;
  336. }
  337. if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) {
  338. return true;
  339. }
  340. } else if ( idStr::Icmp( scope, "idProjectile" ) == 0 ) {
  341. if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) {
  342. return true;
  343. }
  344. } else if ( idStr::Icmp( scope, "idBFGProjectile" ) == 0 ) {
  345. if ( idStr::Icmp( varName, "secondModelDefHandle" ) == 0 ) {
  346. return true;
  347. }
  348. } else if ( idStr::Icmp( scope, "idSmokeParticles" ) == 0 ) {
  349. if ( idStr::Icmp( varName, "renderEntityHandle" ) == 0 ) {
  350. return true;
  351. }
  352. } else if ( idStr::Icmp( scope, "idWeapon" ) == 0 ) {
  353. if ( idStr::Icmp( varName, "muzzleFlashHandle" ) == 0 ) {
  354. return true;
  355. }
  356. if ( idStr::Icmp( varName, "worldMuzzleFlashHandle" ) == 0 ) {
  357. return true;
  358. }
  359. if ( idStr::Icmp( varName, "guiLightHandle" ) == 0 ) {
  360. return true;
  361. }
  362. if ( idStr::Icmp( varName, "nozzleGlowHandle" ) == 0 ) {
  363. return true;
  364. }
  365. }
  366. return false;
  367. }
  368. /*
  369. ================
  370. idTypeInfoTools::PrintVariable
  371. ================
  372. */
  373. void idTypeInfoTools::PrintVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) {
  374. common->Printf( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value );
  375. }
  376. /*
  377. ================
  378. idTypeInfoTools::WriteVariable
  379. ================
  380. */
  381. void idTypeInfoTools::WriteVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) {
  382. for ( int i = idStr::FindChar( value, '#', 0 ); i >= 0; i = idStr::FindChar( value, '#', i+1 ) ) {
  383. if ( idStr::Icmpn( value+i+1, "INF", 3 ) == 0 ||
  384. idStr::Icmpn( value+i+1, "IND", 3 ) == 0 ||
  385. idStr::Icmpn( value+i+1, "NAN", 3 ) == 0 ||
  386. idStr::Icmpn( value+i+1, "QNAN", 4 ) == 0 ||
  387. idStr::Icmpn( value+i+1, "SNAN", 4 ) == 0 ) {
  388. common->Warning( "%s%s::%s%s = \"%s\"", prefix, scope, varName, postfix, value );
  389. break;
  390. }
  391. }
  392. fp->WriteFloatString( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value );
  393. }
  394. /*
  395. ================
  396. idTypeInfoTools::WriteGameStateVariable
  397. ================
  398. */
  399. void idTypeInfoTools::WriteGameStateVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) {
  400. for ( int i = idStr::FindChar( value, '#', 0 ); i >= 0; i = idStr::FindChar( value, '#', i+1 ) ) {
  401. if ( idStr::Icmpn( value+i+1, "INF", 3 ) == 0 ||
  402. idStr::Icmpn( value+i+1, "IND", 3 ) == 0 ||
  403. idStr::Icmpn( value+i+1, "NAN", 3 ) == 0 ||
  404. idStr::Icmpn( value+i+1, "QNAN", 4 ) == 0 ||
  405. idStr::Icmpn( value+i+1, "SNAN", 4 ) == 0 ) {
  406. common->Warning( "%s%s::%s%s = \"%s\"", prefix, scope, varName, postfix, value );
  407. break;
  408. }
  409. }
  410. if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) {
  411. return;
  412. }
  413. if ( IsAllowedToChangedFromSaveGames( varName, varType, scope, prefix, postfix, value ) ) {
  414. return;
  415. }
  416. fp->WriteFloatString( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value );
  417. }
  418. /*
  419. ================
  420. idTypeInfoTools::InitVariable
  421. ================
  422. */
  423. void idTypeInfoTools::InitVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) {
  424. if ( varPtr != NULL && varSize > 0 ) {
  425. // NOTE: skip renderer handles
  426. if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) {
  427. return;
  428. }
  429. memset( const_cast<void*>(varPtr), initValue, varSize );
  430. }
  431. }
  432. /*
  433. ================
  434. idTypeInfoTools::VerifyVariable
  435. ================
  436. */
  437. void idTypeInfoTools::VerifyVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value, const void *varPtr, int varSize ) {
  438. idToken token;
  439. if ( typeError ) {
  440. return;
  441. }
  442. src->SkipUntilString( "=" );
  443. src->ExpectTokenType( TT_STRING, 0, &token );
  444. if ( token.Cmp( value ) != 0 ) {
  445. // NOTE: skip several things
  446. if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) {
  447. return;
  448. }
  449. if ( IsAllowedToChangedFromSaveGames( varName, varType, scope, prefix, postfix, value ) ) {
  450. return;
  451. }
  452. src->Warning( "state diff for %s%s::%s%s\n%s\n%s", prefix, scope, varName, postfix, token.c_str(), value );
  453. typeError = true;
  454. }
  455. }
  456. /*
  457. ================
  458. idTypeInfoTools::WriteVariable_r
  459. ================
  460. */
  461. int idTypeInfoTools::WriteVariable_r( const void *varPtr, const char *varName, const char *varType, const char *scope, const char *prefix, const int pointerDepth ) {
  462. int i, isPointer, typeSize;
  463. idLexer typeSrc;
  464. idToken token;
  465. idStr typeString, templateArgs;
  466. isPointer = 0;
  467. typeSize = -1;
  468. // create a type string without 'const', 'mutable', 'class', 'struct', 'union'
  469. typeSrc.LoadMemory( varType, idStr::Length( varType ), varName );
  470. while( typeSrc.ReadToken( &token ) ) {
  471. if ( token != "const" && token != "mutable" && token != "class" && token != "struct" && token != "union" ) {
  472. typeString += token + " ";
  473. }
  474. }
  475. typeString.StripTrailing( ' ' );
  476. typeSrc.FreeSource();
  477. // if this is an array
  478. if ( typeString[typeString.Length() - 1] == ']' ) {
  479. for ( i = typeString.Length(); i > 0 && typeString[i - 1] != '['; i-- ) {
  480. }
  481. int num = atoi( &typeString[i] );
  482. idStr listVarType = typeString;
  483. listVarType.CapLength( i - 1 );
  484. typeSize = 0;
  485. for ( i = 0; i < num; i++ ) {
  486. idStr listVarName = va( "%s[%d]", varName, i );
  487. int size = WriteVariable_r( varPtr, listVarName, listVarType, scope, prefix, pointerDepth );
  488. typeSize += size;
  489. if ( size == -1 ) {
  490. break;
  491. }
  492. varPtr = (void *)( ( (byte *) varPtr ) + size );
  493. }
  494. return typeSize;
  495. }
  496. // if this is a pointer
  497. isPointer = 0;
  498. for ( i = typeString.Length(); i > 0 && typeString[i - 1] == '*'; i -= 2 ) {
  499. if ( varPtr == (void *)0xcdcdcdcd || ( varPtr != NULL && *((unsigned long *)varPtr) == 0xcdcdcdcd ) ) {
  500. common->Warning( "%s%s::%s%s references uninitialized memory", prefix, scope, varName, "" );
  501. return typeSize;
  502. }
  503. if ( varPtr != NULL ) {
  504. varPtr = *((void **)varPtr);
  505. }
  506. isPointer++;
  507. }
  508. if ( varPtr == NULL ) {
  509. Write( varName, varType, scope, prefix, "", "<NULL>", varPtr, 0 );
  510. return sizeof( void * );
  511. }
  512. typeSrc.LoadMemory( typeString, typeString.Length(), varName );
  513. if ( !typeSrc.ReadToken( &token ) ) {
  514. Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
  515. return -1;
  516. }
  517. // get full type
  518. while( typeSrc.CheckTokenString( "::" ) ) {
  519. idToken newToken;
  520. typeSrc.ExpectTokenType( TT_NAME, 0, &newToken );
  521. token += "::" + newToken;
  522. }
  523. if ( token == "signed" ) {
  524. if ( !typeSrc.ReadToken( &token ) ) {
  525. Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
  526. return -1;
  527. }
  528. if ( token == "char" ) {
  529. typeSize = sizeof( signed char );
  530. Write( varName, varType, scope, prefix, "", va( "%d", *((signed char *)varPtr) ), varPtr, typeSize );
  531. } else if ( token == "short" ) {
  532. typeSize = sizeof( signed short );
  533. Write( varName, varType, scope, prefix, "", va( "%d", *((signed short *)varPtr) ), varPtr, typeSize );
  534. } else if ( token == "int" ) {
  535. typeSize = sizeof( signed int );
  536. Write( varName, varType, scope, prefix, "", va( "%d", *((signed int *)varPtr) ), varPtr, typeSize );
  537. } else if ( token == "long" ) {
  538. typeSize = sizeof( signed long );
  539. Write( varName, varType, scope, prefix, "", va( "%ld", *((signed long *)varPtr) ), varPtr, typeSize );
  540. } else {
  541. Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
  542. return -1;
  543. }
  544. } else if ( token == "unsigned" ) {
  545. if ( !typeSrc.ReadToken( &token ) ) {
  546. Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
  547. return -1;
  548. }
  549. if ( token == "char" ) {
  550. typeSize = sizeof( unsigned char );
  551. Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned char *)varPtr) ), varPtr, typeSize );
  552. } else if ( token == "short" ) {
  553. typeSize = sizeof( unsigned short );
  554. Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned short *)varPtr) ), varPtr, typeSize );
  555. } else if ( token == "int" ) {
  556. typeSize = sizeof( unsigned int );
  557. Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned int *)varPtr) ), varPtr, typeSize );
  558. } else if ( token == "long" ) {
  559. typeSize = sizeof( unsigned long );
  560. Write( varName, varType, scope, prefix, "", va( "%lu", *((unsigned long *)varPtr) ), varPtr, typeSize );
  561. } else {
  562. Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
  563. return -1;
  564. }
  565. } else if ( token == "byte" ) {
  566. typeSize = sizeof( byte );
  567. Write( varName, varType, scope, prefix, "", va( "%d", *((byte *)varPtr) ), varPtr, typeSize );
  568. } else if ( token == "word" ) {
  569. typeSize = sizeof( word );
  570. Write( varName, varType, scope, prefix, "", va( "%d", *((word *)varPtr) ), varPtr, typeSize );
  571. } else if ( token == "dword" ) {
  572. typeSize = sizeof( dword );
  573. Write( varName, varType, scope, prefix, "", va( "%d", *((dword *)varPtr) ), varPtr, typeSize );
  574. } else if ( token == "bool" ) {
  575. typeSize = sizeof( bool );
  576. Write( varName, varType, scope, prefix, "", va( "%d", *((bool *)varPtr) ), varPtr, typeSize );
  577. } else if ( token == "char" ) {
  578. typeSize = sizeof( char );
  579. Write( varName, varType, scope, prefix, "", va( "%d", *((char *)varPtr) ), varPtr, typeSize );
  580. } else if ( token == "short" ) {
  581. typeSize = sizeof( short );
  582. Write( varName, varType, scope, prefix, "", va( "%d", *((short *)varPtr) ), varPtr, typeSize );
  583. } else if ( token == "int" ) {
  584. typeSize = sizeof( int );
  585. Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize );
  586. } else if ( token == "long" ) {
  587. typeSize = sizeof( long );
  588. Write( varName, varType, scope, prefix, "", va( "%ld", *((long *)varPtr) ), varPtr, typeSize );
  589. } else if ( token == "float" ) {
  590. typeSize = sizeof( float );
  591. Write( varName, varType, scope, prefix, "", idStr( *((float *)varPtr) ).c_str(), varPtr, typeSize );
  592. } else if ( token == "double" ) {
  593. typeSize = sizeof( double );
  594. Write( varName, varType, scope, prefix, "", idStr( (float)*((double *)varPtr) ).c_str(), varPtr, typeSize );
  595. } else if ( token == "idVec2" ) {
  596. typeSize = sizeof( idVec2 );
  597. Write( varName, varType, scope, prefix, "", ((idVec2 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  598. } else if ( token == "idVec3" ) {
  599. typeSize = sizeof( idVec3 );
  600. Write( varName, varType, scope, prefix, "", ((idVec3 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  601. } else if ( token == "idVec4" ) {
  602. typeSize = sizeof( idVec4 );
  603. Write( varName, varType, scope, prefix, "", ((idVec4 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  604. } else if ( token == "idVec5" ) {
  605. typeSize = sizeof( idVec5 );
  606. Write( varName, varType, scope, prefix, "", ((idVec5 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  607. } else if ( token == "idVec6" ) {
  608. typeSize = sizeof( idVec6 );
  609. Write( varName, varType, scope, prefix, "", ((idVec6 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  610. } else if ( token == "idVecX" ) {
  611. const idVecX *vec = ((idVecX *)varPtr);
  612. if ( vec->ToFloatPtr() != NULL ) {
  613. Write( varName, varType, scope, prefix, "", vec->ToString( 8 ), vec->ToFloatPtr(), vec->GetSize() * sizeof( float ) );
  614. } else {
  615. Write( varName, varType, scope, prefix, "", "<NULL>", varPtr, 0 );
  616. }
  617. typeSize = sizeof( idVecX );
  618. } else if ( token == "idMat2" ) {
  619. typeSize = sizeof( idMat2 );
  620. Write( varName, varType, scope, prefix, "", ((idMat2 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  621. } else if ( token == "idMat3" ) {
  622. typeSize = sizeof( idMat3 );
  623. Write( varName, varType, scope, prefix, "", ((idMat3 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  624. } else if ( token == "idMat4" ) {
  625. typeSize = sizeof( idMat4 );
  626. Write( varName, varType, scope, prefix, "", ((idMat4 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  627. } else if ( token == "idMat5" ) {
  628. typeSize = sizeof( idMat5 );
  629. Write( varName, varType, scope, prefix, "", ((idMat5 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  630. } else if ( token == "idMat6" ) {
  631. typeSize = sizeof( idMat6 );
  632. Write( varName, varType, scope, prefix, "", ((idMat6 *)varPtr)->ToString( 8 ), varPtr, typeSize );
  633. } else if ( token == "idMatX" ) {
  634. typeSize = sizeof( idMatX );
  635. const idMatX *mat = ((idMatX *)varPtr);
  636. if ( mat->ToFloatPtr() != NULL ) {
  637. Write( varName, varType, scope, prefix, "", mat->ToString( 8 ), mat->ToFloatPtr(), mat->GetNumColumns() * mat->GetNumRows() * sizeof( float ) );
  638. } else {
  639. Write( varName, varType, scope, prefix, "", "<NULL>", NULL, 0 );
  640. }
  641. } else if ( token == "idAngles" ) {
  642. typeSize = sizeof( idAngles );
  643. Write( varName, varType, scope, prefix, "", ((idAngles *)varPtr)->ToString( 8 ), varPtr, typeSize );
  644. } else if ( token == "idQuat" ) {
  645. typeSize = sizeof( idQuat );
  646. Write( varName, varType, scope, prefix, "", ((idQuat *)varPtr)->ToString( 8 ), varPtr, typeSize );
  647. } else if ( token == "idBounds" ) {
  648. typeSize = sizeof( idBounds );
  649. const idBounds *bounds = ((idBounds *)varPtr);
  650. if ( bounds->IsCleared() ) {
  651. Write( varName, varType, scope, prefix, "", "<cleared>", varPtr, typeSize );
  652. } else {
  653. Write( varName, varType, scope, prefix, "", va( "(%s)-(%s)", (*bounds)[0].ToString( 8 ), (*bounds)[1].ToString( 8 ) ), varPtr, typeSize );
  654. }
  655. } else if ( token == "idList" ) {
  656. idList<int> *list = ((idList<int> *)varPtr);
  657. Write( varName, varType, scope, prefix, ".num", va( "%d", list->Num() ), NULL, 0 );
  658. // NOTE: we don't care about the amount of memory allocated
  659. //Write( varName, varType, scope, prefix, ".size", va( "%d", list->Size() ), NULL, 0 );
  660. Write( varName, varType, scope, prefix, ".granularity", va( "%d", list->GetGranularity() ), NULL, 0 );
  661. if ( list->Num() && ParseTemplateArguments( typeSrc, templateArgs ) ) {
  662. void *listVarPtr = list->Ptr();
  663. for ( i = 0; i < list->Num(); i++ ) {
  664. idStr listVarName = va( "%s[%d]", varName, i );
  665. int size = WriteVariable_r( listVarPtr, listVarName, templateArgs, scope, prefix, pointerDepth );
  666. if ( size == -1 ) {
  667. break;
  668. }
  669. listVarPtr = (void *)( ( (byte *) listVarPtr ) + size );
  670. }
  671. }
  672. typeSize = sizeof( idList<int> );
  673. } else if ( token == "idStaticList" ) {
  674. idStaticList<int, 1> *list = ((idStaticList<int, 1> *)varPtr);
  675. Write( varName, varType, scope, prefix, ".num", va( "%d", list->Num() ), NULL, 0 );
  676. int totalSize = 0;
  677. if ( list->Num() && ParseTemplateArguments( typeSrc, templateArgs ) ) {
  678. void *listVarPtr = list->Ptr();
  679. for ( i = 0; i < list->Num(); i++ ) {
  680. idStr listVarName = va( "%s[%d]", varName, i );
  681. int size = WriteVariable_r( listVarPtr, listVarName, templateArgs, scope, prefix, pointerDepth );
  682. if ( size == -1 ) {
  683. break;
  684. }
  685. totalSize += size;
  686. listVarPtr = (void *)( ( (byte *) listVarPtr ) + size );
  687. }
  688. }
  689. typeSize = sizeof( int ) + totalSize;
  690. } else if ( token == "idLinkList" ) {
  691. // FIXME: implement
  692. typeSize = sizeof( idLinkList<idEntity> );
  693. Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), NULL, 0 );
  694. } else if ( token == "idStr" ) {
  695. typeSize = sizeof( idStr );
  696. const idStr *str = ((idStr *)varPtr);
  697. Write( varName, varType, scope, prefix, "", OutputString( str->c_str() ), str->c_str(), str->Length() );
  698. } else if ( token == "idStrList" ) {
  699. typeSize = sizeof( idStrList );
  700. const idStrList *list = ((idStrList *)varPtr);
  701. if ( list->Num() ) {
  702. for ( i = 0; i < list->Num(); i++ ) {
  703. Write( varName, varType, scope, prefix, va("[%d]", i ), OutputString( (*list)[i].c_str() ), (*list)[i].c_str(), (*list)[i].Length() );
  704. }
  705. } else {
  706. Write( varName, varType, scope, prefix, "", "<empty>", NULL, 0 );
  707. }
  708. } else if ( token == "idDict" ) {
  709. typeSize = sizeof( idDict );
  710. const idDict *dict = ((idDict *)varPtr);
  711. if ( dict->GetNumKeyVals() ) {
  712. for ( i = 0; i < dict->GetNumKeyVals(); i++ ) {
  713. const idKeyValue *kv = dict->GetKeyVal( i );
  714. Write( varName, varType, scope, prefix, va("[%d]", i ), va( "\'%s\' \'%s\'", OutputString( kv->GetKey().c_str() ), OutputString( kv->GetValue().c_str() ) ), NULL, 0 );
  715. }
  716. } else {
  717. Write( varName, varType, scope, prefix, "", "<empty>", NULL, 0 );
  718. }
  719. } else if ( token == "idExtrapolate" ) {
  720. const idExtrapolate<float> *interpolate = ((idExtrapolate<float> *)varPtr);
  721. Write( varName, varType, scope, prefix, ".extrapolationType", idStr( interpolate->GetExtrapolationType() ).c_str(), &interpolate->extrapolationType, sizeof( interpolate->extrapolationType ) );
  722. Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) );
  723. Write( varName, varType, scope, prefix, ".duration", idStr( interpolate->GetDuration() ).c_str(), &interpolate->duration, sizeof( interpolate->duration ) );
  724. if ( ParseTemplateArguments( typeSrc, templateArgs ) ) {
  725. if ( templateArgs == "int" ) {
  726. const idExtrapolate<int> *interpolate = ((idExtrapolate<int> *)varPtr);
  727. Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
  728. Write( varName, varType, scope, prefix, ".baseSpeed", idStr( interpolate->GetBaseSpeed() ).c_str(), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) );
  729. Write( varName, varType, scope, prefix, ".speed", idStr( interpolate->GetSpeed() ).c_str(), &interpolate->speed, sizeof( interpolate->speed ) );
  730. typeSize = sizeof( idExtrapolate<int> );
  731. } else if ( templateArgs == "float" ) {
  732. const idExtrapolate<float> *interpolate = ((idExtrapolate<float> *)varPtr);
  733. Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
  734. Write( varName, varType, scope, prefix, ".baseSpeed", idStr( interpolate->GetBaseSpeed() ).c_str(), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) );
  735. Write( varName, varType, scope, prefix, ".speed", idStr( interpolate->GetSpeed() ).c_str(), &interpolate->speed, sizeof( interpolate->speed ) );
  736. typeSize = sizeof( idExtrapolate<float> );
  737. } else if ( templateArgs == "idVec3" ) {
  738. const idExtrapolate<idVec3> *interpolate = ((idExtrapolate<idVec3> *)varPtr);
  739. Write( varName, varType, scope, prefix, ".startValue", interpolate->GetStartValue().ToString( 8 ), &interpolate->startValue, sizeof( interpolate->startValue ) );
  740. Write( varName, varType, scope, prefix, ".baseSpeed", interpolate->GetBaseSpeed().ToString( 8 ), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) );
  741. Write( varName, varType, scope, prefix, ".speed", interpolate->GetSpeed().ToString( 8 ), &interpolate->speed, sizeof( interpolate->speed ) );
  742. typeSize = sizeof( idExtrapolate<idVec3> );
  743. } else if ( templateArgs == "idAngles" ) {
  744. const idExtrapolate<idAngles> *interpolate = ((idExtrapolate<idAngles> *)varPtr);
  745. Write( varName, varType, scope, prefix, ".startValue", interpolate->GetStartValue().ToString( 8 ), &interpolate->startValue, sizeof( interpolate->startValue ) );
  746. Write( varName, varType, scope, prefix, ".baseSpeed", interpolate->GetBaseSpeed().ToString( 8 ), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) );
  747. Write( varName, varType, scope, prefix, ".speed", interpolate->GetSpeed().ToString( 8 ), &interpolate->speed, sizeof( interpolate->speed ) );
  748. typeSize = sizeof( idExtrapolate<idAngles> );
  749. } else {
  750. Write( varName, varType, scope, prefix, "", va( "<unknown template argument type '%s' for idExtrapolate>", templateArgs.c_str() ), NULL, 0 );
  751. }
  752. }
  753. } else if ( token == "idInterpolate" ) {
  754. const idInterpolate<float> *interpolate = ((idInterpolate<float> *)varPtr);
  755. Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) );
  756. Write( varName, varType, scope, prefix, ".duration", idStr( interpolate->GetDuration() ).c_str(), &interpolate->duration, sizeof( interpolate->duration ) );
  757. if ( ParseTemplateArguments( typeSrc, templateArgs ) ) {
  758. if ( templateArgs == "int" ) {
  759. const idInterpolate<int> *interpolate = ((idInterpolate<int> *)varPtr);
  760. Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
  761. Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
  762. typeSize = sizeof( idInterpolate<int> );
  763. } else if ( templateArgs == "float" ) {
  764. const idInterpolate<float> *interpolate = ((idInterpolate<float> *)varPtr);
  765. Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
  766. Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
  767. typeSize = sizeof( idInterpolate<float> );
  768. } else {
  769. Write( varName, varType, scope, prefix, "", va( "<unknown template argument type '%s' for idInterpolate>", templateArgs.c_str() ), NULL, 0 );
  770. }
  771. }
  772. } else if ( token == "idInterpolateAccelDecelLinear" ) {
  773. const idInterpolateAccelDecelLinear<float> *interpolate = ((idInterpolateAccelDecelLinear<float> *)varPtr);
  774. Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) );
  775. Write( varName, varType, scope, prefix, ".accelTime", idStr( interpolate->GetAcceleration() ).c_str(), &interpolate->accelTime, sizeof( interpolate->accelTime ) );
  776. Write( varName, varType, scope, prefix, ".linearTime", idStr( interpolate->linearTime ).c_str(), &interpolate->linearTime, sizeof( interpolate->linearTime ) );
  777. Write( varName, varType, scope, prefix, ".decelTime", idStr( interpolate->GetDeceleration() ).c_str(), &interpolate->decelTime, sizeof( interpolate->decelTime ) );
  778. if ( ParseTemplateArguments( typeSrc, templateArgs ) ) {
  779. if ( templateArgs == "int" ) {
  780. const idInterpolateAccelDecelLinear<int> *interpolate = ((idInterpolateAccelDecelLinear<int> *)varPtr);
  781. Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
  782. Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
  783. typeSize = sizeof( idInterpolateAccelDecelLinear<int> );
  784. } else if ( templateArgs == "float" ) {
  785. const idInterpolateAccelDecelLinear<float> *interpolate = ((idInterpolateAccelDecelLinear<float> *)varPtr);
  786. Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
  787. Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
  788. typeSize = sizeof( idInterpolateAccelDecelLinear<float> );
  789. } else {
  790. Write( varName, varType, scope, prefix, "", va( "<unknown template argument type '%s' for idInterpolateAccelDecelLinear>", templateArgs.c_str() ), NULL, 0 );
  791. }
  792. }
  793. } else if ( token == "idInterpolateAccelDecelSine" ) {
  794. const idInterpolateAccelDecelSine<float> *interpolate = ((idInterpolateAccelDecelSine<float> *)varPtr);
  795. Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) );
  796. Write( varName, varType, scope, prefix, ".accelTime", idStr( interpolate->GetAcceleration() ).c_str(), &interpolate->accelTime, sizeof( interpolate->accelTime ) );
  797. Write( varName, varType, scope, prefix, ".linearTime", idStr( interpolate->linearTime ).c_str(), &interpolate->linearTime, sizeof( interpolate->linearTime ) );
  798. Write( varName, varType, scope, prefix, ".decelTime", idStr( interpolate->GetDeceleration() ).c_str(), &interpolate->decelTime, sizeof( interpolate->decelTime ) );
  799. if ( ParseTemplateArguments( typeSrc, templateArgs ) ) {
  800. if ( templateArgs == "int" ) {
  801. const idInterpolateAccelDecelSine<int> *interpolate = ((idInterpolateAccelDecelSine<int> *)varPtr);
  802. Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
  803. Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
  804. typeSize = sizeof( idInterpolateAccelDecelSine<int> );
  805. } else if ( templateArgs == "float" ) {
  806. const idInterpolateAccelDecelSine<float> *interpolate = ((idInterpolateAccelDecelSine<float> *)varPtr);
  807. Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
  808. Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
  809. typeSize = sizeof( idInterpolateAccelDecelSine<float> );
  810. } else {
  811. Write( varName, varType, scope, prefix, "", va( "<unknown template argument type '%s' for idInterpolateAccelDecelSine>", templateArgs.c_str() ), NULL, 0 );
  812. }
  813. }
  814. } else if ( token == "idUserInterface" ) {
  815. typeSize = sizeof( idUserInterface );
  816. const idUserInterface *gui = ((idUserInterface *)varPtr);
  817. Write( varName, varType, scope, prefix, "", gui->Name(), varPtr, sizeof( varPtr ) );
  818. } else if ( token == "idRenderModel" ) {
  819. typeSize = sizeof( idRenderModel );
  820. const idRenderModel *model = ((idRenderModel *)varPtr);
  821. Write( varName, varType, scope, prefix, "", model->Name(), varPtr, sizeof( varPtr ) );
  822. } else if ( token == "qhandle_t" ) {
  823. typeSize = sizeof( int );
  824. Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize );
  825. } else if ( token == "cmHandle_t" ) {
  826. typeSize = sizeof( int );
  827. Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize );
  828. } else if ( token == "idEntityPtr" ) {
  829. typeSize = sizeof( idEntityPtr<idEntity> );
  830. const idEntityPtr<idEntity> *entPtr = ((idEntityPtr<idEntity> *)varPtr);
  831. if ( entPtr->GetEntity() ) {
  832. idEntity *entity = entPtr->GetEntity();
  833. Write( varName, varType, scope, prefix, ".", va( "entity %d: \'%s\'", entity->entityNumber, entity->name.c_str() ), varPtr, typeSize );
  834. } else {
  835. Write( varName, varType, scope, prefix, "", "<NULL>", varPtr, typeSize );
  836. }
  837. } else if ( token == "idEntity::entityFlags_s" ) {
  838. const idEntity::entityFlags_s *flags = ((idEntity::entityFlags_s *)varPtr);
  839. Write( varName, varType, scope, prefix, ".notarget", flags->notarget ? "true" : "false", NULL, 0 );
  840. Write( varName, varType, scope, prefix, ".noknockback", flags->noknockback ? "true" : "false", NULL, 0 );
  841. Write( varName, varType, scope, prefix, ".takedamage", flags->takedamage ? "true" : "false", NULL, 0 );
  842. Write( varName, varType, scope, prefix, ".hidden", flags->hidden ? "true" : "false", NULL, 0 );
  843. Write( varName, varType, scope, prefix, ".bindOrientated", flags->bindOrientated ? "true" : "false", NULL, 0 );
  844. Write( varName, varType, scope, prefix, ".solidForTeam", flags->solidForTeam ? "true" : "false", NULL, 0 );
  845. Write( varName, varType, scope, prefix, ".forcePhysicsUpdate", flags->forcePhysicsUpdate ? "true" : "false", NULL, 0 );
  846. Write( varName, varType, scope, prefix, ".selected", flags->selected ? "true" : "false", NULL, 0 );
  847. Write( varName, varType, scope, prefix, ".neverDormant", flags->neverDormant ? "true" : "false", NULL, 0 );
  848. Write( varName, varType, scope, prefix, ".isDormant", flags->isDormant ? "true" : "false", NULL, 0 );
  849. Write( varName, varType, scope, prefix, ".hasAwakened", flags->hasAwakened ? "true" : "false", NULL, 0 );
  850. Write( varName, varType, scope, prefix, ".networkSync", flags->networkSync ? "true" : "false", NULL, 0 );
  851. typeSize = sizeof( idEntity::entityFlags_s );
  852. } else if ( token == "idScriptBool" ) {
  853. typeSize = sizeof( idScriptBool );
  854. const idScriptBool *scriptBool = ((idScriptBool *)varPtr);
  855. if ( scriptBool->IsLinked() ) {
  856. Write( varName, varType, scope, prefix, "", ( *scriptBool != 0 ) ? "true" : "false", varPtr, typeSize );
  857. } else {
  858. Write( varName, varType, scope, prefix, "", "<not linked>", varPtr, typeSize );
  859. }
  860. } else {
  861. const classTypeInfo_t *classTypeInfo = FindClassInfo( scope + ( "::" + token ) );
  862. if ( classTypeInfo == NULL ) {
  863. classTypeInfo = FindClassInfo( token );
  864. }
  865. if ( classTypeInfo != NULL ) {
  866. typeSize = classTypeInfo->size;
  867. if ( !isPointer ) {
  868. char newPrefix[1024];
  869. idStr::snPrintf( newPrefix, sizeof( newPrefix ), "%s%s::%s.", prefix, scope, varName );
  870. WriteClass_r( varPtr, "", token, token, newPrefix, pointerDepth );
  871. } else if ( token == "idAnim" ) {
  872. const idAnim *anim = ((idAnim*)varPtr);
  873. Write( varName, varType, scope, prefix, "", anim->Name(), NULL, 0 );
  874. } else if ( token == "idPhysics" ) {
  875. const idPhysics *physics = ((idPhysics*)varPtr);
  876. Write( varName, varType, scope, prefix, "", physics->GetType()->classname, NULL, 0 );
  877. } else if ( IsSubclassOf( token, "idEntity" ) ) {
  878. const idEntity *entity = ((idEntity*)varPtr);
  879. Write( varName, varType, scope, prefix, "", va( "entity %d: \'%s\'", entity->entityNumber, entity->name.c_str() ), NULL, 0 );
  880. } else if ( IsSubclassOf( token, "idDecl" ) ) {
  881. const idDecl *decl = ((idDecl *)varPtr);
  882. Write( varName, varType, scope, prefix, "", decl->GetName(), NULL, 0 );
  883. } else if ( pointerDepth == 0 && (
  884. token == "idAFBody" ||
  885. token == "idAFTree" ||
  886. token == "idClipModel" ||
  887. IsSubclassOf( token, "idAFConstraint" )
  888. ) ) {
  889. char newPrefix[1024];
  890. idStr::snPrintf( newPrefix, sizeof( newPrefix ), "%s%s::%s->", prefix, scope, varName );
  891. WriteClass_r( varPtr, "", token, token, newPrefix, pointerDepth + 1 );
  892. } else {
  893. Write( varName, varType, scope, prefix, "", va( "<pointer type '%s' not listed>", varType ), NULL, 0 );
  894. return -1;
  895. }
  896. } else {
  897. const enumTypeInfo_t *enumTypeInfo = FindEnumInfo( scope + ( "::" + token ) );
  898. if ( enumTypeInfo == NULL ) {
  899. enumTypeInfo = FindEnumInfo( token );
  900. }
  901. if ( enumTypeInfo != NULL ) {
  902. typeSize = sizeof( int ); // NOTE: assuming sizeof( enum ) is sizeof( int )
  903. for ( i = 0; enumTypeInfo->values[i].name != NULL; i++ ) {
  904. if ( *((int *)varPtr) == enumTypeInfo->values[i].value ) {
  905. break;
  906. }
  907. }
  908. if ( enumTypeInfo->values[i].name != NULL ) {
  909. Write( varName, varType, scope, prefix, "", enumTypeInfo->values[i].name, NULL, 0 );
  910. } else {
  911. Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), NULL, 0 );
  912. }
  913. } else {
  914. Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), NULL, 0 );
  915. return -1;
  916. }
  917. }
  918. }
  919. i = 0;
  920. do {
  921. if ( *((unsigned long *)varPtr) == 0xcdcdcdcd ) {
  922. common->Warning( "%s%s::%s%s uses uninitialized memory", prefix, scope, varName, "" );
  923. break;
  924. }
  925. } while( ++i < typeSize );
  926. if ( isPointer ) {
  927. return sizeof( void * );
  928. }
  929. return typeSize;
  930. }
  931. /*
  932. ================
  933. idTypeInfoTools::WriteClass_r
  934. ================
  935. */
  936. void idTypeInfoTools::WriteClass_r( const void *classPtr, const char *className, const char *classType, const char *scope, const char *prefix, const int pointerDepth ) {
  937. int i;
  938. const classTypeInfo_t *classInfo = FindClassInfo( classType );
  939. if ( !classInfo ) {
  940. return;
  941. }
  942. if ( *classInfo->superType != '\0' ) {
  943. WriteClass_r( classPtr, className, classInfo->superType, scope, prefix, pointerDepth );
  944. }
  945. for ( i = 0; classInfo->variables[i].name != NULL; i++ ) {
  946. const classVariableInfo_t &classVar = classInfo->variables[i];
  947. void *varPtr = (void *) (((byte *)classPtr) + classVar.offset);
  948. WriteVariable_r( varPtr, classVar.name, classVar.type, classType, prefix, pointerDepth );
  949. }
  950. }
  951. /*
  952. ================
  953. idTypeInfoTools::WriteGameState
  954. ================
  955. */
  956. void idTypeInfoTools::WriteGameState( const char *fileName ) {
  957. int i, num;
  958. idFile *file;
  959. file = fileSystem->OpenFileWrite( fileName );
  960. if ( !file ) {
  961. common->Warning( "couldn't open %s", fileName );
  962. return;
  963. }
  964. fp = file;
  965. Write = WriteGameStateVariable; //WriteVariable;
  966. #ifdef DUMP_GAMELOCAL
  967. file->WriteFloatString( "\ngameLocal {\n" );
  968. WriteClass_r( (void *)&gameLocal, "", "idGameLocal", "idGameLocal", "", 0 );
  969. file->WriteFloatString( "}\n" );
  970. #endif
  971. for ( num = i = 0; i < gameLocal.num_entities; i++ ) {
  972. idEntity *ent = gameLocal.entities[i];
  973. if ( ent == NULL ) {
  974. continue;
  975. }
  976. file->WriteFloatString( "\nentity %d %s {\n", i, ent->GetType()->classname );
  977. WriteClass_r( (void *)ent, "", ent->GetType()->classname, ent->GetType()->classname, "", 0 );
  978. file->WriteFloatString( "}\n" );
  979. num++;
  980. }
  981. fileSystem->CloseFile( file );
  982. common->Printf( "%d entities written\n", num );
  983. }
  984. /*
  985. ================
  986. idTypeInfoTools::CompareGameState
  987. ================
  988. */
  989. void idTypeInfoTools::CompareGameState( const char *fileName ) {
  990. int entityNum;
  991. idToken token;
  992. src = new idLexer();
  993. src->SetFlags( LEXFL_NOSTRINGESCAPECHARS );
  994. if ( !src->LoadFile( fileName ) ) {
  995. common->Warning( "couldn't load %s", fileName );
  996. delete src;
  997. src = NULL;
  998. return;
  999. }
  1000. fp = NULL;
  1001. Write = VerifyVariable;
  1002. #ifdef DUMP_GAMELOCAL
  1003. if ( !src->ExpectTokenString( "gameLocal" ) || !src->ExpectTokenString( "{" ) ) {
  1004. delete src;
  1005. src = NULL;
  1006. return;
  1007. }
  1008. WriteClass_r( (void *)&gameLocal, "", "idGameLocal", "idGameLocal", "", 0 );
  1009. if ( !src->ExpectTokenString( "}" ) ) {
  1010. delete src;
  1011. src = NULL;
  1012. return;
  1013. }
  1014. #endif
  1015. while( src->ReadToken( &token ) ) {
  1016. if ( token != "entity" ) {
  1017. break;
  1018. }
  1019. if ( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) {
  1020. break;
  1021. }
  1022. entityNum = token.GetIntValue();
  1023. if ( entityNum < 0 || entityNum >= gameLocal.num_entities ) {
  1024. src->Warning( "entity number %d out of range", entityNum );
  1025. break;
  1026. }
  1027. typeError = false;
  1028. idEntity *ent = gameLocal.entities[entityNum];
  1029. if ( !ent ) {
  1030. src->Warning( "entity %d is not spawned", entityNum );
  1031. src->SkipBracedSection( true );
  1032. continue;
  1033. }
  1034. if ( !src->ExpectTokenType( TT_NAME, 0, &token ) ) {
  1035. break;
  1036. }
  1037. if ( token.Cmp( ent->GetType()->classname ) != 0 ) {
  1038. src->Warning( "entity %d has wrong type", entityNum );
  1039. src->SkipBracedSection( true );
  1040. continue;
  1041. }
  1042. if ( !src->ExpectTokenString( "{" ) ) {
  1043. src->Warning( "entity %d missing leading {", entityNum );
  1044. break;
  1045. }
  1046. WriteClass_r( (void *)ent, "", ent->GetType()->classname, ent->GetType()->classname, "", 0 );
  1047. if ( !src->SkipBracedSection( false ) ) {
  1048. src->Warning( "entity %d missing trailing }", entityNum );
  1049. break;
  1050. }
  1051. }
  1052. delete src;
  1053. src = NULL;
  1054. }
  1055. /*
  1056. ================
  1057. WriteGameState_f
  1058. ================
  1059. */
  1060. void WriteGameState_f( const idCmdArgs &args ) {
  1061. idStr fileName;
  1062. if ( args.Argc() > 1 ) {
  1063. fileName = args.Argv(1);
  1064. } else {
  1065. fileName = "GameState.txt";
  1066. }
  1067. fileName.SetFileExtension( "gameState.txt" );
  1068. idTypeInfoTools::WriteGameState( fileName );
  1069. }
  1070. /*
  1071. ================
  1072. CompareGameState_f
  1073. ================
  1074. */
  1075. void CompareGameState_f( const idCmdArgs &args ) {
  1076. idStr fileName;
  1077. if ( args.Argc() > 1 ) {
  1078. fileName = args.Argv(1);
  1079. } else {
  1080. fileName = "GameState.txt";
  1081. }
  1082. fileName.SetFileExtension( "gameState.txt" );
  1083. idTypeInfoTools::CompareGameState( fileName );
  1084. }
  1085. /*
  1086. ================
  1087. TestSaveGame_f
  1088. ================
  1089. */
  1090. void TestSaveGame_f( const idCmdArgs &args ) {
  1091. idStr name;
  1092. if ( args.Argc() <= 1 ) {
  1093. gameLocal.Printf( "testSaveGame <mapName>\n" );
  1094. return;
  1095. }
  1096. name = args.Argv( 1 );
  1097. try {
  1098. cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "map %s", name.c_str() ) );
  1099. name.Replace( "\\", "_" );
  1100. name.Replace( "/", "_" );
  1101. cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "saveGame test_%s", name.c_str() ) );
  1102. cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "loadGame test_%s", name.c_str() ) );
  1103. }
  1104. catch( idException & ) {
  1105. // an ERR_DROP was thrown
  1106. }
  1107. cmdSystem->BufferCommandText( CMD_EXEC_NOW, "quit" );
  1108. }
  1109. /*
  1110. ================
  1111. WriteTypeToFile
  1112. ================
  1113. */
  1114. void WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName ) {
  1115. idTypeInfoTools::WriteTypeToFile( fp, typePtr, typeName );
  1116. }
  1117. /*
  1118. ================
  1119. PrintType
  1120. ================
  1121. */
  1122. void PrintType( const void *typePtr, const char *typeName ) {
  1123. idTypeInfoTools::PrintType( typePtr, typeName );
  1124. }
  1125. /*
  1126. ================
  1127. InitTypeVariables
  1128. ================
  1129. */
  1130. void InitTypeVariables( const void *typePtr, const char *typeName, int value ) {
  1131. idTypeInfoTools::InitTypeVariables( typePtr, typeName, value );
  1132. }
  1133. /*
  1134. ================
  1135. ListTypeInfo_f
  1136. ================
  1137. */
  1138. int SortTypeInfoByName( const int *a, const int *b ) {
  1139. return idStr::Icmp( classTypeInfo[*a].typeName, classTypeInfo[*b].typeName );
  1140. }
  1141. int SortTypeInfoBySize( const int *a, const int *b ) {
  1142. if ( classTypeInfo[*a].size < classTypeInfo[*b].size ) {
  1143. return -1;
  1144. }
  1145. if ( classTypeInfo[*a].size > classTypeInfo[*b].size ) {
  1146. return 1;
  1147. }
  1148. return 0;
  1149. }
  1150. void ListTypeInfo_f( const idCmdArgs &args ) {
  1151. int i, j;
  1152. idList<int> index;
  1153. common->Printf( "%-32s : %-32s size (B)\n", "type name", "super type name" );
  1154. for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
  1155. index.Append( i );
  1156. }
  1157. if ( args.Argc() > 1 && idStr::Icmp( args.Argv( 1 ), "size" ) == 0 ) {
  1158. index.Sort( SortTypeInfoBySize );
  1159. } else {
  1160. index.Sort( SortTypeInfoByName );
  1161. }
  1162. for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
  1163. j = index[i];
  1164. common->Printf( "%-32s : %-32s %d\n", classTypeInfo[j].typeName, classTypeInfo[j].superType, classTypeInfo[j].size );
  1165. }
  1166. }