Class.cpp (26285B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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. 13 14 Doom 3 BFG Edition 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. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 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. 25 26 =========================================================================== 27 */ 28 /* 29 30 Base class for all C++ objects. Provides fast run-time type checking and run-time 31 instancing of objects. 32 33 */ 34 35 #pragma hdrstop 36 #include "../../idlib/precompiled.h" 37 38 39 #include "../Game_local.h" 40 41 #include "TypeInfo.h" 42 43 44 /*********************************************************************** 45 46 idTypeInfo 47 48 ***********************************************************************/ 49 50 // this is the head of a singly linked list of all the idTypes 51 static idTypeInfo *typelist = NULL; 52 static idHierarchy<idTypeInfo> classHierarchy; 53 static int eventCallbackMemory = 0; 54 55 /* 56 ================ 57 idTypeInfo::idClassType() 58 59 Constructor for class. Should only be called from CLASS_DECLARATION macro. 60 Handles linking class definition into class hierarchy. This should only happen 61 at startup as idTypeInfos are statically defined. Since static variables can be 62 initialized in any order, the constructor must handle the case that subclasses 63 are initialized before superclasses. 64 ================ 65 */ 66 idTypeInfo::idTypeInfo( const char *classname, const char *superclass, idEventFunc<idClass> *eventCallbacks, idClass *( *CreateInstance )(), 67 void ( idClass::*Spawn )(), void ( idClass::*Save )( idSaveGame *savefile ) const, void ( idClass::*Restore )( idRestoreGame *savefile ) ) { 68 69 idTypeInfo *type; 70 idTypeInfo **insert; 71 72 this->classname = classname; 73 this->superclass = superclass; 74 this->eventCallbacks = eventCallbacks; 75 this->eventMap = NULL; 76 this->Spawn = Spawn; 77 this->Save = Save; 78 this->Restore = Restore; 79 this->CreateInstance = CreateInstance; 80 this->super = idClass::GetClass( superclass ); 81 this->freeEventMap = false; 82 typeNum = 0; 83 lastChild = 0; 84 85 // Check if any subclasses were initialized before their superclass 86 for( type = typelist; type != NULL; type = type->next ) { 87 if ( ( type->super == NULL ) && !idStr::Cmp( type->superclass, this->classname ) && 88 idStr::Cmp( type->classname, "idClass" ) ) { 89 type->super = this; 90 } 91 } 92 93 // Insert sorted 94 for ( insert = &typelist; *insert; insert = &(*insert)->next ) { 95 assert( idStr::Cmp( classname, (*insert)->classname ) ); 96 if ( idStr::Cmp( classname, (*insert)->classname ) < 0 ) { 97 next = *insert; 98 *insert = this; 99 break; 100 } 101 } 102 if ( !*insert ) { 103 *insert = this; 104 next = NULL; 105 } 106 } 107 108 /* 109 ================ 110 idTypeInfo::~idTypeInfo 111 ================ 112 */ 113 idTypeInfo::~idTypeInfo() { 114 Shutdown(); 115 } 116 117 /* 118 ================ 119 idTypeInfo::Init 120 121 Initializes the event callback table for the class. Creates a 122 table for fast lookups of event functions. Should only be called once. 123 ================ 124 */ 125 void idTypeInfo::Init() { 126 idTypeInfo *c; 127 idEventFunc<idClass> *def; 128 int ev; 129 int i; 130 bool *set; 131 int num; 132 133 if ( eventMap ) { 134 // we've already been initialized by a subclass 135 return; 136 } 137 138 // make sure our superclass is initialized first 139 if ( super && !super->eventMap ) { 140 super->Init(); 141 } 142 143 // add to our node hierarchy 144 if ( super ) { 145 node.ParentTo( super->node ); 146 } else { 147 node.ParentTo( classHierarchy ); 148 } 149 node.SetOwner( this ); 150 151 // keep track of the number of children below each class 152 for( c = super; c != NULL; c = c->super ) { 153 c->lastChild++; 154 } 155 156 // if we're not adding any new event callbacks, we can just use our superclass's table 157 if ( ( !eventCallbacks || !eventCallbacks->event ) && super ) { 158 eventMap = super->eventMap; 159 return; 160 } 161 162 // set a flag so we know to delete the eventMap table 163 freeEventMap = true; 164 165 // Allocate our new table. It has to have as many entries as there 166 // are events. NOTE: could save some space by keeping track of the maximum 167 // event that the class responds to and doing range checking. 168 num = idEventDef::NumEventCommands(); 169 eventMap = new (TAG_SYSTEM) eventCallback_t[ num ]; 170 memset( eventMap, 0, sizeof( eventCallback_t ) * num ); 171 eventCallbackMemory += sizeof( eventCallback_t ) * num; 172 173 // allocate temporary memory for flags so that the subclass's event callbacks 174 // override the superclass's event callback 175 set = new (TAG_SYSTEM) bool[ num ]; 176 memset( set, 0, sizeof( bool ) * num ); 177 178 // go through the inheritence order and copies the event callback function into 179 // a list indexed by the event number. This allows fast lookups of 180 // event functions. 181 for( c = this; c != NULL; c = c->super ) { 182 def = c->eventCallbacks; 183 if ( !def ) { 184 continue; 185 } 186 187 // go through each entry until we hit the NULL terminator 188 for( i = 0; def[ i ].event != NULL; i++ ) { 189 ev = def[ i ].event->GetEventNum(); 190 191 if ( set[ ev ] ) { 192 continue; 193 } 194 set[ ev ] = true; 195 eventMap[ ev ] = def[ i ].function; 196 } 197 } 198 199 delete[] set; 200 } 201 202 /* 203 ================ 204 idTypeInfo::Shutdown 205 206 Should only be called when DLL or EXE is being shutdown. 207 Although it cleans up any allocated memory, it doesn't bother to remove itself 208 from the class list since the program is shutting down. 209 ================ 210 */ 211 void idTypeInfo::Shutdown() { 212 // free up the memory used for event lookups 213 if ( eventMap ) { 214 if ( freeEventMap ) { 215 delete[] eventMap; 216 } 217 eventMap = NULL; 218 } 219 typeNum = 0; 220 lastChild = 0; 221 } 222 223 224 /*********************************************************************** 225 226 idClass 227 228 ***********************************************************************/ 229 230 const idEventDef EV_Remove( "<immediateremove>", NULL ); 231 const idEventDef EV_SafeRemove( "remove", NULL ); 232 233 ABSTRACT_DECLARATION( NULL, idClass ) 234 EVENT( EV_Remove, idClass::Event_Remove ) 235 EVENT( EV_SafeRemove, idClass::Event_SafeRemove ) 236 END_CLASS 237 238 // alphabetical order 239 idList<idTypeInfo *, TAG_IDCLASS> idClass::types; 240 // typenum order 241 idList<idTypeInfo *, TAG_IDCLASS> idClass::typenums; 242 243 bool idClass::initialized = false; 244 int idClass::typeNumBits = 0; 245 int idClass::memused = 0; 246 int idClass::numobjects = 0; 247 248 /* 249 ================ 250 idClass::CallSpawn 251 ================ 252 */ 253 void idClass::CallSpawn() { 254 idTypeInfo *type; 255 256 type = GetType(); 257 CallSpawnFunc( type ); 258 } 259 260 /* 261 ================ 262 idClass::CallSpawnFunc 263 ================ 264 */ 265 classSpawnFunc_t idClass::CallSpawnFunc( idTypeInfo *cls ) { 266 classSpawnFunc_t func; 267 268 if ( cls->super ) { 269 func = CallSpawnFunc( cls->super ); 270 if ( func == cls->Spawn ) { 271 // don't call the same function twice in a row. 272 // this can happen when subclasses don't have their own spawn function. 273 return func; 274 } 275 } 276 277 ( this->*cls->Spawn )(); 278 279 return cls->Spawn; 280 } 281 282 /* 283 ================ 284 idClass::FindUninitializedMemory 285 ================ 286 */ 287 void idClass::FindUninitializedMemory() { 288 #ifdef ID_DEBUG_UNINITIALIZED_MEMORY 289 unsigned long *ptr = ( ( unsigned long * )this ) - 1; 290 int size = *ptr; 291 assert( ( size & 3 ) == 0 ); 292 size >>= 2; 293 for ( int i = 0; i < size; i++ ) { 294 if ( ptr[i] == 0xcdcdcdcd ) { 295 const char *varName = GetTypeVariableName( GetClassname(), i << 2 ); 296 gameLocal.Warning( "type '%s' has uninitialized variable %s (offset %d)", GetClassname(), varName, i << 2 ); 297 } 298 } 299 #endif 300 } 301 302 /* 303 ================ 304 idClass::Spawn 305 ================ 306 */ 307 void idClass::Spawn() { 308 } 309 310 /* 311 ================ 312 idClass::~idClass 313 314 Destructor for object. Cancels any events that depend on this object. 315 ================ 316 */ 317 idClass::~idClass() { 318 idEvent::CancelEvents( this ); 319 } 320 321 /* 322 ================ 323 idClass::DisplayInfo_f 324 ================ 325 */ 326 void idClass::DisplayInfo_f( const idCmdArgs &args ) { 327 gameLocal.Printf( "Class memory status: %i bytes allocated in %i objects\n", memused, numobjects ); 328 } 329 330 /* 331 ================ 332 idClass::ListClasses_f 333 ================ 334 */ 335 void idClass::ListClasses_f( const idCmdArgs &args ) { 336 int i; 337 idTypeInfo *type; 338 339 gameLocal.Printf( "%-24s %-24s %-6s %-6s\n", "Classname", "Superclass", "Type", "Subclasses" ); 340 gameLocal.Printf( "----------------------------------------------------------------------\n" ); 341 342 for( i = 0; i < types.Num(); i++ ) { 343 type = types[ i ]; 344 gameLocal.Printf( "%-24s %-24s %6d %6d\n", type->classname, type->superclass, type->typeNum, type->lastChild - type->typeNum ); 345 } 346 347 gameLocal.Printf( "...%d classes", types.Num() ); 348 } 349 350 /* 351 ================ 352 idClass::CreateInstance 353 ================ 354 */ 355 idClass *idClass::CreateInstance( const char *name ) { 356 const idTypeInfo *type; 357 idClass *obj; 358 359 type = idClass::GetClass( name ); 360 if ( !type ) { 361 return NULL; 362 } 363 364 obj = type->CreateInstance(); 365 return obj; 366 } 367 368 /* 369 ================ 370 idClass::Init 371 372 Should be called after all idTypeInfos are initialized, so must be called 373 manually upon game code initialization. Tells all the idTypeInfos to initialize 374 their event callback table for the associated class. This should only be called 375 once during the execution of the program or DLL. 376 ================ 377 */ 378 void idClass::Init() { 379 idTypeInfo *c; 380 int num; 381 382 gameLocal.Printf( "Initializing class hierarchy\n" ); 383 384 if ( initialized ) { 385 gameLocal.Printf( "...already initialized\n" ); 386 return; 387 } 388 389 // init the event callback tables for all the classes 390 for( c = typelist; c != NULL; c = c->next ) { 391 c->Init(); 392 } 393 394 // number the types according to the class hierarchy so we can quickly determine if a class 395 // is a subclass of another 396 num = 0; 397 for( c = classHierarchy.GetNext(); c != NULL; c = c->node.GetNext(), num++ ) { 398 c->typeNum = num; 399 c->lastChild += num; 400 } 401 402 // number of bits needed to send types over network 403 typeNumBits = idMath::BitsForInteger( num ); 404 405 // create a list of the types so we can do quick lookups 406 // one list in alphabetical order, one in typenum order 407 types.SetGranularity( 1 ); 408 types.SetNum( num ); 409 typenums.SetGranularity( 1 ); 410 typenums.SetNum( num ); 411 num = 0; 412 for( c = typelist; c != NULL; c = c->next, num++ ) { 413 types[ num ] = c; 414 typenums[ c->typeNum ] = c; 415 } 416 417 initialized = true; 418 419 gameLocal.Printf( "...%i classes, %i bytes for event callbacks\n", types.Num(), eventCallbackMemory ); 420 } 421 422 /* 423 ================ 424 idClass::Shutdown 425 ================ 426 */ 427 void idClass::Shutdown() { 428 idTypeInfo *c; 429 430 for( c = typelist; c != NULL; c = c->next ) { 431 c->Shutdown(); 432 } 433 types.Clear(); 434 typenums.Clear(); 435 436 initialized = false; 437 } 438 439 /* 440 ================ 441 idClass::new 442 ================ 443 */ 444 void * idClass::operator new( size_t s ) { 445 int *p; 446 447 s += sizeof( int ); 448 p = (int *)Mem_Alloc( s, TAG_IDCLASS ); 449 *p = s; 450 memused += s; 451 numobjects++; 452 453 return p + 1; 454 } 455 456 /* 457 ================ 458 idClass::delete 459 ================ 460 */ 461 void idClass::operator delete( void *ptr ) { 462 int *p; 463 464 if ( ptr ) { 465 p = ( ( int * )ptr ) - 1; 466 memused -= *p; 467 numobjects--; 468 Mem_Free( p ); 469 } 470 } 471 472 /* 473 ================ 474 idClass::GetClass 475 476 Returns the idTypeInfo for the name of the class passed in. This is a static function 477 so it must be called as idClass::GetClass( classname ) 478 ================ 479 */ 480 idTypeInfo *idClass::GetClass( const char *name ) { 481 idTypeInfo *c; 482 int order; 483 int mid; 484 int min; 485 int max; 486 487 if ( !initialized ) { 488 // idClass::Init hasn't been called yet, so do a slow lookup 489 for( c = typelist; c != NULL; c = c->next ) { 490 if ( !idStr::Cmp( c->classname, name ) ) { 491 return c; 492 } 493 } 494 } else { 495 // do a binary search through the list of types 496 min = 0; 497 max = types.Num() - 1; 498 while( min <= max ) { 499 mid = ( min + max ) / 2; 500 c = types[ mid ]; 501 order = idStr::Cmp( c->classname, name ); 502 if ( !order ) { 503 return c; 504 } else if ( order > 0 ) { 505 max = mid - 1; 506 } else { 507 min = mid + 1; 508 } 509 } 510 } 511 512 return NULL; 513 } 514 515 /* 516 ================ 517 idClass::GetType 518 ================ 519 */ 520 idTypeInfo *idClass::GetType( const int typeNum ) { 521 idTypeInfo *c; 522 523 if ( !initialized ) { 524 for( c = typelist; c != NULL; c = c->next ) { 525 if ( c->typeNum == typeNum ) { 526 return c; 527 } 528 } 529 } else if ( ( typeNum >= 0 ) && ( typeNum < types.Num() ) ) { 530 return typenums[ typeNum ]; 531 } 532 533 return NULL; 534 } 535 536 /* 537 ================ 538 idClass::GetClassname 539 540 Returns the text classname of the object. 541 ================ 542 */ 543 const char *idClass::GetClassname() const { 544 idTypeInfo *type; 545 546 type = GetType(); 547 return type->classname; 548 } 549 550 /* 551 ================ 552 idClass::GetSuperclass 553 554 Returns the text classname of the superclass. 555 ================ 556 */ 557 const char *idClass::GetSuperclass() const { 558 idTypeInfo *cls; 559 560 cls = GetType(); 561 return cls->superclass; 562 } 563 564 /* 565 ================ 566 idClass::CancelEvents 567 ================ 568 */ 569 void idClass::CancelEvents( const idEventDef *ev ) { 570 idEvent::CancelEvents( this, ev ); 571 } 572 573 /* 574 ================ 575 idClass::PostEventArgs 576 ================ 577 */ 578 bool idClass::PostEventArgs( const idEventDef *ev, int time, int numargs, ... ) { 579 idTypeInfo *c; 580 idEvent *event; 581 va_list args; 582 583 assert( ev ); 584 585 if ( !idEvent::initialized ) { 586 return false; 587 } 588 589 c = GetType(); 590 if ( !c->eventMap[ ev->GetEventNum() ] ) { 591 // we don't respond to this event, so ignore it 592 return false; 593 } 594 595 bool isReplicated = true; 596 // If this is an entity with skipReplication, we want to process the event normally even on clients. 597 if ( IsType( idEntity::Type ) ) { 598 idEntity * thisEnt = static_cast< idEntity * >( this ); 599 if ( thisEnt->fl.skipReplication ) { 600 isReplicated = false; 601 } 602 } 603 604 // we service events on the client to avoid any bad code filling up the event pool 605 // we don't want them processed usually, unless when the map is (re)loading. 606 // we allow threads to run fine, though. 607 if ( common->IsClient() && isReplicated && ( gameLocal.GameState() != GAMESTATE_STARTUP ) && !IsType( idThread::Type ) ) { 608 return true; 609 } 610 611 va_start( args, numargs ); 612 event = idEvent::Alloc( ev, numargs, args ); 613 va_end( args ); 614 615 event->Schedule( this, c, time ); 616 617 return true; 618 } 619 620 /* 621 ================ 622 idClass::PostEventMS 623 ================ 624 */ 625 bool idClass::PostEventMS( const idEventDef *ev, int time ) { 626 return PostEventArgs( ev, time, 0 ); 627 } 628 629 /* 630 ================ 631 idClass::PostEventMS 632 ================ 633 */ 634 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1 ) { 635 return PostEventArgs( ev, time, 1, &arg1 ); 636 } 637 638 /* 639 ================ 640 idClass::PostEventMS 641 ================ 642 */ 643 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2 ) { 644 return PostEventArgs( ev, time, 2, &arg1, &arg2 ); 645 } 646 647 /* 648 ================ 649 idClass::PostEventMS 650 ================ 651 */ 652 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) { 653 return PostEventArgs( ev, time, 3, &arg1, &arg2, &arg3 ); 654 } 655 656 /* 657 ================ 658 idClass::PostEventMS 659 ================ 660 */ 661 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) { 662 return PostEventArgs( ev, time, 4, &arg1, &arg2, &arg3, &arg4 ); 663 } 664 665 /* 666 ================ 667 idClass::PostEventMS 668 ================ 669 */ 670 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) { 671 return PostEventArgs( ev, time, 5, &arg1, &arg2, &arg3, &arg4, &arg5 ); 672 } 673 674 /* 675 ================ 676 idClass::PostEventMS 677 ================ 678 */ 679 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) { 680 return PostEventArgs( ev, time, 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 ); 681 } 682 683 /* 684 ================ 685 idClass::PostEventMS 686 ================ 687 */ 688 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) { 689 return PostEventArgs( ev, time, 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 ); 690 } 691 692 /* 693 ================ 694 idClass::PostEventMS 695 ================ 696 */ 697 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) { 698 return PostEventArgs( ev, time, 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 ); 699 } 700 701 /* 702 ================ 703 idClass::PostEventSec 704 ================ 705 */ 706 bool idClass::PostEventSec( const idEventDef *ev, float time ) { 707 return PostEventArgs( ev, SEC2MS( time ), 0 ); 708 } 709 710 /* 711 ================ 712 idClass::PostEventSec 713 ================ 714 */ 715 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1 ) { 716 return PostEventArgs( ev, SEC2MS( time ), 1, &arg1 ); 717 } 718 719 /* 720 ================ 721 idClass::PostEventSec 722 ================ 723 */ 724 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2 ) { 725 return PostEventArgs( ev, SEC2MS( time ), 2, &arg1, &arg2 ); 726 } 727 728 /* 729 ================ 730 idClass::PostEventSec 731 ================ 732 */ 733 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) { 734 return PostEventArgs( ev, SEC2MS( time ), 3, &arg1, &arg2, &arg3 ); 735 } 736 737 /* 738 ================ 739 idClass::PostEventSec 740 ================ 741 */ 742 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) { 743 return PostEventArgs( ev, SEC2MS( time ), 4, &arg1, &arg2, &arg3, &arg4 ); 744 } 745 746 /* 747 ================ 748 idClass::PostEventSec 749 ================ 750 */ 751 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) { 752 return PostEventArgs( ev, SEC2MS( time ), 5, &arg1, &arg2, &arg3, &arg4, &arg5 ); 753 } 754 755 /* 756 ================ 757 idClass::PostEventSec 758 ================ 759 */ 760 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) { 761 return PostEventArgs( ev, SEC2MS( time ), 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 ); 762 } 763 764 /* 765 ================ 766 idClass::PostEventSec 767 ================ 768 */ 769 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) { 770 return PostEventArgs( ev, SEC2MS( time ), 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 ); 771 } 772 773 /* 774 ================ 775 idClass::PostEventSec 776 ================ 777 */ 778 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) { 779 return PostEventArgs( ev, SEC2MS( time ), 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 ); 780 } 781 782 /* 783 ================ 784 idClass::ProcessEventArgs 785 ================ 786 */ 787 bool idClass::ProcessEventArgs( const idEventDef *ev, int numargs, ... ) { 788 idTypeInfo *c; 789 int num; 790 int data[ D_EVENT_MAXARGS ]; 791 va_list args; 792 793 assert( ev ); 794 assert( idEvent::initialized ); 795 796 c = GetType(); 797 num = ev->GetEventNum(); 798 if ( !c->eventMap[ num ] ) { 799 // we don't respond to this event, so ignore it 800 return false; 801 } 802 803 va_start( args, numargs ); 804 idEvent::CopyArgs( ev, numargs, args, data ); 805 va_end( args ); 806 807 ProcessEventArgPtr( ev, data ); 808 809 return true; 810 } 811 812 /* 813 ================ 814 idClass::ProcessEvent 815 ================ 816 */ 817 bool idClass::ProcessEvent( const idEventDef *ev ) { 818 return ProcessEventArgs( ev, 0 ); 819 } 820 821 /* 822 ================ 823 idClass::ProcessEvent 824 ================ 825 */ 826 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1 ) { 827 return ProcessEventArgs( ev, 1, &arg1 ); 828 } 829 830 /* 831 ================ 832 idClass::ProcessEvent 833 ================ 834 */ 835 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2 ) { 836 return ProcessEventArgs( ev, 2, &arg1, &arg2 ); 837 } 838 839 /* 840 ================ 841 idClass::ProcessEvent 842 ================ 843 */ 844 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) { 845 return ProcessEventArgs( ev, 3, &arg1, &arg2, &arg3 ); 846 } 847 848 /* 849 ================ 850 idClass::ProcessEvent 851 ================ 852 */ 853 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) { 854 return ProcessEventArgs( ev, 4, &arg1, &arg2, &arg3, &arg4 ); 855 } 856 857 /* 858 ================ 859 idClass::ProcessEvent 860 ================ 861 */ 862 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) { 863 return ProcessEventArgs( ev, 5, &arg1, &arg2, &arg3, &arg4, &arg5 ); 864 } 865 866 /* 867 ================ 868 idClass::ProcessEvent 869 ================ 870 */ 871 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) { 872 return ProcessEventArgs( ev, 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 ); 873 } 874 875 /* 876 ================ 877 idClass::ProcessEvent 878 ================ 879 */ 880 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) { 881 return ProcessEventArgs( ev, 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 ); 882 } 883 884 /* 885 ================ 886 idClass::ProcessEvent 887 ================ 888 */ 889 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) { 890 return ProcessEventArgs( ev, 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 ); 891 } 892 893 /* 894 ================ 895 idClass::ProcessEventArgPtr 896 ================ 897 */ 898 bool idClass::ProcessEventArgPtr( const idEventDef *ev, int *data ) { 899 idTypeInfo *c; 900 int num; 901 eventCallback_t callback; 902 903 assert( ev ); 904 assert( idEvent::initialized ); 905 906 SetTimeState ts; 907 908 if ( IsType( idEntity::Type ) ) { 909 idEntity *ent = (idEntity*)this; 910 ts.PushState( ent->timeGroup ); 911 } 912 913 if ( g_debugTriggers.GetBool() && ( ev == &EV_Activate ) && IsType( idEntity::Type ) ) { 914 const idEntity *ent = *reinterpret_cast<idEntity **>( data ); 915 gameLocal.Printf( "%d: '%s' activated by '%s'\n", gameLocal.framenum, static_cast<idEntity *>( this )->GetName(), ent ? ent->GetName() : "NULL" ); 916 } 917 918 c = GetType(); 919 num = ev->GetEventNum(); 920 if ( !c->eventMap[ num ] ) { 921 // we don't respond to this event, so ignore it 922 return false; 923 } 924 925 callback = c->eventMap[ num ]; 926 927 #if !CPU_EASYARGS 928 929 /* 930 on ppc architecture, floats are passed in a seperate set of registers 931 the function prototypes must have matching float declaration 932 933 http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/2rt_powerpc_abi/chapter_9_section_5.html 934 */ 935 936 switch( ev->GetFormatspecIndex() ) { 937 case 1 << D_EVENT_MAXARGS : 938 ( this->*callback )(); 939 break; 940 941 // generated file - see CREATE_EVENT_CODE 942 #include "Callbacks.cpp" 943 944 default: 945 gameLocal.Warning( "Invalid formatspec on event '%s'", ev->GetName() ); 946 break; 947 } 948 949 #else 950 951 assert( D_EVENT_MAXARGS == 8 ); 952 953 switch( ev->GetNumArgs() ) { 954 case 0 : 955 ( this->*callback )(); 956 break; 957 958 case 1 : 959 typedef void ( idClass::*eventCallback_1_t )( const int ); 960 ( this->*( eventCallback_1_t )callback )( data[ 0 ] ); 961 break; 962 963 case 2 : 964 typedef void ( idClass::*eventCallback_2_t )( const int, const int ); 965 ( this->*( eventCallback_2_t )callback )( data[ 0 ], data[ 1 ] ); 966 break; 967 968 case 3 : 969 typedef void ( idClass::*eventCallback_3_t )( const int, const int, const int ); 970 ( this->*( eventCallback_3_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ] ); 971 break; 972 973 case 4 : 974 typedef void ( idClass::*eventCallback_4_t )( const int, const int, const int, const int ); 975 ( this->*( eventCallback_4_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ] ); 976 break; 977 978 case 5 : 979 typedef void ( idClass::*eventCallback_5_t )( const int, const int, const int, const int, const int ); 980 ( this->*( eventCallback_5_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ] ); 981 break; 982 983 case 6 : 984 typedef void ( idClass::*eventCallback_6_t )( const int, const int, const int, const int, const int, const int ); 985 ( this->*( eventCallback_6_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] ); 986 break; 987 988 case 7 : 989 typedef void ( idClass::*eventCallback_7_t )( const int, const int, const int, const int, const int, const int, const int ); 990 ( this->*( eventCallback_7_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] ); 991 break; 992 993 case 8 : 994 typedef void ( idClass::*eventCallback_8_t )( const int, const int, const int, const int, const int, const int, const int, const int ); 995 ( this->*( eventCallback_8_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] ); 996 break; 997 998 default: 999 gameLocal.Warning( "Invalid formatspec on event '%s'", ev->GetName() ); 1000 break; 1001 } 1002 1003 #endif 1004 1005 return true; 1006 } 1007 1008 /* 1009 ================ 1010 idClass::Event_Remove 1011 ================ 1012 */ 1013 void idClass::Event_Remove() { 1014 delete this; 1015 } 1016 1017 /* 1018 ================ 1019 idClass::Event_SafeRemove 1020 ================ 1021 */ 1022 void idClass::Event_SafeRemove() { 1023 // Forces the remove to be done at a safe time 1024 PostEventMS( &EV_Remove, 0 ); 1025 }