1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- /*
- sys_event.cpp
- Event are used for scheduling tasks and for linking script commands.
- */
- #pragma hdrstop
- #include "../../idlib/precompiled.h"
- #include "../Game_local.h"
- #define MAX_EVENTSPERFRAME 4096
- //#define CREATE_EVENT_CODE
- /***********************************************************************
- idEventDef
- ***********************************************************************/
- idEventDef *idEventDef::eventDefList[MAX_EVENTS];
- int idEventDef::numEventDefs = 0;
- static bool eventError = false;
- static char eventErrorMsg[ 128 ];
- /*
- ================
- idEventDef::idEventDef
- ================
- */
- idEventDef::idEventDef( const char *command, const char *formatspec, char returnType ) {
- idEventDef *ev;
- int i;
- unsigned int bits;
- assert( command );
- assert( !idEvent::initialized );
- // Allow NULL to indicate no args, but always store it as ""
- // so we don't have to check for it.
- if ( !formatspec ) {
- formatspec = "";
- }
- this->name = command;
- this->formatspec = formatspec;
- this->returnType = returnType;
- numargs = strlen( formatspec );
- assert( numargs <= D_EVENT_MAXARGS );
- if ( numargs > D_EVENT_MAXARGS ) {
- eventError = true;
- sprintf( eventErrorMsg, "idEventDef::idEventDef : Too many args for '%s' event.", name );
- return;
- }
- // make sure the format for the args is valid, calculate the formatspecindex, and the offsets for each arg
- bits = 0;
- argsize = 0;
- memset( argOffset, 0, sizeof( argOffset ) );
- for( i = 0; i < numargs;i++ ) {
- argOffset[ i ] = argsize;
- switch( formatspec[ i ] ) {
- case D_EVENT_FLOAT :
- bits |= 1 << i;
- argsize += sizeof( float );
- break;
- case D_EVENT_INTEGER :
- argsize += sizeof( int );
- break;
- case D_EVENT_VECTOR :
- argsize += sizeof( idVec3 );
- break;
- case D_EVENT_STRING :
- argsize += MAX_STRING_LEN;
- break;
- case D_EVENT_ENTITY :
- argsize += sizeof( idEntityPtr<idEntity> );
- break;
- case D_EVENT_ENTITY_NULL :
- argsize += sizeof( idEntityPtr<idEntity> );
- break;
- case D_EVENT_TRACE :
- argsize += sizeof( trace_t ) + MAX_STRING_LEN + sizeof( bool );
- break;
- default :
- eventError = true;
- sprintf( eventErrorMsg, "idEventDef::idEventDef : Invalid arg format '%s' string for '%s' event.", formatspec, name );
- return;
- break;
- }
- }
- // calculate the formatspecindex
- formatspecIndex = ( 1 << ( numargs + D_EVENT_MAXARGS ) ) | bits;
- // go through the list of defined events and check for duplicates
- // and mismatched format strings
- eventnum = numEventDefs;
- for( i = 0; i < eventnum; i++ ) {
- ev = eventDefList[ i ];
- if ( strcmp( command, ev->name ) == 0 ) {
- if ( strcmp( formatspec, ev->formatspec ) != 0 ) {
- eventError = true;
- sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing format strings ('%s'!='%s').",
- command, formatspec, ev->formatspec );
- return;
- }
- if ( ev->returnType != returnType ) {
- eventError = true;
- sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing return types ('%c'!='%c').",
- command, returnType, ev->returnType );
- return;
- }
- // Don't bother putting the duplicate event in list.
- eventnum = ev->eventnum;
- return;
- }
- }
- ev = this;
- if ( numEventDefs >= MAX_EVENTS ) {
- eventError = true;
- sprintf( eventErrorMsg, "numEventDefs >= MAX_EVENTS" );
- return;
- }
- eventDefList[numEventDefs] = ev;
- numEventDefs++;
- }
- /*
- ================
- idEventDef::NumEventCommands
- ================
- */
- int idEventDef::NumEventCommands() {
- return numEventDefs;
- }
- /*
- ================
- idEventDef::GetEventCommand
- ================
- */
- const idEventDef *idEventDef::GetEventCommand( int eventnum ) {
- return eventDefList[ eventnum ];
- }
- /*
- ================
- idEventDef::FindEvent
- ================
- */
- const idEventDef *idEventDef::FindEvent( const char *name ) {
- idEventDef *ev;
- int num;
- int i;
- assert( name );
- num = numEventDefs;
- for( i = 0; i < num; i++ ) {
- ev = eventDefList[ i ];
- if ( strcmp( name, ev->name ) == 0 ) {
- return ev;
- }
- }
- return NULL;
- }
- /***********************************************************************
- idEvent
- ***********************************************************************/
- static idLinkList<idEvent> FreeEvents;
- static idLinkList<idEvent> EventQueue;
- static idLinkList<idEvent> FastEventQueue;
- static idEvent EventPool[ MAX_EVENTS ];
- bool idEvent::initialized = false;
- idDynamicBlockAlloc<byte, 16 * 1024, 256> idEvent::eventDataAllocator;
- /*
- ================
- idEvent::~idEvent()
- ================
- */
- idEvent::~idEvent() {
- Free();
- }
- /*
- ================
- idEvent::Alloc
- ================
- */
- idEvent *idEvent::Alloc( const idEventDef *evdef, int numargs, va_list args ) {
- idEvent *ev;
- size_t size;
- const char *format;
- idEventArg *arg;
- byte *dataPtr;
- int i;
- const char *materialName;
- if ( FreeEvents.IsListEmpty() ) {
- gameLocal.Error( "idEvent::Alloc : No more free events" );
- }
- ev = FreeEvents.Next();
- ev->eventNode.Remove();
- ev->eventdef = evdef;
- if ( numargs != evdef->GetNumArgs() ) {
- gameLocal.Error( "idEvent::Alloc : Wrong number of args for '%s' event.", evdef->GetName() );
- }
- size = evdef->GetArgSize();
- if ( size ) {
- ev->data = eventDataAllocator.Alloc( size );
- memset( ev->data, 0, size );
- } else {
- ev->data = NULL;
- return ev;
- }
- format = evdef->GetArgFormat();
- for( i = 0; i < numargs; i++ ) {
- arg = va_arg( args, idEventArg * );
- if ( format[ i ] != arg->type ) {
- // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens
- if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) {
- gameLocal.Error( "idEvent::Alloc : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() );
- }
- }
- dataPtr = &ev->data[ evdef->GetArgOffset( i ) ];
- switch( format[ i ] ) {
- case D_EVENT_FLOAT :
- case D_EVENT_INTEGER :
- *reinterpret_cast<int *>( dataPtr ) = arg->value;
- break;
- case D_EVENT_VECTOR :
- if ( arg->value ) {
- *reinterpret_cast<idVec3 *>( dataPtr ) = *reinterpret_cast<const idVec3 *>( arg->value );
- }
- break;
- case D_EVENT_STRING :
- if ( arg->value ) {
- idStr::Copynz( reinterpret_cast<char *>( dataPtr ), reinterpret_cast<const char *>( arg->value ), MAX_STRING_LEN );
- }
- break;
- case D_EVENT_ENTITY :
- case D_EVENT_ENTITY_NULL :
- *reinterpret_cast< idEntityPtr<idEntity> * >( dataPtr ) = reinterpret_cast<idEntity *>( arg->value );
- break;
- case D_EVENT_TRACE :
- if ( arg->value ) {
- *reinterpret_cast<bool *>( dataPtr ) = true;
- *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) ) = *reinterpret_cast<const trace_t *>( arg->value );
- // save off the material as a string since the pointer won't be valid in save games.
- // since we save off the entire trace_t structure, if the material is NULL here,
- // it will be NULL when we process it, so we don't need to save off anything in that case.
- if ( reinterpret_cast<const trace_t *>( arg->value )->c.material ) {
- materialName = reinterpret_cast<const trace_t *>( arg->value )->c.material->GetName();
- idStr::Copynz( reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) ), materialName, MAX_STRING_LEN );
- }
- } else {
- *reinterpret_cast<bool *>( dataPtr ) = false;
- }
- break;
- default :
- gameLocal.Error( "idEvent::Alloc : Invalid arg format '%s' string for '%s' event.", format, evdef->GetName() );
- break;
- }
- }
- return ev;
- }
- /*
- ================
- idEvent::CopyArgs
- ================
- */
- void idEvent::CopyArgs( const idEventDef *evdef, int numargs, va_list args, int data[ D_EVENT_MAXARGS ] ) {
- int i;
- const char *format;
- idEventArg *arg;
- format = evdef->GetArgFormat();
- if ( numargs != evdef->GetNumArgs() ) {
- gameLocal.Error( "idEvent::CopyArgs : Wrong number of args for '%s' event.", evdef->GetName() );
- }
- for( i = 0; i < numargs; i++ ) {
- arg = va_arg( args, idEventArg * );
- if ( format[ i ] != arg->type ) {
- // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens
- if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) {
- gameLocal.Error( "idEvent::CopyArgs : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() );
- }
- }
- data[ i ] = arg->value;
- }
- }
- /*
- ================
- idEvent::Free
- ================
- */
- void idEvent::Free() {
- if ( data ) {
- eventDataAllocator.Free( data );
- data = NULL;
- }
- eventdef = NULL;
- time = 0;
- object = NULL;
- typeinfo = NULL;
- eventNode.SetOwner( this );
- eventNode.AddToEnd( FreeEvents );
- }
- /*
- ================
- idEvent::Schedule
- ================
- */
- void idEvent::Schedule( idClass *obj, const idTypeInfo *type, int time ) {
- idEvent *event;
- assert( initialized );
- if ( !initialized ) {
- return;
- }
- object = obj;
- typeinfo = type;
- // wraps after 24 days...like I care. ;)
- this->time = gameLocal.time + time;
- eventNode.Remove();
- if ( obj->IsType( idEntity::Type ) && ( ( (idEntity*)(obj) )->timeGroup == TIME_GROUP2 ) ) {
- event = FastEventQueue.Next();
- while( ( event != NULL ) && ( this->time >= event->time ) ) {
- event = event->eventNode.Next();
- }
- if ( event ) {
- eventNode.InsertBefore( event->eventNode );
- } else {
- eventNode.AddToEnd( FastEventQueue );
- }
- return;
- } else {
- this->time = gameLocal.slow.time + time;
- }
- event = EventQueue.Next();
- while( ( event != NULL ) && ( this->time >= event->time ) ) {
- event = event->eventNode.Next();
- }
- if ( event ) {
- eventNode.InsertBefore( event->eventNode );
- } else {
- eventNode.AddToEnd( EventQueue );
- }
- }
- /*
- ================
- idEvent::CancelEvents
- ================
- */
- void idEvent::CancelEvents( const idClass *obj, const idEventDef *evdef ) {
- idEvent *event;
- idEvent *next;
- if ( !initialized ) {
- return;
- }
- for( event = EventQueue.Next(); event != NULL; event = next ) {
- next = event->eventNode.Next();
- if ( event->object == obj ) {
- if ( !evdef || ( evdef == event->eventdef ) ) {
- event->Free();
- }
- }
- }
- for( event = FastEventQueue.Next(); event != NULL; event = next ) {
- next = event->eventNode.Next();
- if ( event->object == obj ) {
- if ( !evdef || ( evdef == event->eventdef ) ) {
- event->Free();
- }
- }
- }
- }
- /*
- ================
- idEvent::ClearEventList
- ================
- */
- void idEvent::ClearEventList() {
- int i;
- //
- // initialize lists
- //
- FreeEvents.Clear();
- EventQueue.Clear();
-
- //
- // add the events to the free list
- //
- for( i = 0; i < MAX_EVENTS; i++ ) {
- EventPool[ i ].Free();
- }
- }
- /*
- ================
- idEvent::ServiceEvents
- ================
- */
- void idEvent::ServiceEvents() {
- idEvent *event;
- int num;
- int args[ D_EVENT_MAXARGS ];
- int offset;
- int i;
- int numargs;
- const char *formatspec;
- trace_t **tracePtr;
- const idEventDef *ev;
- byte *data;
- const char *materialName;
- num = 0;
- while( !EventQueue.IsListEmpty() ) {
- event = EventQueue.Next();
- assert( event );
- if ( event->time > gameLocal.time ) {
- break;
- }
- common->UpdateLevelLoadPacifier();
- // copy the data into the local args array and set up pointers
- ev = event->eventdef;
- formatspec = ev->GetArgFormat();
- numargs = ev->GetNumArgs();
- for( i = 0; i < numargs; i++ ) {
- offset = ev->GetArgOffset( i );
- data = event->data;
- switch( formatspec[ i ] ) {
- case D_EVENT_FLOAT :
- case D_EVENT_INTEGER :
- args[ i ] = *reinterpret_cast<int *>( &data[ offset ] );
- break;
- case D_EVENT_VECTOR :
- *reinterpret_cast<idVec3 **>( &args[ i ] ) = reinterpret_cast<idVec3 *>( &data[ offset ] );
- break;
- case D_EVENT_STRING :
- *reinterpret_cast<const char **>( &args[ i ] ) = reinterpret_cast<const char *>( &data[ offset ] );
- break;
- case D_EVENT_ENTITY :
- case D_EVENT_ENTITY_NULL :
- *reinterpret_cast<idEntity **>( &args[ i ] ) = reinterpret_cast< idEntityPtr<idEntity> * >( &data[ offset ] )->GetEntity();
- break;
- case D_EVENT_TRACE :
- tracePtr = reinterpret_cast<trace_t **>( &args[ i ] );
- if ( *reinterpret_cast<bool *>( &data[ offset ] ) ) {
- *tracePtr = reinterpret_cast<trace_t *>( &data[ offset + sizeof( bool ) ] );
- if ( ( *tracePtr )->c.material != NULL ) {
- // look up the material name to get the material pointer
- materialName = reinterpret_cast<const char *>( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] );
- ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true );
- }
- } else {
- *tracePtr = NULL;
- }
- break;
- default:
- gameLocal.Error( "idEvent::ServiceEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() );
- }
- }
- // the event is removed from its list so that if then object
- // is deleted, the event won't be freed twice
- event->eventNode.Remove();
- assert( event->object );
- event->object->ProcessEventArgPtr( ev, args );
- #if 0
- // event functions may never leave return values on the FPU stack
- // enable this code to check if any event call left values on the FPU stack
- if ( !sys->FPU_StackIsEmpty() ) {
- gameLocal.Error( "idEvent::ServiceEvents %d: %s left a value on the FPU stack\n", num, ev->GetName() );
- }
- #endif
- // return the event to the free list
- event->Free();
- // Don't allow ourselves to stay in here too long. An abnormally high number
- // of events being processed is evidence of an infinite loop of events.
- num++;
- if ( num > MAX_EVENTSPERFRAME ) {
- gameLocal.Error( "Event overflow. Possible infinite loop in script." );
- }
- }
- }
- /*
- ================
- idEvent::ServiceFastEvents
- ================
- */
- void idEvent::ServiceFastEvents() {
- idEvent *event;
- int num;
- int args[ D_EVENT_MAXARGS ];
- int offset;
- int i;
- int numargs;
- const char *formatspec;
- trace_t **tracePtr;
- const idEventDef *ev;
- byte *data;
- const char *materialName;
- num = 0;
- while( !FastEventQueue.IsListEmpty() ) {
- event = FastEventQueue.Next();
- assert( event );
- if ( event->time > gameLocal.fast.time ) {
- break;
- }
- // copy the data into the local args array and set up pointers
- ev = event->eventdef;
- formatspec = ev->GetArgFormat();
- numargs = ev->GetNumArgs();
- for( i = 0; i < numargs; i++ ) {
- offset = ev->GetArgOffset( i );
- data = event->data;
- switch( formatspec[ i ] ) {
- case D_EVENT_FLOAT :
- case D_EVENT_INTEGER :
- args[ i ] = *reinterpret_cast<int *>( &data[ offset ] );
- break;
- case D_EVENT_VECTOR :
- *reinterpret_cast<idVec3 **>( &args[ i ] ) = reinterpret_cast<idVec3 *>( &data[ offset ] );
- break;
- case D_EVENT_STRING :
- *reinterpret_cast<const char **>( &args[ i ] ) = reinterpret_cast<const char *>( &data[ offset ] );
- break;
- case D_EVENT_ENTITY :
- case D_EVENT_ENTITY_NULL :
- *reinterpret_cast<idEntity **>( &args[ i ] ) = reinterpret_cast< idEntityPtr<idEntity> * >( &data[ offset ] )->GetEntity();
- break;
- case D_EVENT_TRACE :
- tracePtr = reinterpret_cast<trace_t **>( &args[ i ] );
- if ( *reinterpret_cast<bool *>( &data[ offset ] ) ) {
- *tracePtr = reinterpret_cast<trace_t *>( &data[ offset + sizeof( bool ) ] );
- if ( ( *tracePtr )->c.material != NULL ) {
- // look up the material name to get the material pointer
- materialName = reinterpret_cast<const char *>( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] );
- ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true );
- }
- } else {
- *tracePtr = NULL;
- }
- break;
- default:
- gameLocal.Error( "idEvent::ServiceFastEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() );
- }
- }
- // the event is removed from its list so that if then object
- // is deleted, the event won't be freed twice
- event->eventNode.Remove();
- assert( event->object );
- event->object->ProcessEventArgPtr( ev, args );
- #if 0
- // event functions may never leave return values on the FPU stack
- // enable this code to check if any event call left values on the FPU stack
- if ( !sys->FPU_StackIsEmpty() ) {
- gameLocal.Error( "idEvent::ServiceEvents %d: %s left a value on the FPU stack\n", num, event->eventdef->GetName() );
- }
- #endif
- // return the event to the free list
- event->Free();
- // Don't allow ourselves to stay in here too long. An abnormally high number
- // of events being processed is evidence of an infinite loop of events.
- num++;
- if ( num > MAX_EVENTSPERFRAME ) {
- gameLocal.Error( "Event overflow. Possible infinite loop in script." );
- }
- }
- }
- /*
- ================
- idEvent::Init
- ================
- */
- void idEvent::Init() {
- gameLocal.Printf( "Initializing event system\n" );
- if ( eventError ) {
- gameLocal.Error( "%s", eventErrorMsg );
- }
- #ifdef CREATE_EVENT_CODE
- void CreateEventCallbackHandler();
- CreateEventCallbackHandler();
- gameLocal.Error( "Wrote event callback handler" );
- #endif
- if ( initialized ) {
- gameLocal.Printf( "...already initialized\n" );
- ClearEventList();
- return;
- }
- ClearEventList();
- eventDataAllocator.Init();
- gameLocal.Printf( "...%i event definitions\n", idEventDef::NumEventCommands() );
- // the event system has started
- initialized = true;
- }
- /*
- ================
- idEvent::Shutdown
- ================
- */
- void idEvent::Shutdown() {
- gameLocal.Printf( "Shutdown event system\n" );
- if ( !initialized ) {
- gameLocal.Printf( "...not started\n" );
- return;
- }
- ClearEventList();
-
- eventDataAllocator.Shutdown();
- // say it is now shutdown
- initialized = false;
- }
- /*
- ================
- idEvent::Save
- ================
- */
- void idEvent::Save( idSaveGame *savefile ) {
- char *str;
- int i, size;
- idEvent *event;
- byte *dataPtr;
- bool validTrace;
- const char *format;
- savefile->WriteInt( EventQueue.Num() );
- event = EventQueue.Next();
- while( event != NULL ) {
- savefile->WriteInt( event->time );
- savefile->WriteString( event->eventdef->GetName() );
- savefile->WriteString( event->typeinfo->classname );
- savefile->WriteObject( event->object );
- savefile->WriteInt( event->eventdef->GetArgSize() );
- format = event->eventdef->GetArgFormat();
- for ( i = 0, size = 0; i < event->eventdef->GetNumArgs(); ++i) {
- dataPtr = &event->data[ event->eventdef->GetArgOffset( i ) ];
- switch( format[ i ] ) {
- case D_EVENT_FLOAT :
- savefile->WriteFloat( *reinterpret_cast<float *>( dataPtr ) );
- size += sizeof( float );
- break;
- case D_EVENT_INTEGER :
- case D_EVENT_ENTITY :
- case D_EVENT_ENTITY_NULL :
- savefile->WriteInt( *reinterpret_cast<int *>( dataPtr ) );
- size += sizeof( int );
- break;
- case D_EVENT_VECTOR :
- savefile->WriteVec3( *reinterpret_cast<idVec3 *>( dataPtr ) );
- size += sizeof( idVec3 );
- break;
- case D_EVENT_TRACE :
- validTrace = *reinterpret_cast<bool *>( dataPtr );
- savefile->WriteBool( validTrace );
- size += sizeof( bool );
- if ( validTrace ) {
- size += sizeof( trace_t );
- const trace_t &t = *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) );
- SaveTrace( savefile, t );
- if ( t.c.material ) {
- size += MAX_STRING_LEN;
- str = reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) );
- savefile->Write( str, MAX_STRING_LEN );
- }
- }
- break;
- default:
- break;
- }
- }
- assert( size == (int)event->eventdef->GetArgSize() );
- event = event->eventNode.Next();
- }
- // Save the Fast EventQueue
- savefile->WriteInt( FastEventQueue.Num() );
- event = FastEventQueue.Next();
- while( event != NULL ) {
- savefile->WriteInt( event->time );
- savefile->WriteString( event->eventdef->GetName() );
- savefile->WriteString( event->typeinfo->classname );
- savefile->WriteObject( event->object );
- savefile->WriteInt( event->eventdef->GetArgSize() );
- savefile->Write( event->data, event->eventdef->GetArgSize() );
- event = event->eventNode.Next();
- }
- }
- /*
- ================
- idEvent::Restore
- ================
- */
- void idEvent::Restore( idRestoreGame *savefile ) {
- char *str;
- int num, argsize, i, j, size;
- idStr name;
- byte *dataPtr;
- idEvent *event;
- const char *format;
- savefile->ReadInt( num );
- for ( i = 0; i < num; i++ ) {
- if ( FreeEvents.IsListEmpty() ) {
- gameLocal.Error( "idEvent::Restore : No more free events" );
- }
- event = FreeEvents.Next();
- event->eventNode.Remove();
- event->eventNode.AddToEnd( EventQueue );
- savefile->ReadInt( event->time );
- // read the event name
- savefile->ReadString( name );
- event->eventdef = idEventDef::FindEvent( name );
- if ( event->eventdef == NULL ) {
- savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() );
- return;
- }
- // read the classtype
- savefile->ReadString( name );
- event->typeinfo = idClass::GetClass( name );
- if ( event->typeinfo == NULL ) {
- savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() );
- return;
- }
- savefile->ReadObject( event->object );
- // read the args
- savefile->ReadInt( argsize );
- if ( argsize != (int)event->eventdef->GetArgSize() ) {
- savefile->Error( "idEvent::Restore: arg size (%d) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() );
- }
- if ( argsize ) {
- event->data = eventDataAllocator.Alloc( argsize );
- format = event->eventdef->GetArgFormat();
- assert( format );
- for ( j = 0, size = 0; j < event->eventdef->GetNumArgs(); ++j) {
- dataPtr = &event->data[ event->eventdef->GetArgOffset( j ) ];
- switch( format[ j ] ) {
- case D_EVENT_FLOAT :
- savefile->ReadFloat( *reinterpret_cast<float *>( dataPtr ) );
- size += sizeof( float );
- break;
- case D_EVENT_INTEGER :
- case D_EVENT_ENTITY :
- case D_EVENT_ENTITY_NULL :
- savefile->ReadInt( *reinterpret_cast<int *>( dataPtr ) );
- size += sizeof( int );
- break;
- case D_EVENT_VECTOR :
- savefile->ReadVec3( *reinterpret_cast<idVec3 *>( dataPtr ) );
- size += sizeof( idVec3 );
- break;
- case D_EVENT_TRACE :
- savefile->ReadBool( *reinterpret_cast<bool *>( dataPtr ) );
- size += sizeof( bool );
- if ( *reinterpret_cast<bool *>( dataPtr ) ) {
- size += sizeof( trace_t );
- trace_t &t = *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) );
- RestoreTrace( savefile, t) ;
- if ( t.c.material ) {
- size += MAX_STRING_LEN;
- str = reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) );
- savefile->Read( str, MAX_STRING_LEN );
- }
- }
- break;
- default:
- break;
- }
- }
- assert( size == (int)event->eventdef->GetArgSize() );
- } else {
- event->data = NULL;
- }
- }
- // Restore the Fast EventQueue
- savefile->ReadInt( num );
- for ( i = 0; i < num; i++ ) {
- if ( FreeEvents.IsListEmpty() ) {
- gameLocal.Error( "idEvent::Restore : No more free events" );
- }
- event = FreeEvents.Next();
- event->eventNode.Remove();
- event->eventNode.AddToEnd( FastEventQueue );
- savefile->ReadInt( event->time );
- // read the event name
- savefile->ReadString( name );
- event->eventdef = idEventDef::FindEvent( name );
- if ( event->eventdef == NULL ) {
- savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() );
- return;
- }
- // read the classtype
- savefile->ReadString( name );
- event->typeinfo = idClass::GetClass( name );
- if ( event->typeinfo == NULL ) {
- savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() );
- return;
- }
- savefile->ReadObject( event->object );
- // read the args
- savefile->ReadInt( argsize );
- if ( argsize != (int)event->eventdef->GetArgSize() ) {
- savefile->Error( "idEvent::Restore: arg size (%d) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() );
- }
- if ( argsize ) {
- event->data = eventDataAllocator.Alloc( argsize );
- savefile->Read( event->data, argsize );
- } else {
- event->data = NULL;
- }
- }
- }
- /*
- ================
- idEvent::ReadTrace
-
- idRestoreGame has a ReadTrace procedure, but unfortunately idEvent wants the material
- string name at the of the data structure rather than in the middle
- ================
- */
- void idEvent::RestoreTrace( idRestoreGame *savefile, trace_t &trace ) {
- savefile->ReadFloat( trace.fraction );
- savefile->ReadVec3( trace.endpos );
- savefile->ReadMat3( trace.endAxis );
- savefile->ReadInt( (int&)trace.c.type );
- savefile->ReadVec3( trace.c.point );
- savefile->ReadVec3( trace.c.normal );
- savefile->ReadFloat( trace.c.dist );
- savefile->ReadInt( trace.c.contents );
- savefile->ReadInt( (int&)trace.c.material );
- savefile->ReadInt( trace.c.contents );
- savefile->ReadInt( trace.c.modelFeature );
- savefile->ReadInt( trace.c.trmFeature );
- savefile->ReadInt( trace.c.id );
- }
- /*
- ================
- idEvent::WriteTrace
- idSaveGame has a WriteTrace procedure, but unfortunately idEvent wants the material
- string name at the of the data structure rather than in the middle
- ================
- */
- void idEvent::SaveTrace( idSaveGame *savefile, const trace_t &trace ) {
- savefile->WriteFloat( trace.fraction );
- savefile->WriteVec3( trace.endpos );
- savefile->WriteMat3( trace.endAxis );
- savefile->WriteInt( trace.c.type );
- savefile->WriteVec3( trace.c.point );
- savefile->WriteVec3( trace.c.normal );
- savefile->WriteFloat( trace.c.dist );
- savefile->WriteInt( trace.c.contents );
- savefile->WriteInt( (int&)trace.c.material );
- savefile->WriteInt( trace.c.contents );
- savefile->WriteInt( trace.c.modelFeature );
- savefile->WriteInt( trace.c.trmFeature );
- savefile->WriteInt( trace.c.id );
- }
- #ifdef CREATE_EVENT_CODE
- /*
- ================
- CreateEventCallbackHandler
- ================
- */
- void CreateEventCallbackHandler() {
- int i, j, k;
- char argString[ D_EVENT_MAXARGS + 1 ];
- idStr string1;
- idStr string2;
- idFile *file;
- file = fileSystem->OpenFileWrite( "Callbacks.cpp" );
- file->Printf( "/*\n================================================================================================\nCONFIDENTIAL AND PROPRIETARY INFORMATION/NOT FOR DISCLOSURE WITHOUT WRITTEN PERMISSION \nCopyright 1999-2012 id Software LLC, a ZeniMax Media company. All Rights Reserved. \n================================================================================================\n*/\n\n" );
- for( i = 1; i <= D_EVENT_MAXARGS; i++ ) {
- file->Printf( "\t/*******************************************************\n\n\t\t%d args\n\n\t*******************************************************/\n\n", i );
- for ( j = 0; j < ( 1 << i ); j++ ) {
- for( k = 0; k < i; k++ ) {
- argString[ k ] = j & ( 1 << k ) ? 'f' : 'i';
- }
- argString[ i ] = '\0';
- string1.Empty();
- string2.Empty();
- for( k = 0; k < i; k++ ) {
- if ( j & ( 1 << k ) ) {
- string1 += "const float";
- string2 += va( "*( float * )&data[ %d ]", k );
- } else {
- string1 += "void *";
- string2 += va( "(void *)data[ %d ]", k );
- }
- if ( k < i - 1 ) {
- string1 += ", ";
- string2 += ", ";
- }
- }
- file->Printf( "\tcase %d :\n\t\ttypedef void ( idClass::*eventCallback_%s_t )( %s );\n", ( 1 << ( i + D_EVENT_MAXARGS ) ) + j, argString, string1.c_str() );
- file->Printf( "\t\t( this->*( eventCallback_%s_t )callback )( %s );\n\t\tbreak;\n\n", argString, string2.c_str() );
- }
- }
- fileSystem->CloseFile( file );
- }
- #endif
|