doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Event.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
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.
13 
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.
18 
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/>.
21 
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.
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 sys_event.cpp
30 
31 Event are used for scheduling tasks and for linking script commands.
32 
33 */
34 
35 #include "../../idlib/precompiled.h"
36 #pragma hdrstop
37 
38 #include "../Game_local.h"
39 
40 #define MAX_EVENTSPERFRAME 4096
41 //#define CREATE_EVENT_CODE
42 
43 /***********************************************************************
44 
45  idEventDef
46 
47 ***********************************************************************/
48 
51 
52 static bool eventError = false;
53 static char eventErrorMsg[ 128 ];
54 
55 /*
56 ================
57 idEventDef::idEventDef
58 ================
59 */
60 idEventDef::idEventDef( const char *command, const char *formatspec, char returnType ) {
61  idEventDef *ev;
62  int i;
63  unsigned int bits;
64 
65  assert( command );
67 
68  // Allow NULL to indicate no args, but always store it as ""
69  // so we don't have to check for it.
70  if ( !formatspec ) {
71  formatspec = "";
72  }
73 
74  this->name = command;
75  this->formatspec = formatspec;
76  this->returnType = returnType;
77 
78  numargs = strlen( formatspec );
80  if ( numargs > D_EVENT_MAXARGS ) {
81  eventError = true;
82  sprintf( eventErrorMsg, "idEventDef::idEventDef : Too many args for '%s' event.", name );
83  return;
84  }
85 
86  // make sure the format for the args is valid, calculate the formatspecindex, and the offsets for each arg
87  bits = 0;
88  argsize = 0;
89  memset( argOffset, 0, sizeof( argOffset ) );
90  for( i = 0; i < numargs;i++ ) {
91  argOffset[ i ] = argsize;
92  switch( formatspec[ i ] ) {
93  case D_EVENT_FLOAT :
94  bits |= 1 << i;
95  argsize += sizeof( float );
96  break;
97 
98  case D_EVENT_INTEGER :
99  argsize += sizeof( int );
100  break;
101 
102  case D_EVENT_VECTOR :
103  argsize += sizeof( idVec3 );
104  break;
105 
106  case D_EVENT_STRING :
108  break;
109 
110  case D_EVENT_ENTITY :
111  argsize += sizeof( idEntityPtr<idEntity> );
112  break;
113 
114  case D_EVENT_ENTITY_NULL :
115  argsize += sizeof( idEntityPtr<idEntity> );
116  break;
117 
118  case D_EVENT_TRACE :
119  argsize += sizeof( trace_t ) + MAX_STRING_LEN + sizeof( bool );
120  break;
121 
122  default :
123  eventError = true;
124  sprintf( eventErrorMsg, "idEventDef::idEventDef : Invalid arg format '%s' string for '%s' event.", formatspec, name );
125  return;
126  break;
127  }
128  }
129 
130  // calculate the formatspecindex
131  formatspecIndex = ( 1 << ( numargs + D_EVENT_MAXARGS ) ) | bits;
132 
133  // go through the list of defined events and check for duplicates
134  // and mismatched format strings
136  for( i = 0; i < eventnum; i++ ) {
137  ev = eventDefList[ i ];
138  if ( strcmp( command, ev->name ) == 0 ) {
139  if ( strcmp( formatspec, ev->formatspec ) != 0 ) {
140  eventError = true;
141  sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing format strings ('%s'!='%s').",
142  command, formatspec, ev->formatspec );
143  return;
144  }
145 
146  if ( ev->returnType != returnType ) {
147  eventError = true;
148  sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing return types ('%c'!='%c').",
149  command, returnType, ev->returnType );
150  return;
151  }
152  // Don't bother putting the duplicate event in list.
153  eventnum = ev->eventnum;
154  return;
155  }
156  }
157 
158  ev = this;
159 
160  if ( numEventDefs >= MAX_EVENTS ) {
161  eventError = true;
162  sprintf( eventErrorMsg, "numEventDefs >= MAX_EVENTS" );
163  return;
164  }
166  numEventDefs++;
167 }
168 
169 /*
170 ================
171 idEventDef::NumEventCommands
172 ================
173 */
175  return numEventDefs;
176 }
177 
178 /*
179 ================
180 idEventDef::GetEventCommand
181 ================
182 */
183 const idEventDef *idEventDef::GetEventCommand( int eventnum ) {
184  return eventDefList[ eventnum ];
185 }
186 
187 /*
188 ================
189 idEventDef::FindEvent
190 ================
191 */
192 const idEventDef *idEventDef::FindEvent( const char *name ) {
193  idEventDef *ev;
194  int num;
195  int i;
196 
197  assert( name );
198 
199  num = numEventDefs;
200  for( i = 0; i < num; i++ ) {
201  ev = eventDefList[ i ];
202  if ( strcmp( name, ev->name ) == 0 ) {
203  return ev;
204  }
205  }
206 
207  return NULL;
208 }
209 
210 /***********************************************************************
211 
212  idEvent
213 
214 ***********************************************************************/
215 
216 static idLinkList<idEvent> FreeEvents;
217 static idLinkList<idEvent> EventQueue;
218 #ifdef _D3XP
219 static idLinkList<idEvent> FastEventQueue;
220 #endif
221 static idEvent EventPool[ MAX_EVENTS ];
222 
223 bool idEvent::initialized = false;
224 
226 
227 /*
228 ================
229 idEvent::~idEvent()
230 ================
231 */
233  Free();
234 }
235 
236 /*
237 ================
238 idEvent::Alloc
239 ================
240 */
241 idEvent *idEvent::Alloc( const idEventDef *evdef, int numargs, va_list args ) {
242  idEvent *ev;
243  size_t size;
244  const char *format;
245  idEventArg *arg;
246  byte *dataPtr;
247  int i;
248  const char *materialName;
249 
250  if ( FreeEvents.IsListEmpty() ) {
251  gameLocal.Error( "idEvent::Alloc : No more free events" );
252  }
253 
254  ev = FreeEvents.Next();
255  ev->eventNode.Remove();
256 
257  ev->eventdef = evdef;
258 
259  if ( numargs != evdef->GetNumArgs() ) {
260  gameLocal.Error( "idEvent::Alloc : Wrong number of args for '%s' event.", evdef->GetName() );
261  }
262 
263  size = evdef->GetArgSize();
264  if ( size ) {
265  ev->data = eventDataAllocator.Alloc( size );
266  memset( ev->data, 0, size );
267  } else {
268  ev->data = NULL;
269  }
270 
271  format = evdef->GetArgFormat();
272  for( i = 0; i < numargs; i++ ) {
273  arg = va_arg( args, idEventArg * );
274  if ( format[ i ] != arg->type ) {
275  // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens
276  if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) {
277  gameLocal.Error( "idEvent::Alloc : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() );
278  }
279  }
280 
281  dataPtr = &ev->data[ evdef->GetArgOffset( i ) ];
282 
283  switch( format[ i ] ) {
284  case D_EVENT_FLOAT :
285  case D_EVENT_INTEGER :
286  *reinterpret_cast<int *>( dataPtr ) = arg->value;
287  break;
288 
289  case D_EVENT_VECTOR :
290  if ( arg->value ) {
291  *reinterpret_cast<idVec3 *>( dataPtr ) = *reinterpret_cast<const idVec3 *>( arg->value );
292  }
293  break;
294 
295  case D_EVENT_STRING :
296  if ( arg->value ) {
297  idStr::Copynz( reinterpret_cast<char *>( dataPtr ), reinterpret_cast<const char *>( arg->value ), MAX_STRING_LEN );
298  }
299  break;
300 
301  case D_EVENT_ENTITY :
302  case D_EVENT_ENTITY_NULL :
303  *reinterpret_cast< idEntityPtr<idEntity> * >( dataPtr ) = reinterpret_cast<idEntity *>( arg->value );
304  break;
305 
306  case D_EVENT_TRACE :
307  if ( arg->value ) {
308  *reinterpret_cast<bool *>( dataPtr ) = true;
309  *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) ) = *reinterpret_cast<const trace_t *>( arg->value );
310 
311  // save off the material as a string since the pointer won't be valid in save games.
312  // since we save off the entire trace_t structure, if the material is NULL here,
313  // it will be NULL when we process it, so we don't need to save off anything in that case.
314  if ( reinterpret_cast<const trace_t *>( arg->value )->c.material ) {
315  materialName = reinterpret_cast<const trace_t *>( arg->value )->c.material->GetName();
316  idStr::Copynz( reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) ), materialName, MAX_STRING_LEN );
317  }
318  } else {
319  *reinterpret_cast<bool *>( dataPtr ) = false;
320  }
321  break;
322 
323  default :
324  gameLocal.Error( "idEvent::Alloc : Invalid arg format '%s' string for '%s' event.", format, evdef->GetName() );
325  break;
326  }
327  }
328 
329  return ev;
330 }
331 
332 /*
333 ================
334 idEvent::CopyArgs
335 ================
336 */
337 void idEvent::CopyArgs( const idEventDef *evdef, int numargs, va_list args, int data[ D_EVENT_MAXARGS ] ) {
338  int i;
339  const char *format;
340  idEventArg *arg;
341 
342  format = evdef->GetArgFormat();
343  if ( numargs != evdef->GetNumArgs() ) {
344  gameLocal.Error( "idEvent::CopyArgs : Wrong number of args for '%s' event.", evdef->GetName() );
345  }
346 
347  for( i = 0; i < numargs; i++ ) {
348  arg = va_arg( args, idEventArg * );
349  if ( format[ i ] != arg->type ) {
350  // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens
351  if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) {
352  gameLocal.Error( "idEvent::CopyArgs : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() );
353  }
354  }
355 
356  data[ i ] = arg->value;
357  }
358 }
359 
360 /*
361 ================
362 idEvent::Free
363 ================
364 */
365 void idEvent::Free( void ) {
366  if ( data ) {
368  data = NULL;
369  }
370 
371  eventdef = NULL;
372  time = 0;
373  object = NULL;
374  typeinfo = NULL;
375 
376  eventNode.SetOwner( this );
377  eventNode.AddToEnd( FreeEvents );
378 }
379 
380 /*
381 ================
382 idEvent::Schedule
383 ================
384 */
385 void idEvent::Schedule( idClass *obj, const idTypeInfo *type, int time ) {
386  idEvent *event;
387 
388  assert( initialized );
389  if ( !initialized ) {
390  return;
391  }
392 
393  object = obj;
394  typeinfo = type;
395 
396  // wraps after 24 days...like I care. ;)
397  this->time = gameLocal.time + time;
398 
399  eventNode.Remove();
400 
401 #ifdef _D3XP
402  if ( obj->IsType( idEntity::Type ) && ( ( (idEntity*)(obj) )->timeGroup == TIME_GROUP2 ) ) {
403  event = FastEventQueue.Next();
404  while( ( event != NULL ) && ( this->time >= event->time ) ) {
405  event = event->eventNode.Next();
406  }
407 
408  if ( event ) {
409  eventNode.InsertBefore( event->eventNode );
410  } else {
411  eventNode.AddToEnd( FastEventQueue );
412  }
413 
414  return;
415  } else {
416  this->time = gameLocal.slow.time + time;
417  }
418 #endif
419 
420  event = EventQueue.Next();
421  while( ( event != NULL ) && ( this->time >= event->time ) ) {
422  event = event->eventNode.Next();
423  }
424 
425  if ( event ) {
426  eventNode.InsertBefore( event->eventNode );
427  } else {
428  eventNode.AddToEnd( EventQueue );
429  }
430 }
431 
432 /*
433 ================
434 idEvent::CancelEvents
435 ================
436 */
437 void idEvent::CancelEvents( const idClass *obj, const idEventDef *evdef ) {
438  idEvent *event;
439  idEvent *next;
440 
441  if ( !initialized ) {
442  return;
443  }
444 
445  for( event = EventQueue.Next(); event != NULL; event = next ) {
446  next = event->eventNode.Next();
447  if ( event->object == obj ) {
448  if ( !evdef || ( evdef == event->eventdef ) ) {
449  event->Free();
450  }
451  }
452  }
453 
454 #ifdef _D3XP
455  for( event = FastEventQueue.Next(); event != NULL; event = next ) {
456  next = event->eventNode.Next();
457  if ( event->object == obj ) {
458  if ( !evdef || ( evdef == event->eventdef ) ) {
459  event->Free();
460  }
461  }
462  }
463 #endif
464 }
465 
466 /*
467 ================
468 idEvent::ClearEventList
469 ================
470 */
472  int i;
473 
474  //
475  // initialize lists
476  //
477  FreeEvents.Clear();
478  EventQueue.Clear();
479 
480  //
481  // add the events to the free list
482  //
483  for( i = 0; i < MAX_EVENTS; i++ ) {
484  EventPool[ i ].Free();
485  }
486 }
487 
488 /*
489 ================
490 idEvent::ServiceEvents
491 ================
492 */
494  idEvent *event;
495  int num;
496  int args[ D_EVENT_MAXARGS ];
497  int offset;
498  int i;
499  int numargs;
500  const char *formatspec;
501  trace_t **tracePtr;
502  const idEventDef *ev;
503  byte *data;
504  const char *materialName;
505 
506  num = 0;
507  while( !EventQueue.IsListEmpty() ) {
508  event = EventQueue.Next();
509  assert( event );
510 
511  if ( event->time > gameLocal.time ) {
512  break;
513  }
514 
515  // copy the data into the local args array and set up pointers
516  ev = event->eventdef;
517  formatspec = ev->GetArgFormat();
518  numargs = ev->GetNumArgs();
519  for( i = 0; i < numargs; i++ ) {
520  offset = ev->GetArgOffset( i );
521  data = event->data;
522  switch( formatspec[ i ] ) {
523  case D_EVENT_FLOAT :
524  case D_EVENT_INTEGER :
525  args[ i ] = *reinterpret_cast<int *>( &data[ offset ] );
526  break;
527 
528  case D_EVENT_VECTOR :
529  *reinterpret_cast<idVec3 **>( &args[ i ] ) = reinterpret_cast<idVec3 *>( &data[ offset ] );
530  break;
531 
532  case D_EVENT_STRING :
533  *reinterpret_cast<const char **>( &args[ i ] ) = reinterpret_cast<const char *>( &data[ offset ] );
534  break;
535 
536  case D_EVENT_ENTITY :
537  case D_EVENT_ENTITY_NULL :
538  *reinterpret_cast<idEntity **>( &args[ i ] ) = reinterpret_cast< idEntityPtr<idEntity> * >( &data[ offset ] )->GetEntity();
539  break;
540 
541  case D_EVENT_TRACE :
542  tracePtr = reinterpret_cast<trace_t **>( &args[ i ] );
543  if ( *reinterpret_cast<bool *>( &data[ offset ] ) ) {
544  *tracePtr = reinterpret_cast<trace_t *>( &data[ offset + sizeof( bool ) ] );
545 
546  if ( ( *tracePtr )->c.material != NULL ) {
547  // look up the material name to get the material pointer
548  materialName = reinterpret_cast<const char *>( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] );
549  ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true );
550  }
551  } else {
552  *tracePtr = NULL;
553  }
554  break;
555 
556  default:
557  gameLocal.Error( "idEvent::ServiceEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() );
558  }
559  }
560 
561  // the event is removed from its list so that if then object
562  // is deleted, the event won't be freed twice
563  event->eventNode.Remove();
564  assert( event->object );
565  event->object->ProcessEventArgPtr( ev, args );
566 
567 #if 0
568  // event functions may never leave return values on the FPU stack
569  // enable this code to check if any event call left values on the FPU stack
570  if ( !sys->FPU_StackIsEmpty() ) {
571  gameLocal.Error( "idEvent::ServiceEvents %d: %s left a value on the FPU stack\n", num, ev->GetName() );
572  }
573 #endif
574 
575  // return the event to the free list
576  event->Free();
577 
578  // Don't allow ourselves to stay in here too long. An abnormally high number
579  // of events being processed is evidence of an infinite loop of events.
580  num++;
581  if ( num > MAX_EVENTSPERFRAME ) {
582  gameLocal.Error( "Event overflow. Possible infinite loop in script." );
583  }
584  }
585 }
586 
587 #ifdef _D3XP
588 /*
589 ================
590 idEvent::ServiceFastEvents
591 ================
592 */
593 void idEvent::ServiceFastEvents() {
594  idEvent *event;
595  int num;
596  int args[ D_EVENT_MAXARGS ];
597  int offset;
598  int i;
599  int numargs;
600  const char *formatspec;
601  trace_t **tracePtr;
602  const idEventDef *ev;
603  byte *data;
604  const char *materialName;
605 
606  num = 0;
607  while( !FastEventQueue.IsListEmpty() ) {
608  event = FastEventQueue.Next();
609  assert( event );
610 
611  if ( event->time > gameLocal.fast.time ) {
612  break;
613  }
614 
615  // copy the data into the local args array and set up pointers
616  ev = event->eventdef;
617  formatspec = ev->GetArgFormat();
618  numargs = ev->GetNumArgs();
619  for( i = 0; i < numargs; i++ ) {
620  offset = ev->GetArgOffset( i );
621  data = event->data;
622  switch( formatspec[ i ] ) {
623  case D_EVENT_FLOAT :
624  case D_EVENT_INTEGER :
625  args[ i ] = *reinterpret_cast<int *>( &data[ offset ] );
626  break;
627 
628  case D_EVENT_VECTOR :
629  *reinterpret_cast<idVec3 **>( &args[ i ] ) = reinterpret_cast<idVec3 *>( &data[ offset ] );
630  break;
631 
632  case D_EVENT_STRING :
633  *reinterpret_cast<const char **>( &args[ i ] ) = reinterpret_cast<const char *>( &data[ offset ] );
634  break;
635 
636  case D_EVENT_ENTITY :
637  case D_EVENT_ENTITY_NULL :
638  *reinterpret_cast<idEntity **>( &args[ i ] ) = reinterpret_cast< idEntityPtr<idEntity> * >( &data[ offset ] )->GetEntity();
639  break;
640 
641  case D_EVENT_TRACE :
642  tracePtr = reinterpret_cast<trace_t **>( &args[ i ] );
643  if ( *reinterpret_cast<bool *>( &data[ offset ] ) ) {
644  *tracePtr = reinterpret_cast<trace_t *>( &data[ offset + sizeof( bool ) ] );
645 
646  if ( ( *tracePtr )->c.material != NULL ) {
647  // look up the material name to get the material pointer
648  materialName = reinterpret_cast<const char *>( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] );
649  ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true );
650  }
651  } else {
652  *tracePtr = NULL;
653  }
654  break;
655 
656  default:
657  gameLocal.Error( "idEvent::ServiceFastEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() );
658  }
659  }
660 
661  // the event is removed from its list so that if then object
662  // is deleted, the event won't be freed twice
663  event->eventNode.Remove();
664  assert( event->object );
665  event->object->ProcessEventArgPtr( ev, args );
666 
667 #if 0
668  // event functions may never leave return values on the FPU stack
669  // enable this code to check if any event call left values on the FPU stack
670  if ( !sys->FPU_StackIsEmpty() ) {
671  gameLocal.Error( "idEvent::ServiceEvents %d: %s left a value on the FPU stack\n", num, event->eventdef->GetName() );
672  }
673 #endif
674 
675  // return the event to the free list
676  event->Free();
677 
678  // Don't allow ourselves to stay in here too long. An abnormally high number
679  // of events being processed is evidence of an infinite loop of events.
680  num++;
681  if ( num > MAX_EVENTSPERFRAME ) {
682  gameLocal.Error( "Event overflow. Possible infinite loop in script." );
683  }
684  }
685 }
686 #endif
687 
688 /*
689 ================
690 idEvent::Init
691 ================
692 */
693 void idEvent::Init( void ) {
694  gameLocal.Printf( "Initializing event system\n" );
695 
696  if ( eventError ) {
697  gameLocal.Error( "%s", eventErrorMsg );
698  }
699 
700 #ifdef CREATE_EVENT_CODE
701  void CreateEventCallbackHandler();
702  CreateEventCallbackHandler();
703  gameLocal.Error( "Wrote event callback handler" );
704 #endif
705 
706  if ( initialized ) {
707  gameLocal.Printf( "...already initialized\n" );
708  ClearEventList();
709  return;
710  }
711 
712  ClearEventList();
713 
715 
716  gameLocal.Printf( "...%i event definitions\n", idEventDef::NumEventCommands() );
717 
718  // the event system has started
719  initialized = true;
720 }
721 
722 /*
723 ================
724 idEvent::Shutdown
725 ================
726 */
727 void idEvent::Shutdown( void ) {
728  gameLocal.Printf( "Shutdown event system\n" );
729 
730  if ( !initialized ) {
731  gameLocal.Printf( "...not started\n" );
732  return;
733  }
734 
735  ClearEventList();
736 
738 
739  // say it is now shutdown
740  initialized = false;
741 }
742 
743 /*
744 ================
745 idEvent::Save
746 ================
747 */
748 void idEvent::Save( idSaveGame *savefile ) {
749  char *str;
750  int i, size;
751  idEvent *event;
752  byte *dataPtr;
753  bool validTrace;
754  const char *format;
755 
756  savefile->WriteInt( EventQueue.Num() );
757 
758  event = EventQueue.Next();
759  while( event != NULL ) {
760  savefile->WriteInt( event->time );
761  savefile->WriteString( event->eventdef->GetName() );
762  savefile->WriteString( event->typeinfo->classname );
763  savefile->WriteObject( event->object );
764  savefile->WriteInt( event->eventdef->GetArgSize() );
765  format = event->eventdef->GetArgFormat();
766  for ( i = 0, size = 0; i < event->eventdef->GetNumArgs(); ++i) {
767  dataPtr = &event->data[ event->eventdef->GetArgOffset( i ) ];
768  switch( format[ i ] ) {
769  case D_EVENT_FLOAT :
770  savefile->WriteFloat( *reinterpret_cast<float *>( dataPtr ) );
771  size += sizeof( float );
772  break;
773  case D_EVENT_INTEGER :
774  case D_EVENT_ENTITY :
775  case D_EVENT_ENTITY_NULL :
776  savefile->WriteInt( *reinterpret_cast<int *>( dataPtr ) );
777  size += sizeof( int );
778  break;
779  case D_EVENT_VECTOR :
780  savefile->WriteVec3( *reinterpret_cast<idVec3 *>( dataPtr ) );
781  size += sizeof( idVec3 );
782  break;
783  case D_EVENT_TRACE :
784  validTrace = *reinterpret_cast<bool *>( dataPtr );
785  savefile->WriteBool( validTrace );
786  size += sizeof( bool );
787  if ( validTrace ) {
788  size += sizeof( trace_t );
789  const trace_t &t = *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) );
790  SaveTrace( savefile, t );
791  if ( t.c.material ) {
792  size += MAX_STRING_LEN;
793  str = reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) );
794  savefile->Write( str, MAX_STRING_LEN );
795  }
796  }
797  break;
798  default:
799  break;
800  }
801  }
802  assert( size == event->eventdef->GetArgSize() );
803  event = event->eventNode.Next();
804  }
805 
806 #ifdef _D3XP
807  // Save the Fast EventQueue
808  savefile->WriteInt( FastEventQueue.Num() );
809 
810  event = FastEventQueue.Next();
811  while( event != NULL ) {
812  savefile->WriteInt( event->time );
813  savefile->WriteString( event->eventdef->GetName() );
814  savefile->WriteString( event->typeinfo->classname );
815  savefile->WriteObject( event->object );
816  savefile->WriteInt( event->eventdef->GetArgSize() );
817  savefile->Write( event->data, event->eventdef->GetArgSize() );
818 
819  event = event->eventNode.Next();
820  }
821 #endif
822 }
823 
824 /*
825 ================
826 idEvent::Restore
827 ================
828 */
829 void idEvent::Restore( idRestoreGame *savefile ) {
830  char *str;
831  int num, argsize, i, j, size;
832  idStr name;
833  byte *dataPtr;
834  idEvent *event;
835  const char *format;
836 
837  savefile->ReadInt( num );
838 
839  for ( i = 0; i < num; i++ ) {
840  if ( FreeEvents.IsListEmpty() ) {
841  gameLocal.Error( "idEvent::Restore : No more free events" );
842  }
843 
844  event = FreeEvents.Next();
845  event->eventNode.Remove();
846  event->eventNode.AddToEnd( EventQueue );
847 
848  savefile->ReadInt( event->time );
849 
850  // read the event name
851  savefile->ReadString( name );
852  event->eventdef = idEventDef::FindEvent( name );
853  if ( !event->eventdef ) {
854  savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() );
855  }
856 
857  // read the classtype
858  savefile->ReadString( name );
859  event->typeinfo = idClass::GetClass( name );
860  if ( !event->typeinfo ) {
861  savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() );
862  }
863 
864  savefile->ReadObject( event->object );
865 
866  // read the args
867  savefile->ReadInt( argsize );
868  if ( argsize != event->eventdef->GetArgSize() ) {
869  savefile->Error( "idEvent::Restore: arg size (%d) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() );
870  }
871  if ( argsize ) {
872  event->data = eventDataAllocator.Alloc( argsize );
873  format = event->eventdef->GetArgFormat();
874  assert( format );
875  for ( j = 0, size = 0; j < event->eventdef->GetNumArgs(); ++j) {
876  dataPtr = &event->data[ event->eventdef->GetArgOffset( j ) ];
877  switch( format[ j ] ) {
878  case D_EVENT_FLOAT :
879  savefile->ReadFloat( *reinterpret_cast<float *>( dataPtr ) );
880  size += sizeof( float );
881  break;
882  case D_EVENT_INTEGER :
883  case D_EVENT_ENTITY :
884  case D_EVENT_ENTITY_NULL :
885  savefile->ReadInt( *reinterpret_cast<int *>( dataPtr ) );
886  size += sizeof( int );
887  break;
888  case D_EVENT_VECTOR :
889  savefile->ReadVec3( *reinterpret_cast<idVec3 *>( dataPtr ) );
890  size += sizeof( idVec3 );
891  break;
892  case D_EVENT_TRACE :
893  savefile->ReadBool( *reinterpret_cast<bool *>( dataPtr ) );
894  size += sizeof( bool );
895  if ( *reinterpret_cast<bool *>( dataPtr ) ) {
896  size += sizeof( trace_t );
897  trace_t &t = *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) );
898  RestoreTrace( savefile, t) ;
899  if ( t.c.material ) {
900  size += MAX_STRING_LEN;
901  str = reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) );
902  savefile->Read( str, MAX_STRING_LEN );
903  }
904  }
905  break;
906  default:
907  break;
908  }
909  }
910  assert( size == event->eventdef->GetArgSize() );
911  } else {
912  event->data = NULL;
913  }
914  }
915 
916 #ifdef _D3XP
917  // Restore the Fast EventQueue
918  savefile->ReadInt( num );
919 
920  for ( i = 0; i < num; i++ ) {
921  if ( FreeEvents.IsListEmpty() ) {
922  gameLocal.Error( "idEvent::Restore : No more free events" );
923  }
924 
925  event = FreeEvents.Next();
926  event->eventNode.Remove();
927  event->eventNode.AddToEnd( FastEventQueue );
928 
929  savefile->ReadInt( event->time );
930 
931  // read the event name
932  savefile->ReadString( name );
933  event->eventdef = idEventDef::FindEvent( name );
934  if ( !event->eventdef ) {
935  savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() );
936  }
937 
938  // read the classtype
939  savefile->ReadString( name );
940  event->typeinfo = idClass::GetClass( name );
941  if ( !event->typeinfo ) {
942  savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() );
943  }
944 
945  savefile->ReadObject( event->object );
946 
947  // read the args
948  savefile->ReadInt( argsize );
949  if ( argsize != event->eventdef->GetArgSize() ) {
950  savefile->Error( "idEvent::Restore: arg size (%d) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() );
951  }
952  if ( argsize ) {
953  event->data = eventDataAllocator.Alloc( argsize );
954  savefile->Read( event->data, argsize );
955  } else {
956  event->data = NULL;
957  }
958  }
959 #endif
960 }
961 
962 /*
963  ================
964  idEvent::ReadTrace
965 
966  idRestoreGame has a ReadTrace procedure, but unfortunately idEvent wants the material
967  string name at the of the data structure rather than in the middle
968  ================
969  */
970 void idEvent::RestoreTrace( idRestoreGame *savefile, trace_t &trace ) {
971  savefile->ReadFloat( trace.fraction );
972  savefile->ReadVec3( trace.endpos );
973  savefile->ReadMat3( trace.endAxis );
974  savefile->ReadInt( (int&)trace.c.type );
975  savefile->ReadVec3( trace.c.point );
976  savefile->ReadVec3( trace.c.normal );
977  savefile->ReadFloat( trace.c.dist );
978  savefile->ReadInt( trace.c.contents );
979  savefile->ReadInt( (int&)trace.c.material );
980  savefile->ReadInt( trace.c.contents );
981  savefile->ReadInt( trace.c.modelFeature );
982  savefile->ReadInt( trace.c.trmFeature );
983  savefile->ReadInt( trace.c.id );
984 }
985 
986 /*
987  ================
988  idEvent::WriteTrace
989 
990  idSaveGame has a WriteTrace procedure, but unfortunately idEvent wants the material
991  string name at the of the data structure rather than in the middle
992 ================
993  */
994 void idEvent::SaveTrace( idSaveGame *savefile, const trace_t &trace ) {
995  savefile->WriteFloat( trace.fraction );
996  savefile->WriteVec3( trace.endpos );
997  savefile->WriteMat3( trace.endAxis );
998  savefile->WriteInt( trace.c.type );
999  savefile->WriteVec3( trace.c.point );
1000  savefile->WriteVec3( trace.c.normal );
1001  savefile->WriteFloat( trace.c.dist );
1002  savefile->WriteInt( trace.c.contents );
1003  savefile->WriteInt( (int&)trace.c.material );
1004  savefile->WriteInt( trace.c.contents );
1005  savefile->WriteInt( trace.c.modelFeature );
1006  savefile->WriteInt( trace.c.trmFeature );
1007  savefile->WriteInt( trace.c.id );
1008 }
1009 
1010 
1011 
1012 #ifdef CREATE_EVENT_CODE
1013 /*
1014 ================
1015 CreateEventCallbackHandler
1016 ================
1017 */
1018 void CreateEventCallbackHandler( void ) {
1019  int num;
1020  int count;
1021  int i, j, k;
1022  char argString[ D_EVENT_MAXARGS + 1 ];
1023  idStr string1;
1024  idStr string2;
1025  idFile *file;
1026 
1027  file = fileSystem->OpenFileWrite( "Callbacks.cpp" );
1028 
1029  file->Printf( "// generated file - see CREATE_EVENT_CODE\n\n" );
1030 
1031  for( i = 1; i <= D_EVENT_MAXARGS; i++ ) {
1032 
1033  file->Printf( "\t/*******************************************************\n\n\t\t%d args\n\n\t*******************************************************/\n\n", i );
1034 
1035  for ( j = 0; j < ( 1 << i ); j++ ) {
1036  for( k = 0; k < i; k++ ) {
1037  argString[ k ] = j & ( 1 << k ) ? 'f' : 'i';
1038  }
1039  argString[ i ] = '\0';
1040 
1041  string1.Empty();
1042  string2.Empty();
1043 
1044  for( k = 0; k < i; k++ ) {
1045  if ( j & ( 1 << k ) ) {
1046  string1 += "const float";
1047  string2 += va( "*( float * )&data[ %d ]", k );
1048  } else {
1049  string1 += "const int";
1050  string2 += va( "data[ %d ]", k );
1051  }
1052 
1053  if ( k < i - 1 ) {
1054  string1 += ", ";
1055  string2 += ", ";
1056  }
1057  }
1058 
1059  file->Printf( "\tcase %d :\n\t\ttypedef void ( idClass::*eventCallback_%s_t )( %s );\n", ( 1 << ( i + D_EVENT_MAXARGS ) ) + j, argString, string1.c_str() );
1060  file->Printf( "\t\t( this->*( eventCallback_%s_t )callback )( %s );\n\t\tbreak;\n\n", argString, string2.c_str() );
1061 
1062  }
1063  }
1064 
1065  fileSystem->CloseFile( file );
1066 }
1067 
1068 #endif
int argOffset[D_EVENT_MAXARGS]
Definition: Event.h:61
#define strcmp
Definition: Str.h:41
void Free(void)
Definition: Event.cpp:365
int returnType
Definition: Event.h:58
void WriteString(const char *string)
Definition: SaveGame.cpp:231
assert(prefInfo.fullscreenBtn)
static void Shutdown(void)
Definition: Event.cpp:727
void WriteObject(const idClass *obj)
Definition: SaveGame.cpp:329
const char * name
Definition: Event.h:55
void Printf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:699
virtual bool FPU_StackIsEmpty(void)=0
type * GetEntity(void) const
Definition: Game_local.h:695
GLenum GLsizei GLenum format
Definition: glext.h:2846
#define D_EVENT_ENTITY_NULL
Definition: Event.h:45
void void void void void Error(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:783
size_t argsize
Definition: Event.h:60
bool IsType(const idTypeInfo &c) const
Definition: Class.h:337
#define D_EVENT_STRING
Definition: Event.h:43
void Write(const void *buffer, int len)
Definition: SaveGame.cpp:159
unsigned int formatspecIndex
Definition: Event.h:57
static void RestoreTrace(idRestoreGame *savefile, trace_t &trace)
Definition: Event.cpp:970
case const int
Definition: Callbacks.cpp:52
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
idLinkList< idEvent > eventNode
Definition: Event.h:96
static int numEventDefs
Definition: Event.h:66
Definition: Vector.h:316
case const float
Definition: Callbacks.cpp:62
void ReadBool(bool &value)
Definition: SaveGame.cpp:976
#define MAX_STRING_LEN
contactType_t type
const char * formatspec
Definition: Event.h:56
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
static void ClearEventList(void)
Definition: Event.cpp:471
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
#define D_EVENT_ENTITY
Definition: Event.h:44
GLhandleARB obj
Definition: glext.h:3602
type * Alloc(const int num)
Definition: Heap.h:570
int i
Definition: process.py:33
GLintptr offset
Definition: glext.h:3113
static idEventDef * eventDefList[MAX_EVENTS]
Definition: Event.h:65
contactInfo_t c
GLuint GLuint num
Definition: glext.h:5390
void WriteVec3(const idVec3 &vec)
Definition: SaveGame.cpp:253
static int NumEventCommands(void)
Definition: Event.cpp:174
void Free(type *ptr)
Definition: Heap.h:631
#define D_EVENT_FLOAT
Definition: Event.h:41
Definition: Class.h:174
idClass * object
Definition: Event.h:93
float fraction
const idTypeInfo * typeinfo
Definition: Event.h:94
idVec3 endpos
size_t GetArgSize(void) const
Definition: Event.h:189
~idEvent()
Definition: Event.cpp:232
void WriteBool(const bool value)
Definition: SaveGame.cpp:222
byte * data
Definition: Event.h:91
Definition: File.h:50
int numargs
Definition: Event.h:59
const idMaterial * material
GLuint GLuint GLsizei count
Definition: glext.h:2845
void Shutdown(void)
Definition: Heap.h:461
static const idEventDef * FindEvent(const char *name)
Definition: Event.cpp:192
const char * GetName(void) const
Definition: Event.h:144
const GLubyte * c
Definition: glext.h:4677
void ReadFloat(float &value)
Definition: SaveGame.cpp:967
int value
Definition: Class.h:60
idSys * sys
Definition: maya_main.cpp:48
void Empty(void)
Definition: Str.h:714
void void Read(void *buffer, int len)
Definition: SaveGame.cpp:913
static void Save(idSaveGame *savefile)
Definition: Event.cpp:748
void WriteFloat(const float value)
Definition: SaveGame.cpp:213
int type
Definition: Class.h:59
Definition: Event.h:88
#define NULL
Definition: Lib.h:88
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
#define D_EVENT_VECTOR
Definition: Event.h:42
static idTypeInfo * GetClass(const char *name)
Definition: Class.cpp:530
virtual idFile * OpenFileWrite(const char *relativePath, const char *basePath="fs_savepath")=0
int time
Definition: Event.h:92
static void Copynz(char *dest, const char *src, int destsize)
Definition: Str.cpp:1376
idEventDef(const char *command, const char *formatspec=NULL, char returnType=0)
Definition: Event.cpp:60
#define D_EVENT_TRACE
Definition: Event.h:46
idMat3 endAxis
void Schedule(idClass *object, const idTypeInfo *cls, int time)
Definition: Event.cpp:385
#define D_EVENT_MAXARGS
Definition: Event.h:36
#define MAX_EVENTS
Definition: Event.h:48
static const idEventDef * GetEventCommand(int eventnum)
Definition: Event.cpp:183
static bool initialized
Definition: Event.h:102
idGameLocal gameLocal
Definition: Game_local.cpp:64
void Error(const char *fmt,...) id_attribute((format(printf
Definition: SaveGame.cpp:878
#define MAX_EVENTSPERFRAME
Definition: Event.cpp:40
int GetNumArgs(void) const
Definition: Event.h:180
void Init(void)
Definition: Heap.h:456
int eventnum
Definition: Event.h:62
void WriteInt(const int value)
Definition: SaveGame.cpp:168
idDeclManager * declManager
void WriteMat3(const idMat3 &mat)
Definition: SaveGame.cpp:309
void ReadMat3(idMat3 &mat)
Definition: SaveGame.cpp:1064
#define bits
Definition: Unzip.cpp:3797
static idDynamicBlockAlloc< byte, 16 *1024, 256 > eventDataAllocator
Definition: Event.h:98
unsigned char byte
Definition: Lib.h:75
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
const idEventDef * eventdef
Definition: Event.h:90
const char * GetArgFormat(void) const
Definition: Event.h:153
Definition: Str.h:116
static void Restore(idRestoreGame *savefile)
Definition: Event.cpp:829
static void ServiceEvents(void)
Definition: Event.cpp:493
void ReadVec3(idVec3 &vec)
Definition: SaveGame.cpp:1011
const char * c_str(void) const
Definition: Str.h:487
struct trace_s trace_t
static void SaveTrace(idSaveGame *savefile, const trace_t &trace)
Definition: Event.cpp:994
unsigned char bool
Definition: setup.h:74
GLint j
Definition: qgl.h:264
static void CopyArgs(const idEventDef *evdef, int numargs, va_list args, int data[D_EVENT_MAXARGS])
Definition: Event.cpp:337
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
const char * classname
Definition: Class.h:273
char * va(const char *fmt,...)
Definition: Str.cpp:1568
virtual void CloseFile(idFile *f)=0
static idEvent * Alloc(const idEventDef *evdef, int numargs, va_list args)
Definition: Event.cpp:241
static void CancelEvents(const idClass *obj, const idEventDef *evdef=NULL)
Definition: Event.cpp:437
#define D_EVENT_INTEGER
Definition: Event.h:40
void ReadString(idStr &string)
Definition: SaveGame.cpp:985
static void Init(void)
Definition: Event.cpp:693
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
void ReadInt(int &value)
Definition: SaveGame.cpp:922
int GetArgOffset(int arg) const
Definition: Event.h:198
virtual int Printf(const char *fmt,...) id_attribute((format(printf
Definition: File.cpp:260
void ReadObject(idClass *&obj)
Definition: SaveGame.cpp:1083
GLdouble GLdouble t
Definition: glext.h:2943