IcarusImplementation.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. // IcarusImplementation.cpp
  2. #include "stdafx.h"
  3. #include "IcarusImplementation.h"
  4. #include "BlockStream.h"
  5. #include "Sequence.h"
  6. #include "TaskManager.h"
  7. #include "Sequencer.h"
  8. #define STL_ITERATE( a, b ) for ( a = b.begin(); a != b.end(); a++ )
  9. #define STL_INSERT( a, b ) a.insert( a.end(), b );
  10. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. //
  12. // required implementation of CIcarusInterface
  13. IIcarusInterface* IIcarusInterface::GetIcarus(int flavor,bool constructIfNecessary)
  14. {
  15. if(!CIcarus::s_instances && constructIfNecessary)
  16. {
  17. CIcarus::s_flavorsAvailable = IGameInterface::s_IcarusFlavorsNeeded;
  18. if (!CIcarus::s_flavorsAvailable)
  19. {
  20. return NULL;
  21. }
  22. CIcarus::s_instances = new CIcarus*[CIcarus::s_flavorsAvailable];
  23. for (int index = 0; index < CIcarus::s_flavorsAvailable; index++)
  24. {
  25. CIcarus::s_instances[index] = new CIcarus(index);
  26. //OutputDebugString( "ICARUS flavor successfully created\n" );
  27. }
  28. }
  29. if(flavor >= CIcarus::s_flavorsAvailable || !CIcarus::s_instances )
  30. {
  31. return NULL;
  32. }
  33. return CIcarus::s_instances[flavor];
  34. }
  35. void IIcarusInterface::DestroyIcarus()
  36. {
  37. for(int index = 0; index < CIcarus::s_flavorsAvailable; index++)
  38. {
  39. delete CIcarus::s_instances[index];
  40. }
  41. delete[] CIcarus::s_instances;
  42. CIcarus::s_instances = NULL;
  43. CIcarus::s_flavorsAvailable = 0;
  44. }
  45. IIcarusInterface::~IIcarusInterface()
  46. {
  47. }
  48. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  49. //
  50. // CIcarus
  51. double CIcarus::ICARUS_VERSION = 1.40;
  52. int CIcarus::s_flavorsAvailable = 0;
  53. CIcarus** CIcarus::s_instances = NULL;
  54. CIcarus::CIcarus(int flavor) :
  55. m_flavor(flavor), m_nextSequencerID(0)
  56. {
  57. m_GUID = 0;
  58. #ifdef _DEBUG
  59. m_DEBUG_NumSequencerAlloc = 0;
  60. m_DEBUG_NumSequencerFreed = 0;
  61. m_DEBUG_NumSequencerResidual = 0;
  62. m_DEBUG_NumSequenceAlloc = 0;
  63. m_DEBUG_NumSequenceFreed = 0;
  64. m_DEBUG_NumSequenceResidual = 0;
  65. #endif
  66. m_ulBufferCurPos = 0;
  67. m_ulBytesRead = 0;
  68. m_byBuffer = NULL;
  69. }
  70. CIcarus::~CIcarus()
  71. {
  72. Delete();
  73. }
  74. #if defined (_DEBUG) && defined (_WIN32)
  75. #include "../qcommon/platform.h" // for OutputDebugString
  76. #endif
  77. void CIcarus::Delete( void )
  78. {
  79. Free();
  80. #ifdef _DEBUG
  81. char buffer[1024];
  82. OutputDebugString( "\nICARUS Instance Debug Info:\n---------------------------\n" );
  83. sprintf( (char *) buffer, "Sequencers Allocated:\t%d\n", m_DEBUG_NumSequencerAlloc );
  84. OutputDebugString( (const char *) &buffer );
  85. sprintf( (char *) buffer, "Sequencers Freed:\t\t%d\n", m_DEBUG_NumSequencerFreed );
  86. OutputDebugString( (const char *) &buffer );
  87. sprintf( (char *) buffer, "Sequencers Residual:\t%d\n\n", m_DEBUG_NumSequencerResidual );
  88. OutputDebugString( (const char *) &buffer );
  89. sprintf( (char *) buffer, "Sequences Allocated:\t%d\n", m_DEBUG_NumSequenceAlloc );
  90. OutputDebugString( (const char *) &buffer );
  91. sprintf( (char *) buffer, "Sequences Freed:\t\t%d\n", m_DEBUG_NumSequenceFreed );
  92. OutputDebugString( (const char *) &buffer );
  93. sprintf( (char *) buffer, "Sequences Residual:\t\t%d\n\n", m_DEBUG_NumSequenceResidual );
  94. OutputDebugString( (const char *) &buffer );
  95. OutputDebugString( "\n" );
  96. #endif
  97. }
  98. void CIcarus::Signal( const char *identifier )
  99. {
  100. m_signals[ identifier ] = 1;
  101. }
  102. bool CIcarus::CheckSignal( const char *identifier )
  103. {
  104. signal_m::iterator smi;
  105. smi = m_signals.find( identifier );
  106. if ( smi == m_signals.end() )
  107. return false;
  108. return true;
  109. }
  110. void CIcarus::ClearSignal( const char *identifier )
  111. {
  112. m_signals.erase( identifier );
  113. }
  114. void CIcarus::Free( void )
  115. {
  116. sequencer_l::iterator sri;
  117. //Delete any residual sequencers
  118. STL_ITERATE( sri, m_sequencers )
  119. {
  120. (*sri)->Free(this);
  121. #ifdef _DEBUG
  122. m_DEBUG_NumSequencerResidual++;
  123. #endif
  124. }
  125. m_sequencers.clear();
  126. m_signals.clear();
  127. sequence_l::iterator si;
  128. //Delete any residual sequences
  129. STL_ITERATE( si, m_sequences )
  130. {
  131. (*si)->Delete(this);
  132. delete (*si);
  133. #ifdef _DEBUG
  134. m_DEBUG_NumSequenceResidual++;
  135. #endif
  136. }
  137. m_sequences.clear();
  138. m_sequencerMap.clear();
  139. }
  140. int CIcarus::GetIcarusID( int gameID )
  141. {
  142. CSequencer *sequencer = CSequencer::Create();
  143. CTaskManager *taskManager = CTaskManager::Create();
  144. sequencer->Init( gameID, taskManager );
  145. taskManager->Init( sequencer );
  146. STL_INSERT( m_sequencers, sequencer );
  147. m_sequencerMap[sequencer->GetID()] = sequencer;
  148. #ifdef _DEBUG
  149. m_DEBUG_NumSequencerAlloc++;
  150. #endif
  151. return sequencer->GetID();
  152. }
  153. void CIcarus::DeleteIcarusID( int& icarusID )
  154. {
  155. CSequencer* sequencer = FindSequencer(icarusID);
  156. if(!sequencer)
  157. {
  158. icarusID = -1;
  159. return;
  160. }
  161. CTaskManager *taskManager = sequencer->GetTaskManager();
  162. if (taskManager->IsResident())
  163. {
  164. IGameInterface::GetGame()->DebugPrint( IGameInterface::WL_ERROR, "Refusing DeleteIcarusID(%d) because it is running!\n", icarusID);
  165. assert(0);
  166. return;
  167. }
  168. m_sequencerMap.erase(icarusID);
  169. // added 2/12/2 to properly delete blocks that were passed to the task manager
  170. sequencer->Recall(this);
  171. if ( taskManager )
  172. {
  173. taskManager->Free();
  174. delete taskManager;
  175. }
  176. m_sequencers.remove( sequencer );
  177. sequencer->Free(this);
  178. #ifdef _DEBUG
  179. m_DEBUG_NumSequencerFreed++;
  180. #endif
  181. icarusID = -1;
  182. }
  183. CSequence *CIcarus::GetSequence( void )
  184. {
  185. CSequence *sequence = CSequence::Create();
  186. //Assign the GUID
  187. sequence->SetID( m_GUID++ );
  188. STL_INSERT( m_sequences, sequence );
  189. #ifdef _DEBUG
  190. m_DEBUG_NumSequenceAlloc++;
  191. #endif
  192. return sequence;
  193. }
  194. CSequence *CIcarus::GetSequence( int id )
  195. {
  196. sequence_l::iterator si;
  197. STL_ITERATE( si, m_sequences )
  198. {
  199. if ( (*si)->GetID() == id )
  200. return (*si);
  201. }
  202. return NULL;
  203. }
  204. void CIcarus::DeleteSequence( CSequence *sequence )
  205. {
  206. m_sequences.remove( sequence );
  207. sequence->Delete(this);
  208. delete sequence;
  209. #ifdef _DEBUG
  210. m_DEBUG_NumSequenceFreed++;
  211. #endif
  212. }
  213. int CIcarus::AllocateSequences( int numSequences, int *idTable )
  214. {
  215. CSequence *sequence;
  216. for ( int i = 0; i < numSequences; i++ )
  217. {
  218. //If the GUID of this sequence is higher than the current, take this a the "current" GUID
  219. if ( idTable[i] > m_GUID )
  220. m_GUID = idTable[i];
  221. //Allocate the container sequence
  222. if ( ( sequence = GetSequence() ) == NULL )
  223. return false;
  224. //Override the given GUID with the real one
  225. sequence->SetID( idTable[i] );
  226. }
  227. return true;
  228. }
  229. void CIcarus::Precache(char* buffer, long length)
  230. {
  231. IGameInterface* game = IGameInterface::GetGame(m_flavor);
  232. CBlockStream stream;
  233. CBlockMember *blockMember;
  234. CBlock block;
  235. if ( stream.Open( buffer, length ) == 0 )
  236. return;
  237. const char *sVal1, *sVal2;
  238. //Now iterate through all blocks of the script, searching for keywords
  239. while ( stream.BlockAvailable() )
  240. {
  241. //Get a block
  242. if ( stream.ReadBlock( &block, this ) == 0 )
  243. return;
  244. //Determine what type of block this is
  245. switch( block.GetBlockID() )
  246. {
  247. case ID_CAMERA: // to cache ROFF files
  248. {
  249. float f = *(float *) block.GetMemberData( 0 );
  250. if (f == TYPE_PATH)
  251. {
  252. sVal1 = (const char *) block.GetMemberData( 1 );
  253. game->PrecacheRoff(sVal1);
  254. }
  255. }
  256. break;
  257. case ID_PLAY: // to cache ROFF files
  258. sVal1 = (const char *) block.GetMemberData( 0 );
  259. if (!stricmp(sVal1,"PLAY_ROFF"))
  260. {
  261. sVal1 = (const char *) block.GetMemberData( 1 );
  262. game->PrecacheRoff(sVal1);
  263. }
  264. break;
  265. //Run commands
  266. case ID_RUN:
  267. sVal1 = (const char *) block.GetMemberData( 0 );
  268. game->PrecacheScript( sVal1 );
  269. break;
  270. case ID_SOUND:
  271. sVal1 = (const char *) block.GetMemberData( 1 ); //0 is channel, 1 is filename
  272. game->PrecacheSound(sVal1);
  273. break;
  274. case ID_SET:
  275. blockMember = block.GetMember( 0 );
  276. //NOTENOTE: This will not catch special case get() inlines! (There's not really a good way to do that)
  277. //Make sure we're testing against strings
  278. if ( blockMember->GetID() == TK_STRING )
  279. {
  280. sVal1 = (const char *) block.GetMemberData( 0 );
  281. sVal2 = (const char *) block.GetMemberData( 1 );
  282. game->PrecacheFromSet( sVal1 , sVal2);
  283. }
  284. break;
  285. default:
  286. break;
  287. }
  288. //Clean out the block for the next pass
  289. block.Free(this);
  290. }
  291. //All done
  292. stream.Free();
  293. }
  294. CSequencer* CIcarus::FindSequencer(int sequencerID)
  295. {
  296. sequencer_m::iterator mi = m_sequencerMap.find( sequencerID );
  297. if ( mi == m_sequencerMap.end() )
  298. return NULL;
  299. return (*mi).second;
  300. }
  301. int CIcarus::Run(int icarusID, char* buffer, long length)
  302. {
  303. CSequencer* sequencer = FindSequencer(icarusID);
  304. if(sequencer)
  305. {
  306. return sequencer->Run(buffer, length, this);
  307. }
  308. return ICARUS_INVALID;
  309. }
  310. int CIcarus::SaveSequenceIDTable()
  311. {
  312. //Save out the number of sequences to follow
  313. int numSequences = m_sequences.size();
  314. BufferWrite( &numSequences, sizeof( numSequences ) );
  315. //Sequences are saved first, by ID and information
  316. sequence_l::iterator sqi;
  317. //First pass, save all sequences ID for reconstruction
  318. int *idTable = new int[ numSequences ];
  319. int itr = 0;
  320. if ( idTable == NULL )
  321. return false;
  322. STL_ITERATE( sqi, m_sequences )
  323. {
  324. idTable[itr++] = (*sqi)->GetID();
  325. }
  326. //game->WriteSaveData( 'SQTB', idTable, sizeof( int ) * numSequences );
  327. BufferWrite( idTable, sizeof( int ) * numSequences );
  328. delete[] idTable;
  329. return true;
  330. }
  331. int CIcarus::SaveSequences()
  332. {
  333. //Save out a listing of all the used sequences by ID
  334. SaveSequenceIDTable();
  335. //Save all the information in order
  336. sequence_l::iterator sqi;
  337. STL_ITERATE( sqi, m_sequences )
  338. {
  339. (*sqi)->Save();
  340. }
  341. return true;
  342. }
  343. int CIcarus::SaveSequencers()
  344. {
  345. //Save out the number of sequences to follow
  346. int numSequencers = m_sequencers.size();
  347. BufferWrite( &numSequencers, sizeof( numSequencers ) );
  348. //The sequencers are then saved
  349. int sequencessaved = 0;
  350. sequencer_l::iterator si;
  351. STL_ITERATE( si, m_sequencers )
  352. {
  353. (*si)->Save();
  354. sequencessaved++;
  355. }
  356. assert( sequencessaved == numSequencers );
  357. return true;
  358. }
  359. int CIcarus::SaveSignals()
  360. {
  361. int numSignals = m_signals.size();
  362. //game->WriteSaveData( 'ISIG', &numSignals, sizeof( numSignals ) );
  363. BufferWrite( &numSignals, sizeof( numSignals ) );
  364. signal_m::iterator si;
  365. STL_ITERATE( si, m_signals )
  366. {
  367. //game->WriteSaveData( 'ISIG', &numSignals, sizeof( numSignals ) );
  368. const char *name = ((*si).first).c_str();
  369. int length = strlen( name ) + 1;
  370. //Save out the string size
  371. BufferWrite( &length, sizeof( length ) );
  372. //Write out the string
  373. BufferWrite( (void *) name, length );
  374. }
  375. return true;
  376. }
  377. // Get the current Game flavor.
  378. int CIcarus::GetFlavor()
  379. {
  380. return m_flavor;
  381. }
  382. int CIcarus::Save()
  383. {
  384. // Allocate the temporary buffer.
  385. CreateBuffer();
  386. IGameInterface* game = IGameInterface::GetGame(m_flavor);
  387. //Save out a ICARUS save block header with the ICARUS version
  388. double version = ICARUS_VERSION;
  389. game->WriteSaveData( 'ICAR', &version, sizeof( version ) );
  390. //Save out the signals
  391. if ( SaveSignals() == false )
  392. {
  393. DestroyBuffer();
  394. return false;
  395. }
  396. //Save out the sequences
  397. if ( SaveSequences() == false )
  398. {
  399. DestroyBuffer();
  400. return false;
  401. }
  402. //Save out the sequencers
  403. if ( SaveSequencers() == false )
  404. {
  405. DestroyBuffer();
  406. return false;
  407. }
  408. // Write out the buffer with all our collected data.
  409. game->WriteSaveData( 'ISEQ', m_byBuffer, m_ulBufferCurPos );
  410. // De-allocate the temporary buffer.
  411. DestroyBuffer();
  412. return true;
  413. }
  414. int CIcarus::LoadSignals()
  415. {
  416. int numSignals;
  417. BufferRead( &numSignals, sizeof( numSignals ) );
  418. for ( int i = 0; i < numSignals; i++ )
  419. {
  420. char buffer[1024];
  421. int length;
  422. //Get the size of the string
  423. BufferRead( &length, sizeof( length ) );
  424. //Get the string
  425. BufferRead( &buffer, length );
  426. //Turn it on and add it to the system
  427. Signal( (const char *) &buffer );
  428. }
  429. return true;
  430. }
  431. int CIcarus::LoadSequence()
  432. {
  433. CSequence *sequence = GetSequence();
  434. //Load the sequence back in
  435. sequence->Load(this);
  436. //If this sequence had a higher GUID than the current, save it
  437. if ( sequence->GetID() > m_GUID )
  438. m_GUID = sequence->GetID();
  439. return true;
  440. }
  441. int CIcarus::LoadSequences()
  442. {
  443. CSequence *sequence;
  444. int numSequences;
  445. //Get the number of sequences to read in
  446. BufferRead( &numSequences, sizeof( numSequences ) );
  447. int *idTable = new int[ numSequences ];
  448. if ( idTable == NULL )
  449. return false;
  450. //Load the sequencer ID table
  451. BufferRead( idTable, sizeof( int ) * numSequences );
  452. //First pass, allocate all container sequences and give them their proper IDs
  453. if ( AllocateSequences( numSequences, idTable ) == false )
  454. return false;
  455. //Second pass, load all sequences
  456. for ( int i = 0; i < numSequences; i++ )
  457. {
  458. //Get the proper sequence for this load
  459. if ( ( sequence = GetSequence( idTable[i] ) ) == NULL )
  460. return false;
  461. //Load the sequence
  462. if ( ( sequence->Load(this) ) == false )
  463. return false;
  464. }
  465. //Free the idTable
  466. delete[] idTable;
  467. return true;
  468. }
  469. int CIcarus::LoadSequencers()
  470. {
  471. CSequencer *sequencer;
  472. int numSequencers;
  473. IGameInterface* game = IGameInterface::GetGame(m_flavor);
  474. //Get the number of sequencers to load
  475. BufferRead( &numSequencers, sizeof( numSequencers ) );
  476. //Load all sequencers
  477. for ( int i = 0; i < numSequencers; i++ )
  478. {
  479. //NOTENOTE: The ownerID will be replaced in the loading process
  480. int sequencerID = GetIcarusID(-1);
  481. if ( ( sequencer = FindSequencer(sequencerID) ) == NULL )
  482. return false;
  483. if ( sequencer->Load(this, game) == false )
  484. return false;
  485. }
  486. return true;
  487. }
  488. int CIcarus::Load()
  489. {
  490. CreateBuffer();
  491. IGameInterface* game = IGameInterface::GetGame(m_flavor);
  492. //Clear out any old information
  493. Free();
  494. //Check to make sure we're at the ICARUS save block
  495. double version;
  496. game->ReadSaveData( 'ICAR', &version, sizeof( version ) );
  497. //Versions must match!
  498. if ( version != ICARUS_VERSION )
  499. {
  500. DestroyBuffer();
  501. game->DebugPrint( IGameInterface::WL_ERROR, "save game data contains outdated ICARUS version information!\n");
  502. return false;
  503. }
  504. // Read into the buffer all our data.
  505. /*m_ulBytesAvailable = */game->ReadSaveData( 'ISEQ', m_byBuffer, 0 ); //fixme, use real buff size
  506. //Load all signals
  507. if ( LoadSignals() == false )
  508. {
  509. DestroyBuffer();
  510. game->DebugPrint( IGameInterface::WL_ERROR, "failed to load signals from save game!\n");
  511. return false;
  512. }
  513. //Load in all sequences
  514. if ( LoadSequences() == false )
  515. {
  516. DestroyBuffer();
  517. game->DebugPrint( IGameInterface::WL_ERROR, "failed to load sequences from save game!\n");
  518. return false;
  519. }
  520. //Load in all sequencers
  521. if ( LoadSequencers() == false )
  522. {
  523. DestroyBuffer();
  524. game->DebugPrint( IGameInterface::WL_ERROR, "failed to load sequencers from save game!\n");
  525. return false;
  526. }
  527. DestroyBuffer();
  528. return true;
  529. }
  530. int CIcarus::Update(int icarusID)
  531. {
  532. CSequencer* sequencer = FindSequencer(icarusID);
  533. if(sequencer)
  534. {
  535. return sequencer->GetTaskManager()->Update(this);
  536. }
  537. return -1;
  538. }
  539. int CIcarus::IsRunning(int icarusID)
  540. {
  541. CSequencer* sequencer = FindSequencer(icarusID);
  542. if(sequencer)
  543. {
  544. return sequencer->GetTaskManager()->IsRunning();
  545. }
  546. return false;
  547. }
  548. void CIcarus::Completed( int icarusID, int taskID )
  549. {
  550. CSequencer* sequencer = FindSequencer(icarusID);
  551. if(sequencer)
  552. {
  553. sequencer->GetTaskManager()->Completed(taskID);
  554. }
  555. }
  556. // Destroy the File Buffer.
  557. void CIcarus::DestroyBuffer()
  558. {
  559. if ( m_byBuffer )
  560. {
  561. IGameInterface::GetGame()->Free( m_byBuffer );
  562. m_byBuffer = NULL;
  563. }
  564. }
  565. // Create the File Buffer.
  566. void CIcarus::CreateBuffer()
  567. {
  568. DestroyBuffer();
  569. m_byBuffer = (unsigned char *)IGameInterface::GetGame()->Malloc( MAX_BUFFER_SIZE );
  570. m_ulBufferCurPos = 0;
  571. }
  572. // Write to a buffer.
  573. void CIcarus::BufferWrite( void *pSrcData, unsigned long ulNumBytesToWrite )
  574. {
  575. if ( !pSrcData )
  576. return;
  577. // Make sure we have enough space in the buffer to write to.
  578. if ( MAX_BUFFER_SIZE - m_ulBufferCurPos < ulNumBytesToWrite )
  579. { // Write out the buffer with all our collected data so far...
  580. IGameInterface::GetGame()->DebugPrint( IGameInterface::WL_ERROR, "BufferWrite: Out of buffer space, Flushing." );
  581. IGameInterface::GetGame()->WriteSaveData( 'ISEQ', m_byBuffer, m_ulBufferCurPos );
  582. m_ulBufferCurPos = 0; //reset buffer
  583. }
  584. assert( MAX_BUFFER_SIZE - m_ulBufferCurPos >= ulNumBytesToWrite );
  585. {
  586. memcpy( m_byBuffer + m_ulBufferCurPos, pSrcData, ulNumBytesToWrite );
  587. m_ulBufferCurPos += ulNumBytesToWrite;
  588. }
  589. }
  590. // Read from a buffer.
  591. void CIcarus::BufferRead( void *pDstBuff, unsigned long ulNumBytesToRead )
  592. {
  593. if ( !pDstBuff )
  594. return;
  595. // If we can read this data...
  596. if ( m_ulBytesRead + ulNumBytesToRead > MAX_BUFFER_SIZE )
  597. {// We've tried to read past the buffer...
  598. IGameInterface::GetGame()->DebugPrint( IGameInterface::WL_ERROR, "BufferRead: Buffer underflow, Looking for new block." );
  599. // Read in the next block.
  600. /*m_ulBytesAvailable = */IGameInterface::GetGame()->ReadSaveData( 'ISEQ', m_byBuffer, 0 ); //FIXME, to actually check underflows, use real buff size
  601. m_ulBytesRead = 0; //reset buffer
  602. }
  603. assert(m_ulBytesRead + ulNumBytesToRead <= MAX_BUFFER_SIZE);
  604. {
  605. memcpy( pDstBuff, m_byBuffer + m_ulBytesRead, ulNumBytesToRead );
  606. m_ulBytesRead += ulNumBytesToRead;
  607. }
  608. }