Event.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. /*
  21. sys_event.cpp
  22. Event are used for scheduling tasks and for linking script commands.
  23. */
  24. #pragma hdrstop
  25. #include "../../idlib/precompiled.h"
  26. #include "../Game_local.h"
  27. #define MAX_EVENTSPERFRAME 4096
  28. //#define CREATE_EVENT_CODE
  29. /***********************************************************************
  30. idEventDef
  31. ***********************************************************************/
  32. idEventDef *idEventDef::eventDefList[MAX_EVENTS];
  33. int idEventDef::numEventDefs = 0;
  34. static bool eventError = false;
  35. static char eventErrorMsg[ 128 ];
  36. /*
  37. ================
  38. idEventDef::idEventDef
  39. ================
  40. */
  41. idEventDef::idEventDef( const char *command, const char *formatspec, char returnType ) {
  42. idEventDef *ev;
  43. int i;
  44. unsigned int bits;
  45. assert( command );
  46. assert( !idEvent::initialized );
  47. // Allow NULL to indicate no args, but always store it as ""
  48. // so we don't have to check for it.
  49. if ( !formatspec ) {
  50. formatspec = "";
  51. }
  52. this->name = command;
  53. this->formatspec = formatspec;
  54. this->returnType = returnType;
  55. numargs = strlen( formatspec );
  56. assert( numargs <= D_EVENT_MAXARGS );
  57. if ( numargs > D_EVENT_MAXARGS ) {
  58. eventError = true;
  59. sprintf( eventErrorMsg, "idEventDef::idEventDef : Too many args for '%s' event.", name );
  60. return;
  61. }
  62. // make sure the format for the args is valid, calculate the formatspecindex, and the offsets for each arg
  63. bits = 0;
  64. argsize = 0;
  65. memset( argOffset, 0, sizeof( argOffset ) );
  66. for( i = 0; i < numargs;i++ ) {
  67. argOffset[ i ] = argsize;
  68. switch( formatspec[ i ] ) {
  69. case D_EVENT_FLOAT :
  70. bits |= 1 << i;
  71. argsize += sizeof( float );
  72. break;
  73. case D_EVENT_INTEGER :
  74. argsize += sizeof( int );
  75. break;
  76. case D_EVENT_VECTOR :
  77. argsize += sizeof( idVec3 );
  78. break;
  79. case D_EVENT_STRING :
  80. argsize += MAX_STRING_LEN;
  81. break;
  82. case D_EVENT_ENTITY :
  83. argsize += sizeof( idEntityPtr<idEntity> );
  84. break;
  85. case D_EVENT_ENTITY_NULL :
  86. argsize += sizeof( idEntityPtr<idEntity> );
  87. break;
  88. case D_EVENT_TRACE :
  89. argsize += sizeof( trace_t ) + MAX_STRING_LEN + sizeof( bool );
  90. break;
  91. default :
  92. eventError = true;
  93. sprintf( eventErrorMsg, "idEventDef::idEventDef : Invalid arg format '%s' string for '%s' event.", formatspec, name );
  94. return;
  95. break;
  96. }
  97. }
  98. // calculate the formatspecindex
  99. formatspecIndex = ( 1 << ( numargs + D_EVENT_MAXARGS ) ) | bits;
  100. // go through the list of defined events and check for duplicates
  101. // and mismatched format strings
  102. eventnum = numEventDefs;
  103. for( i = 0; i < eventnum; i++ ) {
  104. ev = eventDefList[ i ];
  105. if ( strcmp( command, ev->name ) == 0 ) {
  106. if ( strcmp( formatspec, ev->formatspec ) != 0 ) {
  107. eventError = true;
  108. sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing format strings ('%s'!='%s').",
  109. command, formatspec, ev->formatspec );
  110. return;
  111. }
  112. if ( ev->returnType != returnType ) {
  113. eventError = true;
  114. sprintf( eventErrorMsg, "idEvent '%s' defined twice with same name but differing return types ('%c'!='%c').",
  115. command, returnType, ev->returnType );
  116. return;
  117. }
  118. // Don't bother putting the duplicate event in list.
  119. eventnum = ev->eventnum;
  120. return;
  121. }
  122. }
  123. ev = this;
  124. if ( numEventDefs >= MAX_EVENTS ) {
  125. eventError = true;
  126. sprintf( eventErrorMsg, "numEventDefs >= MAX_EVENTS" );
  127. return;
  128. }
  129. eventDefList[numEventDefs] = ev;
  130. numEventDefs++;
  131. }
  132. /*
  133. ================
  134. idEventDef::NumEventCommands
  135. ================
  136. */
  137. int idEventDef::NumEventCommands() {
  138. return numEventDefs;
  139. }
  140. /*
  141. ================
  142. idEventDef::GetEventCommand
  143. ================
  144. */
  145. const idEventDef *idEventDef::GetEventCommand( int eventnum ) {
  146. return eventDefList[ eventnum ];
  147. }
  148. /*
  149. ================
  150. idEventDef::FindEvent
  151. ================
  152. */
  153. const idEventDef *idEventDef::FindEvent( const char *name ) {
  154. idEventDef *ev;
  155. int num;
  156. int i;
  157. assert( name );
  158. num = numEventDefs;
  159. for( i = 0; i < num; i++ ) {
  160. ev = eventDefList[ i ];
  161. if ( strcmp( name, ev->name ) == 0 ) {
  162. return ev;
  163. }
  164. }
  165. return NULL;
  166. }
  167. /***********************************************************************
  168. idEvent
  169. ***********************************************************************/
  170. static idLinkList<idEvent> FreeEvents;
  171. static idLinkList<idEvent> EventQueue;
  172. static idLinkList<idEvent> FastEventQueue;
  173. static idEvent EventPool[ MAX_EVENTS ];
  174. bool idEvent::initialized = false;
  175. idDynamicBlockAlloc<byte, 16 * 1024, 256> idEvent::eventDataAllocator;
  176. /*
  177. ================
  178. idEvent::~idEvent()
  179. ================
  180. */
  181. idEvent::~idEvent() {
  182. Free();
  183. }
  184. /*
  185. ================
  186. idEvent::Alloc
  187. ================
  188. */
  189. idEvent *idEvent::Alloc( const idEventDef *evdef, int numargs, va_list args ) {
  190. idEvent *ev;
  191. size_t size;
  192. const char *format;
  193. idEventArg *arg;
  194. byte *dataPtr;
  195. int i;
  196. const char *materialName;
  197. if ( FreeEvents.IsListEmpty() ) {
  198. gameLocal.Error( "idEvent::Alloc : No more free events" );
  199. }
  200. ev = FreeEvents.Next();
  201. ev->eventNode.Remove();
  202. ev->eventdef = evdef;
  203. if ( numargs != evdef->GetNumArgs() ) {
  204. gameLocal.Error( "idEvent::Alloc : Wrong number of args for '%s' event.", evdef->GetName() );
  205. }
  206. size = evdef->GetArgSize();
  207. if ( size ) {
  208. ev->data = eventDataAllocator.Alloc( size );
  209. memset( ev->data, 0, size );
  210. } else {
  211. ev->data = NULL;
  212. return ev;
  213. }
  214. format = evdef->GetArgFormat();
  215. for( i = 0; i < numargs; i++ ) {
  216. arg = va_arg( args, idEventArg * );
  217. if ( format[ i ] != arg->type ) {
  218. // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens
  219. if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) {
  220. gameLocal.Error( "idEvent::Alloc : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() );
  221. }
  222. }
  223. dataPtr = &ev->data[ evdef->GetArgOffset( i ) ];
  224. switch( format[ i ] ) {
  225. case D_EVENT_FLOAT :
  226. case D_EVENT_INTEGER :
  227. *reinterpret_cast<int *>( dataPtr ) = arg->value;
  228. break;
  229. case D_EVENT_VECTOR :
  230. if ( arg->value ) {
  231. *reinterpret_cast<idVec3 *>( dataPtr ) = *reinterpret_cast<const idVec3 *>( arg->value );
  232. }
  233. break;
  234. case D_EVENT_STRING :
  235. if ( arg->value ) {
  236. idStr::Copynz( reinterpret_cast<char *>( dataPtr ), reinterpret_cast<const char *>( arg->value ), MAX_STRING_LEN );
  237. }
  238. break;
  239. case D_EVENT_ENTITY :
  240. case D_EVENT_ENTITY_NULL :
  241. *reinterpret_cast< idEntityPtr<idEntity> * >( dataPtr ) = reinterpret_cast<idEntity *>( arg->value );
  242. break;
  243. case D_EVENT_TRACE :
  244. if ( arg->value ) {
  245. *reinterpret_cast<bool *>( dataPtr ) = true;
  246. *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) ) = *reinterpret_cast<const trace_t *>( arg->value );
  247. // save off the material as a string since the pointer won't be valid in save games.
  248. // since we save off the entire trace_t structure, if the material is NULL here,
  249. // it will be NULL when we process it, so we don't need to save off anything in that case.
  250. if ( reinterpret_cast<const trace_t *>( arg->value )->c.material ) {
  251. materialName = reinterpret_cast<const trace_t *>( arg->value )->c.material->GetName();
  252. idStr::Copynz( reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) ), materialName, MAX_STRING_LEN );
  253. }
  254. } else {
  255. *reinterpret_cast<bool *>( dataPtr ) = false;
  256. }
  257. break;
  258. default :
  259. gameLocal.Error( "idEvent::Alloc : Invalid arg format '%s' string for '%s' event.", format, evdef->GetName() );
  260. break;
  261. }
  262. }
  263. return ev;
  264. }
  265. /*
  266. ================
  267. idEvent::CopyArgs
  268. ================
  269. */
  270. void idEvent::CopyArgs( const idEventDef *evdef, int numargs, va_list args, int data[ D_EVENT_MAXARGS ] ) {
  271. int i;
  272. const char *format;
  273. idEventArg *arg;
  274. format = evdef->GetArgFormat();
  275. if ( numargs != evdef->GetNumArgs() ) {
  276. gameLocal.Error( "idEvent::CopyArgs : Wrong number of args for '%s' event.", evdef->GetName() );
  277. }
  278. for( i = 0; i < numargs; i++ ) {
  279. arg = va_arg( args, idEventArg * );
  280. if ( format[ i ] != arg->type ) {
  281. // when NULL is passed in for an entity, it gets cast as an integer 0, so don't give an error when it happens
  282. if ( !( ( ( format[ i ] == D_EVENT_TRACE ) || ( format[ i ] == D_EVENT_ENTITY ) ) && ( arg->type == 'd' ) && ( arg->value == 0 ) ) ) {
  283. gameLocal.Error( "idEvent::CopyArgs : Wrong type passed in for arg # %d on '%s' event.", i, evdef->GetName() );
  284. }
  285. }
  286. data[ i ] = arg->value;
  287. }
  288. }
  289. /*
  290. ================
  291. idEvent::Free
  292. ================
  293. */
  294. void idEvent::Free() {
  295. if ( data ) {
  296. eventDataAllocator.Free( data );
  297. data = NULL;
  298. }
  299. eventdef = NULL;
  300. time = 0;
  301. object = NULL;
  302. typeinfo = NULL;
  303. eventNode.SetOwner( this );
  304. eventNode.AddToEnd( FreeEvents );
  305. }
  306. /*
  307. ================
  308. idEvent::Schedule
  309. ================
  310. */
  311. void idEvent::Schedule( idClass *obj, const idTypeInfo *type, int time ) {
  312. idEvent *event;
  313. assert( initialized );
  314. if ( !initialized ) {
  315. return;
  316. }
  317. object = obj;
  318. typeinfo = type;
  319. // wraps after 24 days...like I care. ;)
  320. this->time = gameLocal.time + time;
  321. eventNode.Remove();
  322. if ( obj->IsType( idEntity::Type ) && ( ( (idEntity*)(obj) )->timeGroup == TIME_GROUP2 ) ) {
  323. event = FastEventQueue.Next();
  324. while( ( event != NULL ) && ( this->time >= event->time ) ) {
  325. event = event->eventNode.Next();
  326. }
  327. if ( event ) {
  328. eventNode.InsertBefore( event->eventNode );
  329. } else {
  330. eventNode.AddToEnd( FastEventQueue );
  331. }
  332. return;
  333. } else {
  334. this->time = gameLocal.slow.time + time;
  335. }
  336. event = EventQueue.Next();
  337. while( ( event != NULL ) && ( this->time >= event->time ) ) {
  338. event = event->eventNode.Next();
  339. }
  340. if ( event ) {
  341. eventNode.InsertBefore( event->eventNode );
  342. } else {
  343. eventNode.AddToEnd( EventQueue );
  344. }
  345. }
  346. /*
  347. ================
  348. idEvent::CancelEvents
  349. ================
  350. */
  351. void idEvent::CancelEvents( const idClass *obj, const idEventDef *evdef ) {
  352. idEvent *event;
  353. idEvent *next;
  354. if ( !initialized ) {
  355. return;
  356. }
  357. for( event = EventQueue.Next(); event != NULL; event = next ) {
  358. next = event->eventNode.Next();
  359. if ( event->object == obj ) {
  360. if ( !evdef || ( evdef == event->eventdef ) ) {
  361. event->Free();
  362. }
  363. }
  364. }
  365. for( event = FastEventQueue.Next(); event != NULL; event = next ) {
  366. next = event->eventNode.Next();
  367. if ( event->object == obj ) {
  368. if ( !evdef || ( evdef == event->eventdef ) ) {
  369. event->Free();
  370. }
  371. }
  372. }
  373. }
  374. /*
  375. ================
  376. idEvent::ClearEventList
  377. ================
  378. */
  379. void idEvent::ClearEventList() {
  380. int i;
  381. //
  382. // initialize lists
  383. //
  384. FreeEvents.Clear();
  385. EventQueue.Clear();
  386. //
  387. // add the events to the free list
  388. //
  389. for( i = 0; i < MAX_EVENTS; i++ ) {
  390. EventPool[ i ].Free();
  391. }
  392. }
  393. /*
  394. ================
  395. idEvent::ServiceEvents
  396. ================
  397. */
  398. void idEvent::ServiceEvents() {
  399. idEvent *event;
  400. int num;
  401. int args[ D_EVENT_MAXARGS ];
  402. int offset;
  403. int i;
  404. int numargs;
  405. const char *formatspec;
  406. trace_t **tracePtr;
  407. const idEventDef *ev;
  408. byte *data;
  409. const char *materialName;
  410. num = 0;
  411. while( !EventQueue.IsListEmpty() ) {
  412. event = EventQueue.Next();
  413. assert( event );
  414. if ( event->time > gameLocal.time ) {
  415. break;
  416. }
  417. common->UpdateLevelLoadPacifier();
  418. // copy the data into the local args array and set up pointers
  419. ev = event->eventdef;
  420. formatspec = ev->GetArgFormat();
  421. numargs = ev->GetNumArgs();
  422. for( i = 0; i < numargs; i++ ) {
  423. offset = ev->GetArgOffset( i );
  424. data = event->data;
  425. switch( formatspec[ i ] ) {
  426. case D_EVENT_FLOAT :
  427. case D_EVENT_INTEGER :
  428. args[ i ] = *reinterpret_cast<int *>( &data[ offset ] );
  429. break;
  430. case D_EVENT_VECTOR :
  431. *reinterpret_cast<idVec3 **>( &args[ i ] ) = reinterpret_cast<idVec3 *>( &data[ offset ] );
  432. break;
  433. case D_EVENT_STRING :
  434. *reinterpret_cast<const char **>( &args[ i ] ) = reinterpret_cast<const char *>( &data[ offset ] );
  435. break;
  436. case D_EVENT_ENTITY :
  437. case D_EVENT_ENTITY_NULL :
  438. *reinterpret_cast<idEntity **>( &args[ i ] ) = reinterpret_cast< idEntityPtr<idEntity> * >( &data[ offset ] )->GetEntity();
  439. break;
  440. case D_EVENT_TRACE :
  441. tracePtr = reinterpret_cast<trace_t **>( &args[ i ] );
  442. if ( *reinterpret_cast<bool *>( &data[ offset ] ) ) {
  443. *tracePtr = reinterpret_cast<trace_t *>( &data[ offset + sizeof( bool ) ] );
  444. if ( ( *tracePtr )->c.material != NULL ) {
  445. // look up the material name to get the material pointer
  446. materialName = reinterpret_cast<const char *>( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] );
  447. ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true );
  448. }
  449. } else {
  450. *tracePtr = NULL;
  451. }
  452. break;
  453. default:
  454. gameLocal.Error( "idEvent::ServiceEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() );
  455. }
  456. }
  457. // the event is removed from its list so that if then object
  458. // is deleted, the event won't be freed twice
  459. event->eventNode.Remove();
  460. assert( event->object );
  461. event->object->ProcessEventArgPtr( ev, args );
  462. #if 0
  463. // event functions may never leave return values on the FPU stack
  464. // enable this code to check if any event call left values on the FPU stack
  465. if ( !sys->FPU_StackIsEmpty() ) {
  466. gameLocal.Error( "idEvent::ServiceEvents %d: %s left a value on the FPU stack\n", num, ev->GetName() );
  467. }
  468. #endif
  469. // return the event to the free list
  470. event->Free();
  471. // Don't allow ourselves to stay in here too long. An abnormally high number
  472. // of events being processed is evidence of an infinite loop of events.
  473. num++;
  474. if ( num > MAX_EVENTSPERFRAME ) {
  475. gameLocal.Error( "Event overflow. Possible infinite loop in script." );
  476. }
  477. }
  478. }
  479. /*
  480. ================
  481. idEvent::ServiceFastEvents
  482. ================
  483. */
  484. void idEvent::ServiceFastEvents() {
  485. idEvent *event;
  486. int num;
  487. int args[ D_EVENT_MAXARGS ];
  488. int offset;
  489. int i;
  490. int numargs;
  491. const char *formatspec;
  492. trace_t **tracePtr;
  493. const idEventDef *ev;
  494. byte *data;
  495. const char *materialName;
  496. num = 0;
  497. while( !FastEventQueue.IsListEmpty() ) {
  498. event = FastEventQueue.Next();
  499. assert( event );
  500. if ( event->time > gameLocal.fast.time ) {
  501. break;
  502. }
  503. // copy the data into the local args array and set up pointers
  504. ev = event->eventdef;
  505. formatspec = ev->GetArgFormat();
  506. numargs = ev->GetNumArgs();
  507. for( i = 0; i < numargs; i++ ) {
  508. offset = ev->GetArgOffset( i );
  509. data = event->data;
  510. switch( formatspec[ i ] ) {
  511. case D_EVENT_FLOAT :
  512. case D_EVENT_INTEGER :
  513. args[ i ] = *reinterpret_cast<int *>( &data[ offset ] );
  514. break;
  515. case D_EVENT_VECTOR :
  516. *reinterpret_cast<idVec3 **>( &args[ i ] ) = reinterpret_cast<idVec3 *>( &data[ offset ] );
  517. break;
  518. case D_EVENT_STRING :
  519. *reinterpret_cast<const char **>( &args[ i ] ) = reinterpret_cast<const char *>( &data[ offset ] );
  520. break;
  521. case D_EVENT_ENTITY :
  522. case D_EVENT_ENTITY_NULL :
  523. *reinterpret_cast<idEntity **>( &args[ i ] ) = reinterpret_cast< idEntityPtr<idEntity> * >( &data[ offset ] )->GetEntity();
  524. break;
  525. case D_EVENT_TRACE :
  526. tracePtr = reinterpret_cast<trace_t **>( &args[ i ] );
  527. if ( *reinterpret_cast<bool *>( &data[ offset ] ) ) {
  528. *tracePtr = reinterpret_cast<trace_t *>( &data[ offset + sizeof( bool ) ] );
  529. if ( ( *tracePtr )->c.material != NULL ) {
  530. // look up the material name to get the material pointer
  531. materialName = reinterpret_cast<const char *>( &data[ offset + sizeof( bool ) + sizeof( trace_t ) ] );
  532. ( *tracePtr )->c.material = declManager->FindMaterial( materialName, true );
  533. }
  534. } else {
  535. *tracePtr = NULL;
  536. }
  537. break;
  538. default:
  539. gameLocal.Error( "idEvent::ServiceFastEvents : Invalid arg format '%s' string for '%s' event.", formatspec, ev->GetName() );
  540. }
  541. }
  542. // the event is removed from its list so that if then object
  543. // is deleted, the event won't be freed twice
  544. event->eventNode.Remove();
  545. assert( event->object );
  546. event->object->ProcessEventArgPtr( ev, args );
  547. #if 0
  548. // event functions may never leave return values on the FPU stack
  549. // enable this code to check if any event call left values on the FPU stack
  550. if ( !sys->FPU_StackIsEmpty() ) {
  551. gameLocal.Error( "idEvent::ServiceEvents %d: %s left a value on the FPU stack\n", num, event->eventdef->GetName() );
  552. }
  553. #endif
  554. // return the event to the free list
  555. event->Free();
  556. // Don't allow ourselves to stay in here too long. An abnormally high number
  557. // of events being processed is evidence of an infinite loop of events.
  558. num++;
  559. if ( num > MAX_EVENTSPERFRAME ) {
  560. gameLocal.Error( "Event overflow. Possible infinite loop in script." );
  561. }
  562. }
  563. }
  564. /*
  565. ================
  566. idEvent::Init
  567. ================
  568. */
  569. void idEvent::Init() {
  570. gameLocal.Printf( "Initializing event system\n" );
  571. if ( eventError ) {
  572. gameLocal.Error( "%s", eventErrorMsg );
  573. }
  574. #ifdef CREATE_EVENT_CODE
  575. void CreateEventCallbackHandler();
  576. CreateEventCallbackHandler();
  577. gameLocal.Error( "Wrote event callback handler" );
  578. #endif
  579. if ( initialized ) {
  580. gameLocal.Printf( "...already initialized\n" );
  581. ClearEventList();
  582. return;
  583. }
  584. ClearEventList();
  585. eventDataAllocator.Init();
  586. gameLocal.Printf( "...%i event definitions\n", idEventDef::NumEventCommands() );
  587. // the event system has started
  588. initialized = true;
  589. }
  590. /*
  591. ================
  592. idEvent::Shutdown
  593. ================
  594. */
  595. void idEvent::Shutdown() {
  596. gameLocal.Printf( "Shutdown event system\n" );
  597. if ( !initialized ) {
  598. gameLocal.Printf( "...not started\n" );
  599. return;
  600. }
  601. ClearEventList();
  602. eventDataAllocator.Shutdown();
  603. // say it is now shutdown
  604. initialized = false;
  605. }
  606. /*
  607. ================
  608. idEvent::Save
  609. ================
  610. */
  611. void idEvent::Save( idSaveGame *savefile ) {
  612. char *str;
  613. int i, size;
  614. idEvent *event;
  615. byte *dataPtr;
  616. bool validTrace;
  617. const char *format;
  618. savefile->WriteInt( EventQueue.Num() );
  619. event = EventQueue.Next();
  620. while( event != NULL ) {
  621. savefile->WriteInt( event->time );
  622. savefile->WriteString( event->eventdef->GetName() );
  623. savefile->WriteString( event->typeinfo->classname );
  624. savefile->WriteObject( event->object );
  625. savefile->WriteInt( event->eventdef->GetArgSize() );
  626. format = event->eventdef->GetArgFormat();
  627. for ( i = 0, size = 0; i < event->eventdef->GetNumArgs(); ++i) {
  628. dataPtr = &event->data[ event->eventdef->GetArgOffset( i ) ];
  629. switch( format[ i ] ) {
  630. case D_EVENT_FLOAT :
  631. savefile->WriteFloat( *reinterpret_cast<float *>( dataPtr ) );
  632. size += sizeof( float );
  633. break;
  634. case D_EVENT_INTEGER :
  635. case D_EVENT_ENTITY :
  636. case D_EVENT_ENTITY_NULL :
  637. savefile->WriteInt( *reinterpret_cast<int *>( dataPtr ) );
  638. size += sizeof( int );
  639. break;
  640. case D_EVENT_VECTOR :
  641. savefile->WriteVec3( *reinterpret_cast<idVec3 *>( dataPtr ) );
  642. size += sizeof( idVec3 );
  643. break;
  644. case D_EVENT_TRACE :
  645. validTrace = *reinterpret_cast<bool *>( dataPtr );
  646. savefile->WriteBool( validTrace );
  647. size += sizeof( bool );
  648. if ( validTrace ) {
  649. size += sizeof( trace_t );
  650. const trace_t &t = *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) );
  651. SaveTrace( savefile, t );
  652. if ( t.c.material ) {
  653. size += MAX_STRING_LEN;
  654. str = reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) );
  655. savefile->Write( str, MAX_STRING_LEN );
  656. }
  657. }
  658. break;
  659. default:
  660. break;
  661. }
  662. }
  663. assert( size == (int)event->eventdef->GetArgSize() );
  664. event = event->eventNode.Next();
  665. }
  666. // Save the Fast EventQueue
  667. savefile->WriteInt( FastEventQueue.Num() );
  668. event = FastEventQueue.Next();
  669. while( event != NULL ) {
  670. savefile->WriteInt( event->time );
  671. savefile->WriteString( event->eventdef->GetName() );
  672. savefile->WriteString( event->typeinfo->classname );
  673. savefile->WriteObject( event->object );
  674. savefile->WriteInt( event->eventdef->GetArgSize() );
  675. savefile->Write( event->data, event->eventdef->GetArgSize() );
  676. event = event->eventNode.Next();
  677. }
  678. }
  679. /*
  680. ================
  681. idEvent::Restore
  682. ================
  683. */
  684. void idEvent::Restore( idRestoreGame *savefile ) {
  685. char *str;
  686. int num, argsize, i, j, size;
  687. idStr name;
  688. byte *dataPtr;
  689. idEvent *event;
  690. const char *format;
  691. savefile->ReadInt( num );
  692. for ( i = 0; i < num; i++ ) {
  693. if ( FreeEvents.IsListEmpty() ) {
  694. gameLocal.Error( "idEvent::Restore : No more free events" );
  695. }
  696. event = FreeEvents.Next();
  697. event->eventNode.Remove();
  698. event->eventNode.AddToEnd( EventQueue );
  699. savefile->ReadInt( event->time );
  700. // read the event name
  701. savefile->ReadString( name );
  702. event->eventdef = idEventDef::FindEvent( name );
  703. if ( event->eventdef == NULL ) {
  704. savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() );
  705. return;
  706. }
  707. // read the classtype
  708. savefile->ReadString( name );
  709. event->typeinfo = idClass::GetClass( name );
  710. if ( event->typeinfo == NULL ) {
  711. savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() );
  712. return;
  713. }
  714. savefile->ReadObject( event->object );
  715. // read the args
  716. savefile->ReadInt( argsize );
  717. if ( argsize != (int)event->eventdef->GetArgSize() ) {
  718. savefile->Error( "idEvent::Restore: arg size (%d) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() );
  719. }
  720. if ( argsize ) {
  721. event->data = eventDataAllocator.Alloc( argsize );
  722. format = event->eventdef->GetArgFormat();
  723. assert( format );
  724. for ( j = 0, size = 0; j < event->eventdef->GetNumArgs(); ++j) {
  725. dataPtr = &event->data[ event->eventdef->GetArgOffset( j ) ];
  726. switch( format[ j ] ) {
  727. case D_EVENT_FLOAT :
  728. savefile->ReadFloat( *reinterpret_cast<float *>( dataPtr ) );
  729. size += sizeof( float );
  730. break;
  731. case D_EVENT_INTEGER :
  732. case D_EVENT_ENTITY :
  733. case D_EVENT_ENTITY_NULL :
  734. savefile->ReadInt( *reinterpret_cast<int *>( dataPtr ) );
  735. size += sizeof( int );
  736. break;
  737. case D_EVENT_VECTOR :
  738. savefile->ReadVec3( *reinterpret_cast<idVec3 *>( dataPtr ) );
  739. size += sizeof( idVec3 );
  740. break;
  741. case D_EVENT_TRACE :
  742. savefile->ReadBool( *reinterpret_cast<bool *>( dataPtr ) );
  743. size += sizeof( bool );
  744. if ( *reinterpret_cast<bool *>( dataPtr ) ) {
  745. size += sizeof( trace_t );
  746. trace_t &t = *reinterpret_cast<trace_t *>( dataPtr + sizeof( bool ) );
  747. RestoreTrace( savefile, t) ;
  748. if ( t.c.material ) {
  749. size += MAX_STRING_LEN;
  750. str = reinterpret_cast<char *>( dataPtr + sizeof( bool ) + sizeof( trace_t ) );
  751. savefile->Read( str, MAX_STRING_LEN );
  752. }
  753. }
  754. break;
  755. default:
  756. break;
  757. }
  758. }
  759. assert( size == (int)event->eventdef->GetArgSize() );
  760. } else {
  761. event->data = NULL;
  762. }
  763. }
  764. // Restore the Fast EventQueue
  765. savefile->ReadInt( num );
  766. for ( i = 0; i < num; i++ ) {
  767. if ( FreeEvents.IsListEmpty() ) {
  768. gameLocal.Error( "idEvent::Restore : No more free events" );
  769. }
  770. event = FreeEvents.Next();
  771. event->eventNode.Remove();
  772. event->eventNode.AddToEnd( FastEventQueue );
  773. savefile->ReadInt( event->time );
  774. // read the event name
  775. savefile->ReadString( name );
  776. event->eventdef = idEventDef::FindEvent( name );
  777. if ( event->eventdef == NULL ) {
  778. savefile->Error( "idEvent::Restore: unknown event '%s'", name.c_str() );
  779. return;
  780. }
  781. // read the classtype
  782. savefile->ReadString( name );
  783. event->typeinfo = idClass::GetClass( name );
  784. if ( event->typeinfo == NULL ) {
  785. savefile->Error( "idEvent::Restore: unknown class '%s' on event '%s'", name.c_str(), event->eventdef->GetName() );
  786. return;
  787. }
  788. savefile->ReadObject( event->object );
  789. // read the args
  790. savefile->ReadInt( argsize );
  791. if ( argsize != (int)event->eventdef->GetArgSize() ) {
  792. savefile->Error( "idEvent::Restore: arg size (%d) doesn't match saved arg size(%d) on event '%s'", event->eventdef->GetArgSize(), argsize, event->eventdef->GetName() );
  793. }
  794. if ( argsize ) {
  795. event->data = eventDataAllocator.Alloc( argsize );
  796. savefile->Read( event->data, argsize );
  797. } else {
  798. event->data = NULL;
  799. }
  800. }
  801. }
  802. /*
  803. ================
  804. idEvent::ReadTrace
  805. idRestoreGame has a ReadTrace procedure, but unfortunately idEvent wants the material
  806. string name at the of the data structure rather than in the middle
  807. ================
  808. */
  809. void idEvent::RestoreTrace( idRestoreGame *savefile, trace_t &trace ) {
  810. savefile->ReadFloat( trace.fraction );
  811. savefile->ReadVec3( trace.endpos );
  812. savefile->ReadMat3( trace.endAxis );
  813. savefile->ReadInt( (int&)trace.c.type );
  814. savefile->ReadVec3( trace.c.point );
  815. savefile->ReadVec3( trace.c.normal );
  816. savefile->ReadFloat( trace.c.dist );
  817. savefile->ReadInt( trace.c.contents );
  818. savefile->ReadInt( (int&)trace.c.material );
  819. savefile->ReadInt( trace.c.contents );
  820. savefile->ReadInt( trace.c.modelFeature );
  821. savefile->ReadInt( trace.c.trmFeature );
  822. savefile->ReadInt( trace.c.id );
  823. }
  824. /*
  825. ================
  826. idEvent::WriteTrace
  827. idSaveGame has a WriteTrace procedure, but unfortunately idEvent wants the material
  828. string name at the of the data structure rather than in the middle
  829. ================
  830. */
  831. void idEvent::SaveTrace( idSaveGame *savefile, const trace_t &trace ) {
  832. savefile->WriteFloat( trace.fraction );
  833. savefile->WriteVec3( trace.endpos );
  834. savefile->WriteMat3( trace.endAxis );
  835. savefile->WriteInt( trace.c.type );
  836. savefile->WriteVec3( trace.c.point );
  837. savefile->WriteVec3( trace.c.normal );
  838. savefile->WriteFloat( trace.c.dist );
  839. savefile->WriteInt( trace.c.contents );
  840. savefile->WriteInt( (int&)trace.c.material );
  841. savefile->WriteInt( trace.c.contents );
  842. savefile->WriteInt( trace.c.modelFeature );
  843. savefile->WriteInt( trace.c.trmFeature );
  844. savefile->WriteInt( trace.c.id );
  845. }
  846. #ifdef CREATE_EVENT_CODE
  847. /*
  848. ================
  849. CreateEventCallbackHandler
  850. ================
  851. */
  852. void CreateEventCallbackHandler() {
  853. int i, j, k;
  854. char argString[ D_EVENT_MAXARGS + 1 ];
  855. idStr string1;
  856. idStr string2;
  857. idFile *file;
  858. file = fileSystem->OpenFileWrite( "Callbacks.cpp" );
  859. 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" );
  860. for( i = 1; i <= D_EVENT_MAXARGS; i++ ) {
  861. file->Printf( "\t/*******************************************************\n\n\t\t%d args\n\n\t*******************************************************/\n\n", i );
  862. for ( j = 0; j < ( 1 << i ); j++ ) {
  863. for( k = 0; k < i; k++ ) {
  864. argString[ k ] = j & ( 1 << k ) ? 'f' : 'i';
  865. }
  866. argString[ i ] = '\0';
  867. string1.Empty();
  868. string2.Empty();
  869. for( k = 0; k < i; k++ ) {
  870. if ( j & ( 1 << k ) ) {
  871. string1 += "const float";
  872. string2 += va( "*( float * )&data[ %d ]", k );
  873. } else {
  874. string1 += "void *";
  875. string2 += va( "(void *)data[ %d ]", k );
  876. }
  877. if ( k < i - 1 ) {
  878. string1 += ", ";
  879. string2 += ", ";
  880. }
  881. }
  882. file->Printf( "\tcase %d :\n\t\ttypedef void ( idClass::*eventCallback_%s_t )( %s );\n", ( 1 << ( i + D_EVENT_MAXARGS ) ) + j, argString, string1.c_str() );
  883. file->Printf( "\t\t( this->*( eventCallback_%s_t )callback )( %s );\n\t\tbreak;\n\n", argString, string2.c_str() );
  884. }
  885. }
  886. fileSystem->CloseFile( file );
  887. }
  888. #endif