mirror of
https://github.com/DrBeef/JKXR.git
synced 2024-12-11 13:11:58 +00:00
882 lines
18 KiB
C++
882 lines
18 KiB
C++
|
/*
|
||
|
===========================================================================
|
||
|
Copyright (C) 2000 - 2013, Raven Software, Inc.
|
||
|
Copyright (C) 2001 - 2013, Activision, Inc.
|
||
|
Copyright (C) 2013 - 2015, OpenJK contributors
|
||
|
|
||
|
This file is part of the OpenJK source code.
|
||
|
|
||
|
OpenJK is free software; you can redistribute it and/or modify it
|
||
|
under the terms of the GNU General Public License version 2 as
|
||
|
published by the Free Software Foundation.
|
||
|
|
||
|
This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
|
||
|
===========================================================================
|
||
|
*/
|
||
|
|
||
|
// IcarusImplementation.cpp
|
||
|
|
||
|
#include <memory>
|
||
|
#include "StdAfx.h"
|
||
|
#include "IcarusInterface.h"
|
||
|
#include "IcarusImplementation.h"
|
||
|
|
||
|
#include "blockstream.h"
|
||
|
#include "sequence.h"
|
||
|
#include "taskmanager.h"
|
||
|
#include "sequencer.h"
|
||
|
|
||
|
#include "../qcommon/q_shared.h"
|
||
|
#include "../qcommon/qcommon.h"
|
||
|
#include "qcommon/ojk_saved_game_helper.h"
|
||
|
|
||
|
#define STL_ITERATE( a, b ) for ( a = b.begin(); a != b.end(); ++a )
|
||
|
#define STL_INSERT( a, b ) a.insert( a.end(), b );
|
||
|
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// required implementation of CIcarusInterface
|
||
|
|
||
|
IIcarusInterface* IIcarusInterface::GetIcarus(int flavor,bool constructIfNecessary)
|
||
|
{
|
||
|
if(!CIcarus::s_instances && constructIfNecessary)
|
||
|
{
|
||
|
CIcarus::s_flavorsAvailable = IGameInterface::s_IcarusFlavorsNeeded;
|
||
|
if (!CIcarus::s_flavorsAvailable)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
CIcarus::s_instances = new CIcarus*[CIcarus::s_flavorsAvailable];
|
||
|
for (int index = 0; index < CIcarus::s_flavorsAvailable; index++)
|
||
|
{
|
||
|
CIcarus::s_instances[index] = new CIcarus(index);
|
||
|
//OutputDebugString( "ICARUS flavor successfully created\n" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(flavor >= CIcarus::s_flavorsAvailable || !CIcarus::s_instances )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
return CIcarus::s_instances[flavor];
|
||
|
}
|
||
|
|
||
|
void IIcarusInterface::DestroyIcarus()
|
||
|
{
|
||
|
for(int index = 0; index < CIcarus::s_flavorsAvailable; index++)
|
||
|
{
|
||
|
delete CIcarus::s_instances[index];
|
||
|
}
|
||
|
delete[] CIcarus::s_instances;
|
||
|
CIcarus::s_instances = NULL;
|
||
|
CIcarus::s_flavorsAvailable = 0;
|
||
|
}
|
||
|
|
||
|
IIcarusInterface::~IIcarusInterface()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// CIcarus
|
||
|
|
||
|
double CIcarus::ICARUS_VERSION = 1.40;
|
||
|
|
||
|
int CIcarus::s_flavorsAvailable = 0;
|
||
|
|
||
|
CIcarus** CIcarus::s_instances = NULL;
|
||
|
|
||
|
CIcarus::CIcarus(int flavor) :
|
||
|
m_flavor(flavor), m_nextSequencerID(0)
|
||
|
{
|
||
|
|
||
|
m_GUID = 0;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequencerAlloc = 0;
|
||
|
m_DEBUG_NumSequencerFreed = 0;
|
||
|
m_DEBUG_NumSequencerResidual = 0;
|
||
|
|
||
|
m_DEBUG_NumSequenceAlloc = 0;
|
||
|
m_DEBUG_NumSequenceFreed = 0;
|
||
|
m_DEBUG_NumSequenceResidual = 0;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
m_ulBufferCurPos = 0;
|
||
|
m_ulBytesRead = 0;
|
||
|
m_byBuffer = NULL;
|
||
|
}
|
||
|
|
||
|
CIcarus::~CIcarus()
|
||
|
{
|
||
|
Delete();
|
||
|
}
|
||
|
|
||
|
void CIcarus::Delete( void )
|
||
|
{
|
||
|
|
||
|
Free();
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
Com_Printf( "ICARUS Instance Debug Info:\n" );
|
||
|
Com_Printf( "---------------------------\n" );
|
||
|
Com_Printf( "Sequencers Allocated:\t%d\n", m_DEBUG_NumSequencerAlloc );
|
||
|
Com_Printf( "Sequencers Freed:\t\t%d\n", m_DEBUG_NumSequencerFreed );
|
||
|
Com_Printf( "Sequencers Residual:\t%d\n\n", m_DEBUG_NumSequencerResidual );
|
||
|
Com_Printf( "Sequences Allocated:\t%d\n", m_DEBUG_NumSequenceAlloc );
|
||
|
Com_Printf( "Sequences Freed:\t\t%d\n", m_DEBUG_NumSequenceFreed );
|
||
|
Com_Printf( "Sequences Residual:\t\t%d\n\n", m_DEBUG_NumSequenceResidual );
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void CIcarus::Signal( const char *identifier )
|
||
|
{
|
||
|
m_signals[ identifier ] = 1;
|
||
|
}
|
||
|
|
||
|
bool CIcarus::CheckSignal( const char *identifier )
|
||
|
{
|
||
|
signal_m::iterator smi;
|
||
|
|
||
|
smi = m_signals.find( identifier );
|
||
|
|
||
|
if ( smi == m_signals.end() )
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void CIcarus::ClearSignal( const char *identifier )
|
||
|
{
|
||
|
m_signals.erase( identifier );
|
||
|
}
|
||
|
|
||
|
void CIcarus::Free( void )
|
||
|
{
|
||
|
sequencer_l::iterator sri;
|
||
|
|
||
|
//Delete any residual sequencers
|
||
|
STL_ITERATE( sri, m_sequencers )
|
||
|
{
|
||
|
(*sri)->Free(this);
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequencerResidual++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
m_sequencers.clear();
|
||
|
m_signals.clear();
|
||
|
|
||
|
sequence_l::iterator si;
|
||
|
|
||
|
//Delete any residual sequences
|
||
|
STL_ITERATE( si, m_sequences )
|
||
|
{
|
||
|
(*si)->Delete(this);
|
||
|
delete (*si);
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequenceResidual++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
m_sequences.clear();
|
||
|
|
||
|
m_sequencerMap.clear();
|
||
|
}
|
||
|
|
||
|
int CIcarus::GetIcarusID( int gameID )
|
||
|
{
|
||
|
CSequencer *sequencer = CSequencer::Create();
|
||
|
CTaskManager *taskManager = CTaskManager::Create();
|
||
|
|
||
|
sequencer->Init( gameID, taskManager );
|
||
|
|
||
|
taskManager->Init( sequencer );
|
||
|
|
||
|
STL_INSERT( m_sequencers, sequencer );
|
||
|
|
||
|
m_sequencerMap[sequencer->GetID()] = sequencer;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequencerAlloc++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return sequencer->GetID();
|
||
|
}
|
||
|
|
||
|
void CIcarus::DeleteIcarusID( int& icarusID )
|
||
|
{
|
||
|
CSequencer* sequencer = FindSequencer(icarusID);
|
||
|
if(!sequencer)
|
||
|
{
|
||
|
icarusID = -1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CTaskManager *taskManager = sequencer->GetTaskManager();
|
||
|
if (taskManager->IsResident())
|
||
|
{
|
||
|
IGameInterface::GetGame()->DebugPrint( IGameInterface::WL_ERROR, "Refusing DeleteIcarusID(%d) because it is running!\n", icarusID);
|
||
|
assert(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m_sequencerMap.erase(icarusID);
|
||
|
|
||
|
// added 2/12/2 to properly delete blocks that were passed to the task manager
|
||
|
sequencer->Recall(this);
|
||
|
|
||
|
|
||
|
if ( taskManager )
|
||
|
{
|
||
|
taskManager->Free();
|
||
|
delete taskManager;
|
||
|
}
|
||
|
|
||
|
m_sequencers.remove( sequencer );
|
||
|
|
||
|
sequencer->Free(this);
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequencerFreed++;
|
||
|
|
||
|
#endif
|
||
|
icarusID = -1;
|
||
|
}
|
||
|
|
||
|
CSequence *CIcarus::GetSequence( void )
|
||
|
{
|
||
|
CSequence *sequence = CSequence::Create();
|
||
|
|
||
|
//Assign the GUID
|
||
|
sequence->SetID( m_GUID++ );
|
||
|
|
||
|
STL_INSERT( m_sequences, sequence );
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequenceAlloc++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return sequence;
|
||
|
}
|
||
|
|
||
|
CSequence *CIcarus::GetSequence( int id )
|
||
|
{
|
||
|
sequence_l::iterator si;
|
||
|
STL_ITERATE( si, m_sequences )
|
||
|
{
|
||
|
if ( (*si)->GetID() == id )
|
||
|
return (*si);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void CIcarus::DeleteSequence( CSequence *sequence )
|
||
|
{
|
||
|
m_sequences.remove( sequence );
|
||
|
|
||
|
sequence->Delete(this);
|
||
|
delete sequence;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequenceFreed++;
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int CIcarus::AllocateSequences( int numSequences, int *idTable )
|
||
|
{
|
||
|
CSequence *sequence;
|
||
|
|
||
|
for ( int i = 0; i < numSequences; i++ )
|
||
|
{
|
||
|
//If the GUID of this sequence is higher than the current, take this a the "current" GUID
|
||
|
if ( idTable[i] > m_GUID )
|
||
|
m_GUID = idTable[i];
|
||
|
|
||
|
//Allocate the container sequence
|
||
|
if ( ( sequence = GetSequence() ) == NULL )
|
||
|
return false;
|
||
|
|
||
|
//Override the given GUID with the real one
|
||
|
sequence->SetID( idTable[i] );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void CIcarus::Precache(char* buffer, long length)
|
||
|
{
|
||
|
IGameInterface* game = IGameInterface::GetGame(m_flavor);
|
||
|
CBlockStream stream;
|
||
|
CBlockMember *blockMember;
|
||
|
CBlock block;
|
||
|
|
||
|
if ( stream.Open( buffer, length ) == 0 )
|
||
|
return;
|
||
|
|
||
|
const char *sVal1, *sVal2;
|
||
|
|
||
|
//Now iterate through all blocks of the script, searching for keywords
|
||
|
while ( stream.BlockAvailable() )
|
||
|
{
|
||
|
//Get a block
|
||
|
if ( stream.ReadBlock( &block, this ) == 0 )
|
||
|
return;
|
||
|
|
||
|
//Determine what type of block this is
|
||
|
switch( block.GetBlockID() )
|
||
|
{
|
||
|
case ID_CAMERA: // to cache ROFF files
|
||
|
{
|
||
|
float f = *(float *) block.GetMemberData( 0 );
|
||
|
|
||
|
if (f == TYPE_PATH)
|
||
|
{
|
||
|
sVal1 = (const char *) block.GetMemberData( 1 );
|
||
|
|
||
|
game->PrecacheRoff(sVal1);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ID_PLAY: // to cache ROFF files
|
||
|
|
||
|
sVal1 = (const char *) block.GetMemberData( 0 );
|
||
|
|
||
|
if (!Q_stricmp(sVal1,"PLAY_ROFF"))
|
||
|
{
|
||
|
sVal1 = (const char *) block.GetMemberData( 1 );
|
||
|
|
||
|
game->PrecacheRoff(sVal1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
//Run commands
|
||
|
case ID_RUN:
|
||
|
sVal1 = (const char *) block.GetMemberData( 0 );
|
||
|
game->PrecacheScript( sVal1 );
|
||
|
break;
|
||
|
|
||
|
case ID_SOUND:
|
||
|
sVal1 = (const char *) block.GetMemberData( 1 ); //0 is channel, 1 is filename
|
||
|
game->PrecacheSound(sVal1);
|
||
|
break;
|
||
|
|
||
|
case ID_SET:
|
||
|
blockMember = block.GetMember( 0 );
|
||
|
|
||
|
//NOTENOTE: This will not catch special case get() inlines! (There's not really a good way to do that)
|
||
|
|
||
|
//Make sure we're testing against strings
|
||
|
if ( blockMember->GetID() == TK_STRING )
|
||
|
{
|
||
|
sVal1 = (const char *) block.GetMemberData( 0 );
|
||
|
sVal2 = (const char *) block.GetMemberData( 1 );
|
||
|
|
||
|
game->PrecacheFromSet( sVal1 , sVal2);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//Clean out the block for the next pass
|
||
|
block.Free(this);
|
||
|
}
|
||
|
|
||
|
//All done
|
||
|
stream.Free();
|
||
|
}
|
||
|
|
||
|
CSequencer* CIcarus::FindSequencer(int sequencerID)
|
||
|
{
|
||
|
sequencer_m::iterator mi = m_sequencerMap.find( sequencerID );
|
||
|
|
||
|
if ( mi == m_sequencerMap.end() )
|
||
|
return NULL;
|
||
|
|
||
|
return (*mi).second;
|
||
|
}
|
||
|
|
||
|
int CIcarus::Run(int icarusID, char* buffer, long length)
|
||
|
{
|
||
|
CSequencer* sequencer = FindSequencer(icarusID);
|
||
|
if(sequencer)
|
||
|
{
|
||
|
return sequencer->Run(buffer, length, this);
|
||
|
}
|
||
|
return ICARUS_INVALID;
|
||
|
}
|
||
|
|
||
|
int CIcarus::SaveSequenceIDTable()
|
||
|
{
|
||
|
//Save out the number of sequences to follow
|
||
|
int numSequences = m_sequences.size();
|
||
|
|
||
|
BufferWrite( &numSequences, sizeof( numSequences ) );
|
||
|
|
||
|
//Sequences are saved first, by ID and information
|
||
|
sequence_l::iterator sqi;
|
||
|
|
||
|
//First pass, save all sequences ID for reconstruction
|
||
|
int *idTable = new int[ numSequences ];
|
||
|
int itr = 0;
|
||
|
|
||
|
if ( idTable == NULL )
|
||
|
return false;
|
||
|
|
||
|
STL_ITERATE( sqi, m_sequences )
|
||
|
{
|
||
|
idTable[itr++] = (*sqi)->GetID();
|
||
|
}
|
||
|
|
||
|
//game->WriteSaveData( INT_ID('S','Q','T','B'), idTable, sizeof( int ) * numSequences );
|
||
|
BufferWrite( idTable, sizeof( int ) * numSequences );
|
||
|
|
||
|
delete[] idTable;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::SaveSequences()
|
||
|
{
|
||
|
//Save out a listing of all the used sequences by ID
|
||
|
SaveSequenceIDTable();
|
||
|
|
||
|
//Save all the information in order
|
||
|
sequence_l::iterator sqi;
|
||
|
STL_ITERATE( sqi, m_sequences )
|
||
|
{
|
||
|
(*sqi)->Save();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::SaveSequencers()
|
||
|
{
|
||
|
//Save out the number of sequences to follow
|
||
|
int numSequencers = m_sequencers.size();
|
||
|
BufferWrite( &numSequencers, sizeof( numSequencers ) );
|
||
|
|
||
|
//The sequencers are then saved
|
||
|
int sequencessaved = 0;
|
||
|
sequencer_l::iterator si;
|
||
|
STL_ITERATE( si, m_sequencers )
|
||
|
{
|
||
|
(*si)->Save();
|
||
|
sequencessaved++;
|
||
|
}
|
||
|
|
||
|
assert( sequencessaved == numSequencers );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::SaveSignals()
|
||
|
{
|
||
|
int numSignals = m_signals.size();
|
||
|
|
||
|
//game->WriteSaveData( INT_ID('I','S','I','G'), &numSignals, sizeof( numSignals ) );
|
||
|
BufferWrite( &numSignals, sizeof( numSignals ) );
|
||
|
|
||
|
signal_m::iterator si;
|
||
|
STL_ITERATE( si, m_signals )
|
||
|
{
|
||
|
//game->WriteSaveData( INT_ID('I','S','I','G'), &numSignals, sizeof( numSignals ) );
|
||
|
const char *name = ((*si).first).c_str();
|
||
|
|
||
|
int length = strlen( name ) + 1;
|
||
|
|
||
|
//Save out the string size
|
||
|
BufferWrite( &length, sizeof( length ) );
|
||
|
|
||
|
//Write out the string
|
||
|
BufferWrite( (void *) name, length );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Get the current Game flavor.
|
||
|
int CIcarus::GetFlavor()
|
||
|
{
|
||
|
return m_flavor;
|
||
|
}
|
||
|
|
||
|
int CIcarus::Save()
|
||
|
{
|
||
|
// Allocate the temporary buffer.
|
||
|
CreateBuffer();
|
||
|
|
||
|
IGameInterface* game = IGameInterface::GetGame(m_flavor);
|
||
|
|
||
|
ojk::SavedGameHelper saved_game(
|
||
|
game->get_saved_game_file());
|
||
|
|
||
|
//Save out a ICARUS save block header with the ICARUS version
|
||
|
double version = ICARUS_VERSION;
|
||
|
|
||
|
saved_game.write_chunk<double>(
|
||
|
INT_ID('I', 'C', 'A', 'R'),
|
||
|
version);
|
||
|
|
||
|
//Save out the signals
|
||
|
if ( SaveSignals() == false )
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Save out the sequences
|
||
|
if ( SaveSequences() == false )
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Save out the sequencers
|
||
|
if ( SaveSequencers() == false )
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Write out the buffer with all our collected data.
|
||
|
saved_game.write_chunk(
|
||
|
INT_ID('I', 'S', 'E', 'Q'),
|
||
|
m_byBuffer,
|
||
|
static_cast<int>(m_ulBufferCurPos));
|
||
|
|
||
|
// De-allocate the temporary buffer.
|
||
|
DestroyBuffer();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::LoadSignals()
|
||
|
{
|
||
|
int numSignals;
|
||
|
|
||
|
BufferRead( &numSignals, sizeof( numSignals ) );
|
||
|
|
||
|
for ( int i = 0; i < numSignals; i++ )
|
||
|
{
|
||
|
char buffer[1024];
|
||
|
int length = 0;
|
||
|
|
||
|
//Get the size of the string
|
||
|
BufferRead( &length, sizeof( length ) );
|
||
|
|
||
|
//Get the string
|
||
|
BufferRead( &buffer, length );
|
||
|
|
||
|
//Turn it on and add it to the system
|
||
|
Signal( (const char *) &buffer );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::LoadSequence()
|
||
|
{
|
||
|
CSequence *sequence = GetSequence();
|
||
|
|
||
|
//Load the sequence back in
|
||
|
sequence->Load(this);
|
||
|
|
||
|
//If this sequence had a higher GUID than the current, save it
|
||
|
if ( sequence->GetID() > m_GUID )
|
||
|
m_GUID = sequence->GetID();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::LoadSequences()
|
||
|
{
|
||
|
CSequence *sequence;
|
||
|
int numSequences;
|
||
|
|
||
|
//Get the number of sequences to read in
|
||
|
BufferRead( &numSequences, sizeof( numSequences ) );
|
||
|
|
||
|
int *idTable = new int[ numSequences ];
|
||
|
|
||
|
if ( idTable == NULL )
|
||
|
return false;
|
||
|
|
||
|
//Load the sequencer ID table
|
||
|
BufferRead( idTable, sizeof( int ) * numSequences );
|
||
|
|
||
|
//First pass, allocate all container sequences and give them their proper IDs
|
||
|
if ( AllocateSequences( numSequences, idTable ) == false )
|
||
|
return false;
|
||
|
|
||
|
//Second pass, load all sequences
|
||
|
for ( int i = 0; i < numSequences; i++ )
|
||
|
{
|
||
|
//Get the proper sequence for this load
|
||
|
if ( ( sequence = GetSequence( idTable[i] ) ) == NULL )
|
||
|
return false;
|
||
|
|
||
|
//Load the sequence
|
||
|
if ( ( sequence->Load(this) ) == false )
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Free the idTable
|
||
|
delete[] idTable;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::LoadSequencers()
|
||
|
{
|
||
|
CSequencer *sequencer;
|
||
|
int numSequencers;
|
||
|
IGameInterface* game = IGameInterface::GetGame(m_flavor);
|
||
|
|
||
|
//Get the number of sequencers to load
|
||
|
BufferRead( &numSequencers, sizeof( numSequencers ) );
|
||
|
|
||
|
//Load all sequencers
|
||
|
for ( int i = 0; i < numSequencers; i++ )
|
||
|
{
|
||
|
//NOTENOTE: The ownerID will be replaced in the loading process
|
||
|
int sequencerID = GetIcarusID(-1);
|
||
|
if ( ( sequencer = FindSequencer(sequencerID) ) == NULL )
|
||
|
return false;
|
||
|
|
||
|
if ( sequencer->Load(this, game) == false )
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::Load()
|
||
|
{
|
||
|
CreateBuffer();
|
||
|
|
||
|
IGameInterface* game = IGameInterface::GetGame(m_flavor);
|
||
|
|
||
|
ojk::SavedGameHelper saved_game(
|
||
|
game->get_saved_game_file());
|
||
|
|
||
|
//Clear out any old information
|
||
|
Free();
|
||
|
|
||
|
//Check to make sure we're at the ICARUS save block
|
||
|
double version = 0.0;
|
||
|
|
||
|
saved_game.read_chunk<double>(
|
||
|
INT_ID('I', 'C', 'A', 'R'),
|
||
|
version);
|
||
|
|
||
|
//Versions must match!
|
||
|
if ( version != ICARUS_VERSION )
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
game->DebugPrint( IGameInterface::WL_ERROR, "save game data contains outdated ICARUS version information!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Read into the buffer all our data.
|
||
|
saved_game.read_chunk(
|
||
|
INT_ID('I','S','E','Q'));
|
||
|
|
||
|
const unsigned char* sg_buffer_data = static_cast<const unsigned char*>(
|
||
|
saved_game.get_buffer_data());
|
||
|
|
||
|
int sg_buffer_size = saved_game.get_buffer_size();
|
||
|
|
||
|
if (sg_buffer_size < 0 || static_cast<size_t>(sg_buffer_size) > MAX_BUFFER_SIZE)
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
game->DebugPrint( IGameInterface::WL_ERROR, "invalid ISEQ length: %d bytes\n", sg_buffer_size);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
std::uninitialized_copy_n(
|
||
|
sg_buffer_data,
|
||
|
sg_buffer_size,
|
||
|
m_byBuffer);
|
||
|
|
||
|
//Load all signals
|
||
|
if ( LoadSignals() == false )
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
game->DebugPrint( IGameInterface::WL_ERROR, "failed to load signals from save game!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Load in all sequences
|
||
|
if ( LoadSequences() == false )
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
game->DebugPrint( IGameInterface::WL_ERROR, "failed to load sequences from save game!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Load in all sequencers
|
||
|
if ( LoadSequencers() == false )
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
game->DebugPrint( IGameInterface::WL_ERROR, "failed to load sequencers from save game!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
DestroyBuffer();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CIcarus::Update(int icarusID)
|
||
|
{
|
||
|
CSequencer* sequencer = FindSequencer(icarusID);
|
||
|
if(sequencer)
|
||
|
{
|
||
|
return sequencer->GetTaskManager()->Update(this);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int CIcarus::IsRunning(int icarusID)
|
||
|
{
|
||
|
CSequencer* sequencer = FindSequencer(icarusID);
|
||
|
if(sequencer)
|
||
|
{
|
||
|
return sequencer->GetTaskManager()->IsRunning();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void CIcarus::Completed( int icarusID, int taskID )
|
||
|
{
|
||
|
CSequencer* sequencer = FindSequencer(icarusID);
|
||
|
if(sequencer)
|
||
|
{
|
||
|
sequencer->GetTaskManager()->Completed(taskID);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Destroy the File Buffer.
|
||
|
void CIcarus::DestroyBuffer()
|
||
|
{
|
||
|
if ( m_byBuffer )
|
||
|
{
|
||
|
IGameInterface::GetGame()->Free( m_byBuffer );
|
||
|
m_byBuffer = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create the File Buffer.
|
||
|
void CIcarus::CreateBuffer()
|
||
|
{
|
||
|
DestroyBuffer();
|
||
|
m_byBuffer = (unsigned char *)IGameInterface::GetGame()->Malloc( MAX_BUFFER_SIZE );
|
||
|
m_ulBufferCurPos = 0;
|
||
|
}
|
||
|
|
||
|
// Write to a buffer.
|
||
|
void CIcarus::BufferWrite( void *pSrcData, unsigned long ulNumBytesToWrite )
|
||
|
{
|
||
|
if ( !pSrcData )
|
||
|
return;
|
||
|
|
||
|
// Make sure we have enough space in the buffer to write to.
|
||
|
if ( MAX_BUFFER_SIZE - m_ulBufferCurPos < ulNumBytesToWrite )
|
||
|
{ // Write out the buffer with all our collected data so far...
|
||
|
IGameInterface::GetGame()->DebugPrint( IGameInterface::WL_ERROR, "BufferWrite: Out of buffer space, Flushing." );
|
||
|
|
||
|
ojk::SavedGameHelper saved_game(
|
||
|
IGameInterface::GetGame()->get_saved_game_file());
|
||
|
|
||
|
saved_game.write_chunk(
|
||
|
INT_ID('I', 'S', 'E', 'Q'),
|
||
|
m_byBuffer,
|
||
|
static_cast<int>(m_ulBufferCurPos));
|
||
|
|
||
|
m_ulBufferCurPos = 0; //reset buffer
|
||
|
}
|
||
|
|
||
|
assert( MAX_BUFFER_SIZE - m_ulBufferCurPos >= ulNumBytesToWrite );
|
||
|
{
|
||
|
memcpy( m_byBuffer + m_ulBufferCurPos, pSrcData, ulNumBytesToWrite );
|
||
|
m_ulBufferCurPos += ulNumBytesToWrite;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Read from a buffer.
|
||
|
void CIcarus::BufferRead( void *pDstBuff, unsigned long ulNumBytesToRead )
|
||
|
{
|
||
|
if ( !pDstBuff )
|
||
|
return;
|
||
|
|
||
|
// If we can read this data...
|
||
|
if ( m_ulBytesRead + ulNumBytesToRead > MAX_BUFFER_SIZE )
|
||
|
{// We've tried to read past the buffer...
|
||
|
IGameInterface::GetGame()->DebugPrint( IGameInterface::WL_ERROR, "BufferRead: Buffer underflow, Looking for new block." );
|
||
|
// Read in the next block.
|
||
|
|
||
|
ojk::SavedGameHelper saved_game(
|
||
|
IGameInterface::GetGame()->get_saved_game_file());
|
||
|
|
||
|
saved_game.read_chunk(
|
||
|
INT_ID('I', 'S', 'E', 'Q'));
|
||
|
|
||
|
const unsigned char* sg_buffer_data = static_cast<const unsigned char*>(
|
||
|
saved_game.get_buffer_data());
|
||
|
|
||
|
int sg_buffer_size = saved_game.get_buffer_size();
|
||
|
|
||
|
if (sg_buffer_size < 0 || static_cast<size_t>(sg_buffer_size) > MAX_BUFFER_SIZE)
|
||
|
{
|
||
|
IGameInterface::GetGame()->DebugPrint( IGameInterface::WL_ERROR, "invalid ISEQ length: %d bytes\n", sg_buffer_size);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
std::uninitialized_copy_n(
|
||
|
sg_buffer_data,
|
||
|
sg_buffer_size,
|
||
|
m_byBuffer);
|
||
|
|
||
|
m_ulBytesRead = 0; //reset buffer
|
||
|
}
|
||
|
|
||
|
assert(m_ulBytesRead + ulNumBytesToRead <= MAX_BUFFER_SIZE);
|
||
|
{
|
||
|
memcpy( pDstBuff, m_byBuffer + m_ulBytesRead, ulNumBytesToRead );
|
||
|
m_ulBytesRead += ulNumBytesToRead;
|
||
|
}
|
||
|
}
|