2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 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.
24 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.
26 ===========================================================================
29 // This is real evil but allows the code to inspect arbitrary class variables.
30 #define private public
31 #define protected public
33 #include "../../idlib/precompiled.h"
36 #include "../Game_local.h"
38 #ifdef ID_DEBUG_MEMORY
39 #include "GameTypeInfo.h" // Make sure this is up to date!
41 #include "NoGameTypeInfo.h"
44 // disabled because it's adds about 64MB to state dumps and takes a really long time
45 //#define DUMP_GAMELOCAL
48 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 );
51 class idTypeInfoTools {
53 static const classTypeInfo_t * FindClassInfo( const char *typeName );
54 static const enumTypeInfo_t * FindEnumInfo( const char *typeName );
55 static bool IsSubclassOf( const char *typeName, const char *superType );
56 static void PrintType( const void *typePtr, const char *typeName );
57 static void WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName );
58 static void InitTypeVariables( const void *typePtr, const char *typeName, int value );
59 static void WriteGameState( const char *fileName );
60 static void CompareGameState( const char *fileName );
65 static WriteVariableType_t Write;
67 static bool typeError;
69 static const char * OutputString( const char *string );
70 static bool ParseTemplateArguments( idLexer &src, idStr &arguments );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 static int WriteVariable_r( const void *varPtr, const char *varName, const char *varType, const char *scope, const char *prefix, const int pointerDepth );
77 static void WriteClass_r( const void *classPtr, const char *className, const char *classType, const char *scope, const char *prefix, const int pointerDepth );
80 idFile * idTypeInfoTools::fp = NULL;
81 int idTypeInfoTools::initValue = 0;
82 WriteVariableType_t idTypeInfoTools::Write = NULL;
83 idLexer * idTypeInfoTools::src = NULL;
84 bool idTypeInfoTools::typeError = false;
92 const char *GetTypeVariableName( const char *typeName, int offset ) {
93 static char varName[1024];
96 for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
97 if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) {
98 if ( classTypeInfo[i].variables[0].name != NULL && offset >= classTypeInfo[i].variables[0].offset ) {
101 typeName = classTypeInfo[i].superType;
102 if ( *typeName == '\0' ) {
109 const classTypeInfo_t &classInfo = classTypeInfo[i];
111 for ( i = 0; classInfo.variables[i].name != NULL; i++ ) {
112 if ( offset <= classInfo.variables[i].offset ) {
117 idStr::snPrintf( varName, sizeof( varName ), "%s::<unknown>", classInfo.typeName );
119 idStr::snPrintf( varName, sizeof( varName ), "%s::%s", classInfo.typeName, classInfo.variables[i-1].name );
126 idTypeInfoTools::FindClassInfo
129 const classTypeInfo_t *idTypeInfoTools::FindClassInfo( const char *typeName ) {
132 for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
133 if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) {
134 return &classTypeInfo[i];
142 idTypeInfoTools::FindEnumInfo
145 const enumTypeInfo_t *idTypeInfoTools::FindEnumInfo( const char *typeName ) {
148 for ( i = 0; enumTypeInfo[i].typeName != NULL; i++ ) {
149 if ( idStr::Cmp( typeName, enumTypeInfo[i].typeName ) == 0 ) {
150 return &enumTypeInfo[i];
158 idTypeInfoTools::IsSubclassOf
161 bool idTypeInfoTools::IsSubclassOf( const char *typeName, const char *superType ) {
164 while( *typeName != '\0' ) {
165 if ( idStr::Cmp( typeName, superType ) == 0 ) {
168 for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
169 if ( idStr::Cmp( typeName, classTypeInfo[i].typeName ) == 0 ) {
170 typeName = classTypeInfo[i].superType;
174 if ( classTypeInfo[i].typeName == NULL ) {
175 common->Warning( "super class %s not found", typeName );
184 idTypeInfoTools::OutputString
187 const char *idTypeInfoTools::OutputString( const char *string ) {
188 static int index = 0;
189 static char buffers[4][16384];
193 out = buffers[index];
194 index = ( index + 1 ) & 3;
196 if ( string == NULL ) {
200 for ( i = 0; i < sizeof( buffers[0] ) - 2; i++ ) {
203 case '\0': out[i] = '\0'; return out;
204 case '\\': out[i++] = '\\'; out[i] = '\\'; break;
205 case '\n': out[i++] = '\\'; out[i] = 'n'; break;
206 case '\r': out[i++] = '\\'; out[i] = 'r'; break;
207 case '\t': out[i++] = '\\'; out[i] = 't'; break;
208 case '\v': out[i++] = '\\'; out[i] = 'v'; break;
209 default: out[i] = c; break;
218 idTypeInfoTools::ParseTemplateArguments
221 bool idTypeInfoTools::ParseTemplateArguments( idLexer &src, idStr &arguments ) {
227 if ( !src.ExpectTokenString( "<" ) ) {
233 if ( !src.ReadToken( &token ) ) {
236 if ( token == "<" ) {
238 } else if ( token == ">" ) {
241 if ( arguments.Length() ) {
252 idTypeInfoTools::PrintType
255 void idTypeInfoTools::PrintType( const void *typePtr, const char *typeName ) {
256 idTypeInfoTools::fp = NULL;
257 idTypeInfoTools::initValue = 0;
258 idTypeInfoTools::Write = PrintVariable;
259 WriteClass_r( typePtr, "", typeName, "", "", 0 );
264 idTypeInfoTools::WriteTypeToFile
267 void idTypeInfoTools::WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName ) {
268 idTypeInfoTools::fp = fp;
269 idTypeInfoTools::initValue = 0;
270 idTypeInfoTools::Write = WriteVariable;
271 WriteClass_r( typePtr, "", typeName, "", "", 0 );
276 idTypeInfoTools::InitTypeVariables
279 void idTypeInfoTools::InitTypeVariables( const void *typePtr, const char *typeName, int value ) {
280 idTypeInfoTools::fp = NULL;
281 idTypeInfoTools::initValue = value;
282 idTypeInfoTools::Write = InitVariable;
283 WriteClass_r( typePtr, "", typeName, "", "", 0 );
288 IsAllowedToChangedFromSaveGames
291 bool IsAllowedToChangedFromSaveGames( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value ) {
292 if ( idStr::Icmp( scope, "idAnimator" ) == 0 ) {
293 if ( idStr::Icmp( varName, "forceUpdate" ) == 0 ) {
296 if ( idStr::Icmp( varName, "lastTransformTime" ) == 0 ) {
299 if ( idStr::Icmp( varName, "AFPoseTime" ) == 0 ) {
302 if ( idStr::Icmp( varName, "frameBounds" ) == 0 ) {
305 } else if ( idStr::Icmp( scope, "idClipModel" ) == 0 ) {
306 if ( idStr::Icmp( varName, "touchCount" ) == 0 ) {
309 } else if ( idStr::Icmp( scope, "idEntity" ) == 0 ) {
310 if ( idStr::Icmp( varName, "numPVSAreas" ) == 0 ) {
313 if ( idStr::Icmp( varName, "renderView" ) == 0 ) {
316 } else if ( idStr::Icmp( scope, "idBrittleFracture" ) == 0 ) {
317 if ( idStr::Icmp( varName, "changed" ) == 0 ) {
320 } else if ( idStr::Icmp( scope, "idPhysics_AF" ) == 0 ) {
322 } else if ( idStr::Icmp( scope, "renderEntity_t" ) == 0 ) {
323 // These get fixed up when UpdateVisuals is called
324 if ( idStr::Icmp( varName, "origin" ) == 0 ) {
327 if ( idStr::Icmp( varName, "axis" ) == 0 ) {
330 if ( idStr::Icmp( varName, "bounds" ) == 0 ) {
335 if ( idStr::Icmpn( prefix, "idAFEntity_Base::af.idAF::physicsObj.idPhysics_AF", 49) == 0 ) {
344 IsRenderHandleVariable
347 bool IsRenderHandleVariable( const char *varName, const char *varType, const char *scope, const char *prefix, const char *postfix, const char *value ) {
348 if ( idStr::Icmp( scope, "idClipModel" ) == 0 ) {
349 if ( idStr::Icmp( varName, "renderModelHandle" ) == 0 ) {
352 } else if ( idStr::Icmp( scope, "idFXLocalAction" ) == 0 ) {
353 if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) {
356 if ( idStr::Icmp( varName, "modelDefHandle" ) == 0 ) {
359 } else if ( idStr::Icmp( scope, "idEntity" ) == 0 ) {
360 if ( idStr::Icmp( varName, "modelDefHandle" ) == 0 ) {
363 } else if ( idStr::Icmp( scope, "idLight" ) == 0 ) {
364 if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) {
367 } else if ( idStr::Icmp( scope, "idAFEntity_Gibbable" ) == 0 ) {
368 if ( idStr::Icmp( varName, "skeletonModelDefHandle" ) == 0 ) {
371 } else if ( idStr::Icmp( scope, "idAFEntity_SteamPipe" ) == 0 ) {
372 if ( idStr::Icmp( varName, "steamModelHandle" ) == 0 ) {
375 } else if ( idStr::Icmp( scope, "idItem" ) == 0 ) {
376 if ( idStr::Icmp( varName, "itemShellHandle" ) == 0 ) {
379 } else if ( idStr::Icmp( scope, "idExplodingBarrel" ) == 0 ) {
380 if ( idStr::Icmp( varName, "particleModelDefHandle" ) == 0 ) {
383 if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) {
386 } else if ( idStr::Icmp( scope, "idProjectile" ) == 0 ) {
387 if ( idStr::Icmp( varName, "lightDefHandle" ) == 0 ) {
390 } else if ( idStr::Icmp( scope, "idBFGProjectile" ) == 0 ) {
391 if ( idStr::Icmp( varName, "secondModelDefHandle" ) == 0 ) {
394 } else if ( idStr::Icmp( scope, "idSmokeParticles" ) == 0 ) {
395 if ( idStr::Icmp( varName, "renderEntityHandle" ) == 0 ) {
398 } else if ( idStr::Icmp( scope, "idWeapon" ) == 0 ) {
399 if ( idStr::Icmp( varName, "muzzleFlashHandle" ) == 0 ) {
402 if ( idStr::Icmp( varName, "worldMuzzleFlashHandle" ) == 0 ) {
405 if ( idStr::Icmp( varName, "guiLightHandle" ) == 0 ) {
408 if ( idStr::Icmp( varName, "nozzleGlowHandle" ) == 0 ) {
417 idTypeInfoTools::PrintVariable
420 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 ) {
421 common->Printf( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value );
426 idTypeInfoTools::WriteVariable
429 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 ) {
431 for ( int i = idStr::FindChar( value, '#', 0 ); i >= 0; i = idStr::FindChar( value, '#', i+1 ) ) {
432 if ( idStr::Icmpn( value+i+1, "INF", 3 ) == 0 ||
433 idStr::Icmpn( value+i+1, "IND", 3 ) == 0 ||
434 idStr::Icmpn( value+i+1, "NAN", 3 ) == 0 ||
435 idStr::Icmpn( value+i+1, "QNAN", 4 ) == 0 ||
436 idStr::Icmpn( value+i+1, "SNAN", 4 ) == 0 ) {
437 common->Warning( "%s%s::%s%s = \"%s\"", prefix, scope, varName, postfix, value );
441 fp->WriteFloatString( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value );
446 idTypeInfoTools::WriteGameStateVariable
449 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 ) {
451 for ( int i = idStr::FindChar( value, '#', 0 ); i >= 0; i = idStr::FindChar( value, '#', i+1 ) ) {
452 if ( idStr::Icmpn( value+i+1, "INF", 3 ) == 0 ||
453 idStr::Icmpn( value+i+1, "IND", 3 ) == 0 ||
454 idStr::Icmpn( value+i+1, "NAN", 3 ) == 0 ||
455 idStr::Icmpn( value+i+1, "QNAN", 4 ) == 0 ||
456 idStr::Icmpn( value+i+1, "SNAN", 4 ) == 0 ) {
457 common->Warning( "%s%s::%s%s = \"%s\"", prefix, scope, varName, postfix, value );
462 if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) {
466 if ( IsAllowedToChangedFromSaveGames( varName, varType, scope, prefix, postfix, value ) ) {
470 fp->WriteFloatString( "%s%s::%s%s = \"%s\"\n", prefix, scope, varName, postfix, value );
475 idTypeInfoTools::InitVariable
478 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 ) {
479 if ( varPtr != NULL && varSize > 0 ) {
480 // NOTE: skip renderer handles
481 if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) {
484 memset( const_cast<void*>(varPtr), initValue, varSize );
490 idTypeInfoTools::VerifyVariable
493 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 ) {
500 src->SkipUntilString( "=" );
501 src->ExpectTokenType( TT_STRING, 0, &token );
502 if ( token.Cmp( value ) != 0 ) {
504 // NOTE: skip several things
506 if ( IsRenderHandleVariable( varName, varType, scope, prefix, postfix, value ) ) {
510 if ( IsAllowedToChangedFromSaveGames( varName, varType, scope, prefix, postfix, value ) ) {
514 src->Warning( "state diff for %s%s::%s%s\n%s\n%s", prefix, scope, varName, postfix, token.c_str(), value );
521 idTypeInfoTools::WriteVariable_r
524 int idTypeInfoTools::WriteVariable_r( const void *varPtr, const char *varName, const char *varType, const char *scope, const char *prefix, const int pointerDepth ) {
525 int i, isPointer, typeSize;
528 idStr typeString, templateArgs;
533 // create a type string without 'const', 'mutable', 'class', 'struct', 'union'
534 typeSrc.LoadMemory( varType, idStr::Length( varType ), varName );
535 while( typeSrc.ReadToken( &token ) ) {
536 if ( token != "const" && token != "mutable" && token != "class" && token != "struct" && token != "union" ) {
537 typeString += token + " ";
540 typeString.StripTrailing( ' ' );
541 typeSrc.FreeSource();
543 // if this is an array
544 if ( typeString[typeString.Length() - 1] == ']' ) {
545 for ( i = typeString.Length(); i > 0 && typeString[i - 1] != '['; i-- ) {
547 int num = atoi( &typeString[i] );
548 idStr listVarType = typeString;
549 listVarType.CapLength( i - 1 );
551 for ( i = 0; i < num; i++ ) {
552 idStr listVarName = va( "%s[%d]", varName, i );
553 int size = WriteVariable_r( varPtr, listVarName, listVarType, scope, prefix, pointerDepth );
558 varPtr = (void *)( ( (byte *) varPtr ) + size );
563 // if this is a pointer
565 for ( i = typeString.Length(); i > 0 && typeString[i - 1] == '*'; i -= 2 ) {
566 if ( varPtr == (void *)0xcdcdcdcd || ( varPtr != NULL && *((unsigned long *)varPtr) == 0xcdcdcdcd ) ) {
567 common->Warning( "%s%s::%s%s references uninitialized memory", prefix, scope, varName, "" );
570 if ( varPtr != NULL ) {
571 varPtr = *((void **)varPtr);
576 if ( varPtr == NULL ) {
577 Write( varName, varType, scope, prefix, "", "<NULL>", varPtr, 0 );
578 return sizeof( void * );
581 typeSrc.LoadMemory( typeString, typeString.Length(), varName );
583 if ( !typeSrc.ReadToken( &token ) ) {
584 Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
589 while( typeSrc.CheckTokenString( "::" ) ) {
591 typeSrc.ExpectTokenType( TT_NAME, 0, &newToken );
592 token += "::" + newToken;
595 if ( token == "signed" ) {
597 if ( !typeSrc.ReadToken( &token ) ) {
598 Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
601 if ( token == "char" ) {
603 typeSize = sizeof( signed char );
604 Write( varName, varType, scope, prefix, "", va( "%d", *((signed char *)varPtr) ), varPtr, typeSize );
606 } else if ( token == "short" ) {
608 typeSize = sizeof( signed short );
609 Write( varName, varType, scope, prefix, "", va( "%d", *((signed short *)varPtr) ), varPtr, typeSize );
611 } else if ( token == "int" ) {
613 typeSize = sizeof( signed int );
614 Write( varName, varType, scope, prefix, "", va( "%d", *((signed int *)varPtr) ), varPtr, typeSize );
616 } else if ( token == "long" ) {
618 typeSize = sizeof( signed long );
619 Write( varName, varType, scope, prefix, "", va( "%ld", *((signed long *)varPtr) ), varPtr, typeSize );
623 Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
627 } else if ( token == "unsigned" ) {
629 if ( !typeSrc.ReadToken( &token ) ) {
630 Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
633 if ( token == "char" ) {
635 typeSize = sizeof( unsigned char );
636 Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned char *)varPtr) ), varPtr, typeSize );
638 } else if ( token == "short" ) {
640 typeSize = sizeof( unsigned short );
641 Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned short *)varPtr) ), varPtr, typeSize );
643 } else if ( token == "int" ) {
645 typeSize = sizeof( unsigned int );
646 Write( varName, varType, scope, prefix, "", va( "%d", *((unsigned int *)varPtr) ), varPtr, typeSize );
648 } else if ( token == "long" ) {
650 typeSize = sizeof( unsigned long );
651 Write( varName, varType, scope, prefix, "", va( "%lu", *((unsigned long *)varPtr) ), varPtr, typeSize );
655 Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), varPtr, 0 );
659 } else if ( token == "byte" ) {
661 typeSize = sizeof( byte );
662 Write( varName, varType, scope, prefix, "", va( "%d", *((byte *)varPtr) ), varPtr, typeSize );
664 } else if ( token == "word" ) {
666 typeSize = sizeof( word );
667 Write( varName, varType, scope, prefix, "", va( "%d", *((word *)varPtr) ), varPtr, typeSize );
669 } else if ( token == "dword" ) {
671 typeSize = sizeof( dword );
672 Write( varName, varType, scope, prefix, "", va( "%d", *((dword *)varPtr) ), varPtr, typeSize );
674 } else if ( token == "bool" ) {
676 typeSize = sizeof( bool );
677 Write( varName, varType, scope, prefix, "", va( "%d", *((bool *)varPtr) ), varPtr, typeSize );
679 } else if ( token == "char" ) {
681 typeSize = sizeof( char );
682 Write( varName, varType, scope, prefix, "", va( "%d", *((char *)varPtr) ), varPtr, typeSize );
684 } else if ( token == "short" ) {
686 typeSize = sizeof( short );
687 Write( varName, varType, scope, prefix, "", va( "%d", *((short *)varPtr) ), varPtr, typeSize );
689 } else if ( token == "int" ) {
691 typeSize = sizeof( int );
692 Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize );
694 } else if ( token == "long" ) {
696 typeSize = sizeof( long );
697 Write( varName, varType, scope, prefix, "", va( "%ld", *((long *)varPtr) ), varPtr, typeSize );
699 } else if ( token == "float" ) {
701 typeSize = sizeof( float );
702 Write( varName, varType, scope, prefix, "", idStr( *((float *)varPtr) ).c_str(), varPtr, typeSize );
704 } else if ( token == "double" ) {
706 typeSize = sizeof( double );
707 Write( varName, varType, scope, prefix, "", idStr( (float)*((double *)varPtr) ).c_str(), varPtr, typeSize );
709 } else if ( token == "idVec2" ) {
711 typeSize = sizeof( idVec2 );
712 Write( varName, varType, scope, prefix, "", ((idVec2 *)varPtr)->ToString( 8 ), varPtr, typeSize );
714 } else if ( token == "idVec3" ) {
716 typeSize = sizeof( idVec3 );
717 Write( varName, varType, scope, prefix, "", ((idVec3 *)varPtr)->ToString( 8 ), varPtr, typeSize );
719 } else if ( token == "idVec4" ) {
721 typeSize = sizeof( idVec4 );
722 Write( varName, varType, scope, prefix, "", ((idVec4 *)varPtr)->ToString( 8 ), varPtr, typeSize );
724 } else if ( token == "idVec5" ) {
726 typeSize = sizeof( idVec5 );
727 Write( varName, varType, scope, prefix, "", ((idVec5 *)varPtr)->ToString( 8 ), varPtr, typeSize );
729 } else if ( token == "idVec6" ) {
731 typeSize = sizeof( idVec6 );
732 Write( varName, varType, scope, prefix, "", ((idVec6 *)varPtr)->ToString( 8 ), varPtr, typeSize );
734 } else if ( token == "idVecX" ) {
736 const idVecX *vec = ((idVecX *)varPtr);
737 if ( vec->ToFloatPtr() != NULL ) {
738 Write( varName, varType, scope, prefix, "", vec->ToString( 8 ), vec->ToFloatPtr(), vec->GetSize() * sizeof( float ) );
740 Write( varName, varType, scope, prefix, "", "<NULL>", varPtr, 0 );
742 typeSize = sizeof( idVecX );
744 } else if ( token == "idMat2" ) {
746 typeSize = sizeof( idMat2 );
747 Write( varName, varType, scope, prefix, "", ((idMat2 *)varPtr)->ToString( 8 ), varPtr, typeSize );
749 } else if ( token == "idMat3" ) {
751 typeSize = sizeof( idMat3 );
752 Write( varName, varType, scope, prefix, "", ((idMat3 *)varPtr)->ToString( 8 ), varPtr, typeSize );
754 } else if ( token == "idMat4" ) {
756 typeSize = sizeof( idMat4 );
757 Write( varName, varType, scope, prefix, "", ((idMat4 *)varPtr)->ToString( 8 ), varPtr, typeSize );
759 } else if ( token == "idMat5" ) {
761 typeSize = sizeof( idMat5 );
762 Write( varName, varType, scope, prefix, "", ((idMat5 *)varPtr)->ToString( 8 ), varPtr, typeSize );
764 } else if ( token == "idMat6" ) {
766 typeSize = sizeof( idMat6 );
767 Write( varName, varType, scope, prefix, "", ((idMat6 *)varPtr)->ToString( 8 ), varPtr, typeSize );
769 } else if ( token == "idMatX" ) {
771 typeSize = sizeof( idMatX );
772 const idMatX *mat = ((idMatX *)varPtr);
773 if ( mat->ToFloatPtr() != NULL ) {
774 Write( varName, varType, scope, prefix, "", mat->ToString( 8 ), mat->ToFloatPtr(), mat->GetNumColumns() * mat->GetNumRows() * sizeof( float ) );
776 Write( varName, varType, scope, prefix, "", "<NULL>", NULL, 0 );
779 } else if ( token == "idAngles" ) {
781 typeSize = sizeof( idAngles );
782 Write( varName, varType, scope, prefix, "", ((idAngles *)varPtr)->ToString( 8 ), varPtr, typeSize );
784 } else if ( token == "idQuat" ) {
786 typeSize = sizeof( idQuat );
787 Write( varName, varType, scope, prefix, "", ((idQuat *)varPtr)->ToString( 8 ), varPtr, typeSize );
789 } else if ( token == "idBounds" ) {
791 typeSize = sizeof( idBounds );
792 const idBounds *bounds = ((idBounds *)varPtr);
793 if ( bounds->IsCleared() ) {
794 Write( varName, varType, scope, prefix, "", "<cleared>", varPtr, typeSize );
796 Write( varName, varType, scope, prefix, "", va( "(%s)-(%s)", (*bounds)[0].ToString( 8 ), (*bounds)[1].ToString( 8 ) ), varPtr, typeSize );
799 } else if ( token == "idList" ) {
801 idList<int> *list = ((idList<int> *)varPtr);
802 Write( varName, varType, scope, prefix, ".num", va( "%d", list->Num() ), NULL, 0 );
803 // NOTE: we don't care about the amount of memory allocated
804 //Write( varName, varType, scope, prefix, ".size", va( "%d", list->Size() ), NULL, 0 );
805 Write( varName, varType, scope, prefix, ".granularity", va( "%d", list->GetGranularity() ), NULL, 0 );
807 if ( list->Num() && ParseTemplateArguments( typeSrc, templateArgs ) ) {
808 void *listVarPtr = list->Ptr();
809 for ( i = 0; i < list->Num(); i++ ) {
810 idStr listVarName = va( "%s[%d]", varName, i );
811 int size = WriteVariable_r( listVarPtr, listVarName, templateArgs, scope, prefix, pointerDepth );
815 listVarPtr = (void *)( ( (byte *) listVarPtr ) + size );
819 typeSize = sizeof( idList<int> );
821 } else if ( token == "idStaticList" ) {
823 idStaticList<int, 1> *list = ((idStaticList<int, 1> *)varPtr);
824 Write( varName, varType, scope, prefix, ".num", va( "%d", list->Num() ), NULL, 0 );
827 if ( list->Num() && ParseTemplateArguments( typeSrc, templateArgs ) ) {
828 void *listVarPtr = list->Ptr();
829 for ( i = 0; i < list->Num(); i++ ) {
830 idStr listVarName = va( "%s[%d]", varName, i );
831 int size = WriteVariable_r( listVarPtr, listVarName, templateArgs, scope, prefix, pointerDepth );
836 listVarPtr = (void *)( ( (byte *) listVarPtr ) + size );
840 typeSize = sizeof( int ) + totalSize;
842 } else if ( token == "idLinkList" ) {
845 typeSize = sizeof( idLinkList<idEntity> );
846 Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), NULL, 0 );
848 } else if ( token == "idStr" ) {
850 typeSize = sizeof( idStr );
852 const idStr *str = ((idStr *)varPtr);
853 Write( varName, varType, scope, prefix, "", OutputString( str->c_str() ), str->c_str(), str->Length() );
855 } else if ( token == "idStrList" ) {
857 typeSize = sizeof( idStrList );
859 const idStrList *list = ((idStrList *)varPtr);
861 for ( i = 0; i < list->Num(); i++ ) {
862 Write( varName, varType, scope, prefix, va("[%d]", i ), OutputString( (*list)[i].c_str() ), (*list)[i].c_str(), (*list)[i].Length() );
865 Write( varName, varType, scope, prefix, "", "<empty>", NULL, 0 );
868 } else if ( token == "idDict" ) {
870 typeSize = sizeof( idDict );
872 const idDict *dict = ((idDict *)varPtr);
873 if ( dict->GetNumKeyVals() ) {
874 for ( i = 0; i < dict->GetNumKeyVals(); i++ ) {
875 const idKeyValue *kv = dict->GetKeyVal( i );
876 Write( varName, varType, scope, prefix, va("[%d]", i ), va( "\'%s\' \'%s\'", OutputString( kv->GetKey().c_str() ), OutputString( kv->GetValue().c_str() ) ), NULL, 0 );
879 Write( varName, varType, scope, prefix, "", "<empty>", NULL, 0 );
882 } else if ( token == "idExtrapolate" ) {
884 const idExtrapolate<float> *interpolate = ((idExtrapolate<float> *)varPtr);
885 Write( varName, varType, scope, prefix, ".extrapolationType", idStr( interpolate->GetExtrapolationType() ).c_str(), &interpolate->extrapolationType, sizeof( interpolate->extrapolationType ) );
886 Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) );
887 Write( varName, varType, scope, prefix, ".duration", idStr( interpolate->GetDuration() ).c_str(), &interpolate->duration, sizeof( interpolate->duration ) );
889 if ( ParseTemplateArguments( typeSrc, templateArgs ) ) {
890 if ( templateArgs == "int" ) {
891 const idExtrapolate<int> *interpolate = ((idExtrapolate<int> *)varPtr);
892 Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
893 Write( varName, varType, scope, prefix, ".baseSpeed", idStr( interpolate->GetBaseSpeed() ).c_str(), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) );
894 Write( varName, varType, scope, prefix, ".speed", idStr( interpolate->GetSpeed() ).c_str(), &interpolate->speed, sizeof( interpolate->speed ) );
895 typeSize = sizeof( idExtrapolate<int> );
896 } else if ( templateArgs == "float" ) {
897 const idExtrapolate<float> *interpolate = ((idExtrapolate<float> *)varPtr);
898 Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
899 Write( varName, varType, scope, prefix, ".baseSpeed", idStr( interpolate->GetBaseSpeed() ).c_str(), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) );
900 Write( varName, varType, scope, prefix, ".speed", idStr( interpolate->GetSpeed() ).c_str(), &interpolate->speed, sizeof( interpolate->speed ) );
901 typeSize = sizeof( idExtrapolate<float> );
902 } else if ( templateArgs == "idVec3" ) {
903 const idExtrapolate<idVec3> *interpolate = ((idExtrapolate<idVec3> *)varPtr);
904 Write( varName, varType, scope, prefix, ".startValue", interpolate->GetStartValue().ToString( 8 ), &interpolate->startValue, sizeof( interpolate->startValue ) );
905 Write( varName, varType, scope, prefix, ".baseSpeed", interpolate->GetBaseSpeed().ToString( 8 ), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) );
906 Write( varName, varType, scope, prefix, ".speed", interpolate->GetSpeed().ToString( 8 ), &interpolate->speed, sizeof( interpolate->speed ) );
907 typeSize = sizeof( idExtrapolate<idVec3> );
908 } else if ( templateArgs == "idAngles" ) {
909 const idExtrapolate<idAngles> *interpolate = ((idExtrapolate<idAngles> *)varPtr);
910 Write( varName, varType, scope, prefix, ".startValue", interpolate->GetStartValue().ToString( 8 ), &interpolate->startValue, sizeof( interpolate->startValue ) );
911 Write( varName, varType, scope, prefix, ".baseSpeed", interpolate->GetBaseSpeed().ToString( 8 ), &interpolate->baseSpeed, sizeof( interpolate->baseSpeed ) );
912 Write( varName, varType, scope, prefix, ".speed", interpolate->GetSpeed().ToString( 8 ), &interpolate->speed, sizeof( interpolate->speed ) );
913 typeSize = sizeof( idExtrapolate<idAngles> );
915 Write( varName, varType, scope, prefix, "", va( "<unknown template argument type '%s' for idExtrapolate>", templateArgs.c_str() ), NULL, 0 );
919 } else if ( token == "idInterpolate" ) {
921 const idInterpolate<float> *interpolate = ((idInterpolate<float> *)varPtr);
922 Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) );
923 Write( varName, varType, scope, prefix, ".duration", idStr( interpolate->GetDuration() ).c_str(), &interpolate->duration, sizeof( interpolate->duration ) );
925 if ( ParseTemplateArguments( typeSrc, templateArgs ) ) {
926 if ( templateArgs == "int" ) {
927 const idInterpolate<int> *interpolate = ((idInterpolate<int> *)varPtr);
928 Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
929 Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
930 typeSize = sizeof( idInterpolate<int> );
931 } else if ( templateArgs == "float" ) {
932 const idInterpolate<float> *interpolate = ((idInterpolate<float> *)varPtr);
933 Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
934 Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
935 typeSize = sizeof( idInterpolate<float> );
937 Write( varName, varType, scope, prefix, "", va( "<unknown template argument type '%s' for idInterpolate>", templateArgs.c_str() ), NULL, 0 );
941 } else if ( token == "idInterpolateAccelDecelLinear" ) {
943 const idInterpolateAccelDecelLinear<float> *interpolate = ((idInterpolateAccelDecelLinear<float> *)varPtr);
944 Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) );
945 Write( varName, varType, scope, prefix, ".accelTime", idStr( interpolate->GetAcceleration() ).c_str(), &interpolate->accelTime, sizeof( interpolate->accelTime ) );
946 Write( varName, varType, scope, prefix, ".linearTime", idStr( interpolate->linearTime ).c_str(), &interpolate->linearTime, sizeof( interpolate->linearTime ) );
947 Write( varName, varType, scope, prefix, ".decelTime", idStr( interpolate->GetDeceleration() ).c_str(), &interpolate->decelTime, sizeof( interpolate->decelTime ) );
949 if ( ParseTemplateArguments( typeSrc, templateArgs ) ) {
950 if ( templateArgs == "int" ) {
951 const idInterpolateAccelDecelLinear<int> *interpolate = ((idInterpolateAccelDecelLinear<int> *)varPtr);
952 Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
953 Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
954 typeSize = sizeof( idInterpolateAccelDecelLinear<int> );
955 } else if ( templateArgs == "float" ) {
956 const idInterpolateAccelDecelLinear<float> *interpolate = ((idInterpolateAccelDecelLinear<float> *)varPtr);
957 Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
958 Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
959 typeSize = sizeof( idInterpolateAccelDecelLinear<float> );
961 Write( varName, varType, scope, prefix, "", va( "<unknown template argument type '%s' for idInterpolateAccelDecelLinear>", templateArgs.c_str() ), NULL, 0 );
965 } else if ( token == "idInterpolateAccelDecelSine" ) {
967 const idInterpolateAccelDecelSine<float> *interpolate = ((idInterpolateAccelDecelSine<float> *)varPtr);
968 Write( varName, varType, scope, prefix, ".startTime", idStr( interpolate->GetStartTime() ).c_str(), &interpolate->startTime, sizeof( interpolate->startTime ) );
969 Write( varName, varType, scope, prefix, ".accelTime", idStr( interpolate->GetAcceleration() ).c_str(), &interpolate->accelTime, sizeof( interpolate->accelTime ) );
970 Write( varName, varType, scope, prefix, ".linearTime", idStr( interpolate->linearTime ).c_str(), &interpolate->linearTime, sizeof( interpolate->linearTime ) );
971 Write( varName, varType, scope, prefix, ".decelTime", idStr( interpolate->GetDeceleration() ).c_str(), &interpolate->decelTime, sizeof( interpolate->decelTime ) );
973 if ( ParseTemplateArguments( typeSrc, templateArgs ) ) {
974 if ( templateArgs == "int" ) {
975 const idInterpolateAccelDecelSine<int> *interpolate = ((idInterpolateAccelDecelSine<int> *)varPtr);
976 Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
977 Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
978 typeSize = sizeof( idInterpolateAccelDecelSine<int> );
979 } else if ( templateArgs == "float" ) {
980 const idInterpolateAccelDecelSine<float> *interpolate = ((idInterpolateAccelDecelSine<float> *)varPtr);
981 Write( varName, varType, scope, prefix, ".startValue", idStr( interpolate->GetStartValue() ).c_str(), &interpolate->startValue, sizeof( interpolate->startValue ) );
982 Write( varName, varType, scope, prefix, ".endValue", idStr( interpolate->GetEndValue() ).c_str(), &interpolate->endValue, sizeof( interpolate->endValue ) );
983 typeSize = sizeof( idInterpolateAccelDecelSine<float> );
985 Write( varName, varType, scope, prefix, "", va( "<unknown template argument type '%s' for idInterpolateAccelDecelSine>", templateArgs.c_str() ), NULL, 0 );
989 } else if ( token == "idUserInterface" ) {
991 typeSize = sizeof( idUserInterface );
992 const idUserInterface *gui = ((idUserInterface *)varPtr);
993 Write( varName, varType, scope, prefix, "", gui->Name(), varPtr, sizeof( varPtr ) );
995 } else if ( token == "idRenderModel" ) {
997 typeSize = sizeof( idRenderModel );
998 const idRenderModel *model = ((idRenderModel *)varPtr);
999 Write( varName, varType, scope, prefix, "", model->Name(), varPtr, sizeof( varPtr ) );
1001 } else if ( token == "qhandle_t" ) {
1003 typeSize = sizeof( int );
1004 Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize );
1006 } else if ( token == "cmHandle_t" ) {
1008 typeSize = sizeof( int );
1009 Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), varPtr, typeSize );
1011 } else if ( token == "idEntityPtr" ) {
1013 typeSize = sizeof( idEntityPtr<idEntity> );
1015 const idEntityPtr<idEntity> *entPtr = ((idEntityPtr<idEntity> *)varPtr);
1016 if ( entPtr->GetEntity() ) {
1017 idEntity *entity = entPtr->GetEntity();
1018 Write( varName, varType, scope, prefix, ".", va( "entity %d: \'%s\'", entity->entityNumber, entity->name.c_str() ), varPtr, typeSize );
1020 Write( varName, varType, scope, prefix, "", "<NULL>", varPtr, typeSize );
1023 } else if ( token == "idEntity::entityFlags_s" ) {
1025 const idEntity::entityFlags_s *flags = ((idEntity::entityFlags_s *)varPtr);
1026 Write( varName, varType, scope, prefix, ".notarget", flags->notarget ? "true" : "false", NULL, 0 );
1027 Write( varName, varType, scope, prefix, ".noknockback", flags->noknockback ? "true" : "false", NULL, 0 );
1028 Write( varName, varType, scope, prefix, ".takedamage", flags->takedamage ? "true" : "false", NULL, 0 );
1029 Write( varName, varType, scope, prefix, ".hidden", flags->hidden ? "true" : "false", NULL, 0 );
1030 Write( varName, varType, scope, prefix, ".bindOrientated", flags->bindOrientated ? "true" : "false", NULL, 0 );
1031 Write( varName, varType, scope, prefix, ".solidForTeam", flags->solidForTeam ? "true" : "false", NULL, 0 );
1032 Write( varName, varType, scope, prefix, ".forcePhysicsUpdate", flags->forcePhysicsUpdate ? "true" : "false", NULL, 0 );
1033 Write( varName, varType, scope, prefix, ".selected", flags->selected ? "true" : "false", NULL, 0 );
1034 Write( varName, varType, scope, prefix, ".neverDormant", flags->neverDormant ? "true" : "false", NULL, 0 );
1035 Write( varName, varType, scope, prefix, ".isDormant", flags->isDormant ? "true" : "false", NULL, 0 );
1036 Write( varName, varType, scope, prefix, ".hasAwakened", flags->hasAwakened ? "true" : "false", NULL, 0 );
1037 Write( varName, varType, scope, prefix, ".networkSync", flags->networkSync ? "true" : "false", NULL, 0 );
1038 typeSize = sizeof( idEntity::entityFlags_s );
1040 } else if ( token == "idScriptBool" ) {
1042 typeSize = sizeof( idScriptBool );
1044 const idScriptBool *scriptBool = ((idScriptBool *)varPtr);
1045 if ( scriptBool->IsLinked() ) {
1046 Write( varName, varType, scope, prefix, "", ( *scriptBool != 0 ) ? "true" : "false", varPtr, typeSize );
1048 Write( varName, varType, scope, prefix, "", "<not linked>", varPtr, typeSize );
1053 const classTypeInfo_t *classTypeInfo = FindClassInfo( scope + ( "::" + token ) );
1054 if ( classTypeInfo == NULL ) {
1055 classTypeInfo = FindClassInfo( token );
1057 if ( classTypeInfo != NULL ) {
1059 typeSize = classTypeInfo->size;
1063 char newPrefix[1024];
1064 idStr::snPrintf( newPrefix, sizeof( newPrefix ), "%s%s::%s.", prefix, scope, varName );
1065 WriteClass_r( varPtr, "", token, token, newPrefix, pointerDepth );
1067 } else if ( token == "idAnim" ) {
1069 const idAnim *anim = ((idAnim*)varPtr);
1070 Write( varName, varType, scope, prefix, "", anim->Name(), NULL, 0 );
1072 } else if ( token == "idPhysics" ) {
1074 const idPhysics *physics = ((idPhysics*)varPtr);
1075 Write( varName, varType, scope, prefix, "", physics->GetType()->classname, NULL, 0 );
1077 } else if ( IsSubclassOf( token, "idEntity" ) ) {
1079 const idEntity *entity = ((idEntity*)varPtr);
1080 Write( varName, varType, scope, prefix, "", va( "entity %d: \'%s\'", entity->entityNumber, entity->name.c_str() ), NULL, 0 );
1082 } else if ( IsSubclassOf( token, "idDecl" ) ) {
1084 const idDecl *decl = ((idDecl *)varPtr);
1085 Write( varName, varType, scope, prefix, "", decl->GetName(), NULL, 0 );
1087 } else if ( pointerDepth == 0 && (
1088 token == "idAFBody" ||
1089 token == "idAFTree" ||
1090 token == "idClipModel" ||
1091 IsSubclassOf( token, "idAFConstraint" )
1094 char newPrefix[1024];
1095 idStr::snPrintf( newPrefix, sizeof( newPrefix ), "%s%s::%s->", prefix, scope, varName );
1096 WriteClass_r( varPtr, "", token, token, newPrefix, pointerDepth + 1 );
1100 Write( varName, varType, scope, prefix, "", va( "<pointer type '%s' not listed>", varType ), NULL, 0 );
1104 const enumTypeInfo_t *enumTypeInfo = FindEnumInfo( scope + ( "::" + token ) );
1105 if ( enumTypeInfo == NULL ) {
1106 enumTypeInfo = FindEnumInfo( token );
1108 if ( enumTypeInfo != NULL ) {
1110 typeSize = sizeof( int ); // NOTE: assuming sizeof( enum ) is sizeof( int )
1112 for ( i = 0; enumTypeInfo->values[i].name != NULL; i++ ) {
1113 if ( *((int *)varPtr) == enumTypeInfo->values[i].value ) {
1117 if ( enumTypeInfo->values[i].name != NULL ) {
1118 Write( varName, varType, scope, prefix, "", enumTypeInfo->values[i].name, NULL, 0 );
1120 Write( varName, varType, scope, prefix, "", va( "%d", *((int *)varPtr) ), NULL, 0 );
1124 Write( varName, varType, scope, prefix, "", va( "<unknown type '%s'>", varType ), NULL, 0 );
1132 if ( *((unsigned long *)varPtr) == 0xcdcdcdcd ) {
1133 common->Warning( "%s%s::%s%s uses uninitialized memory", prefix, scope, varName, "" );
1136 } while( ++i < typeSize );
1139 return sizeof( void * );
1146 idTypeInfoTools::WriteClass_r
1149 void idTypeInfoTools::WriteClass_r( const void *classPtr, const char *className, const char *classType, const char *scope, const char *prefix, const int pointerDepth ) {
1152 const classTypeInfo_t *classInfo = FindClassInfo( classType );
1156 if ( *classInfo->superType != '\0' ) {
1157 WriteClass_r( classPtr, className, classInfo->superType, scope, prefix, pointerDepth );
1160 for ( i = 0; classInfo->variables[i].name != NULL; i++ ) {
1161 const classVariableInfo_t &classVar = classInfo->variables[i];
1163 void *varPtr = (void *) (((byte *)classPtr) + classVar.offset);
1165 WriteVariable_r( varPtr, classVar.name, classVar.type, classType, prefix, pointerDepth );
1171 idTypeInfoTools::WriteGameState
1174 void idTypeInfoTools::WriteGameState( const char *fileName ) {
1178 file = fileSystem->OpenFileWrite( fileName );
1180 common->Warning( "couldn't open %s", fileName );
1185 Write = WriteGameStateVariable; //WriteVariable;
1187 #ifdef DUMP_GAMELOCAL
1189 file->WriteFloatString( "\ngameLocal {\n" );
1190 WriteClass_r( (void *)&gameLocal, "", "idGameLocal", "idGameLocal", "", 0 );
1191 file->WriteFloatString( "}\n" );
1195 for ( num = i = 0; i < gameLocal.num_entities; i++ ) {
1196 idEntity *ent = gameLocal.entities[i];
1197 if ( ent == NULL ) {
1200 file->WriteFloatString( "\nentity %d %s {\n", i, ent->GetType()->classname );
1201 WriteClass_r( (void *)ent, "", ent->GetType()->classname, ent->GetType()->classname, "", 0 );
1202 file->WriteFloatString( "}\n" );
1206 fileSystem->CloseFile( file );
1208 common->Printf( "%d entities written\n", num );
1213 idTypeInfoTools::CompareGameState
1216 void idTypeInfoTools::CompareGameState( const char *fileName ) {
1220 src = new idLexer();
1221 src->SetFlags( LEXFL_NOSTRINGESCAPECHARS );
1223 if ( !src->LoadFile( fileName ) ) {
1224 common->Warning( "couldn't load %s", fileName );
1231 Write = VerifyVariable;
1233 #ifdef DUMP_GAMELOCAL
1235 if ( !src->ExpectTokenString( "gameLocal" ) || !src->ExpectTokenString( "{" ) ) {
1241 WriteClass_r( (void *)&gameLocal, "", "idGameLocal", "idGameLocal", "", 0 );
1243 if ( !src->ExpectTokenString( "}" ) ) {
1251 while( src->ReadToken( &token ) ) {
1252 if ( token != "entity" ) {
1255 if ( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) {
1259 entityNum = token.GetIntValue();
1261 if ( entityNum < 0 || entityNum >= gameLocal.num_entities ) {
1262 src->Warning( "entity number %d out of range", entityNum );
1268 idEntity *ent = gameLocal.entities[entityNum];
1270 src->Warning( "entity %d is not spawned", entityNum );
1271 src->SkipBracedSection( true );
1275 if ( !src->ExpectTokenType( TT_NAME, 0, &token ) ) {
1279 if ( token.Cmp( ent->GetType()->classname ) != 0 ) {
1280 src->Warning( "entity %d has wrong type", entityNum );
1281 src->SkipBracedSection( true );
1285 if ( !src->ExpectTokenString( "{" ) ) {
1286 src->Warning( "entity %d missing leading {", entityNum );
1290 WriteClass_r( (void *)ent, "", ent->GetType()->classname, ent->GetType()->classname, "", 0 );
1292 if ( !src->SkipBracedSection( false ) ) {
1293 src->Warning( "entity %d missing trailing }", entityNum );
1307 void WriteGameState_f( const idCmdArgs &args ) {
1310 if ( args.Argc() > 1 ) {
1311 fileName = args.Argv(1);
1313 fileName = "GameState.txt";
1315 fileName.SetFileExtension( "gameState.txt" );
1317 idTypeInfoTools::WriteGameState( fileName );
1325 void CompareGameState_f( const idCmdArgs &args ) {
1328 if ( args.Argc() > 1 ) {
1329 fileName = args.Argv(1);
1331 fileName = "GameState.txt";
1333 fileName.SetFileExtension( "gameState.txt" );
1335 idTypeInfoTools::CompareGameState( fileName );
1343 void TestSaveGame_f( const idCmdArgs &args ) {
1346 if ( args.Argc() <= 1 ) {
1347 gameLocal.Printf( "testSaveGame <mapName>\n" );
1351 name = args.Argv( 1 );
1354 cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "map %s", name.c_str() ) );
1355 name.Replace( "\\", "_" );
1356 name.Replace( "/", "_" );
1357 cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "saveGame test_%s", name.c_str() ) );
1358 cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "loadGame test_%s", name.c_str() ) );
1360 catch( idException & ) {
1361 // an ERR_DROP was thrown
1363 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "quit" );
1371 void WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName ) {
1372 idTypeInfoTools::WriteTypeToFile( fp, typePtr, typeName );
1380 void PrintType( const void *typePtr, const char *typeName ) {
1381 idTypeInfoTools::PrintType( typePtr, typeName );
1389 void InitTypeVariables( const void *typePtr, const char *typeName, int value ) {
1390 idTypeInfoTools::InitTypeVariables( typePtr, typeName, value );
1398 int SortTypeInfoByName( const int *a, const int *b ) {
1399 return idStr::Icmp( classTypeInfo[*a].typeName, classTypeInfo[*b].typeName );
1402 int SortTypeInfoBySize( const int *a, const int *b ) {
1403 if ( classTypeInfo[*a].size < classTypeInfo[*b].size ) {
1406 if ( classTypeInfo[*a].size > classTypeInfo[*b].size ) {
1412 void ListTypeInfo_f( const idCmdArgs &args ) {
1416 common->Printf( "%-32s : %-32s size (B)\n", "type name", "super type name" );
1417 for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
1421 if ( args.Argc() > 1 && idStr::Icmp( args.Argv( 1 ), "size" ) == 0 ) {
1422 index.Sort( SortTypeInfoBySize );
1424 index.Sort( SortTypeInfoByName );
1427 for ( i = 0; classTypeInfo[i].typeName != NULL; i++ ) {
1429 common->Printf( "%-32s : %-32s %d\n", classTypeInfo[j].typeName, classTypeInfo[j].superType, classTypeInfo[j].size );