mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-18 11:44:51 +02:00
Added typeinfogen with state system
This commit is contained in:
@@ -0,0 +1,496 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "../Game_local.h"
|
||||
|
||||
const int HISTORY_COUNT = 50;
|
||||
|
||||
/*
|
||||
=====================
|
||||
stateParms_t::Wait
|
||||
=====================
|
||||
*/
|
||||
void stateParms_t::Wait( float seconds )
|
||||
{
|
||||
time = gameLocal.time + SEC2MS( seconds );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
stateParms_t::Save
|
||||
=====================
|
||||
*/
|
||||
void stateParms_t::Save( idSaveGame* saveFile ) const
|
||||
{
|
||||
saveFile->WriteInt( blendFrames );
|
||||
saveFile->WriteInt( time );
|
||||
saveFile->WriteInt( stage );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
stateParms_t::Restore
|
||||
=====================
|
||||
*/
|
||||
void stateParms_t::Restore( idRestoreGame* saveFile )
|
||||
{
|
||||
saveFile->ReadInt( blendFrames );
|
||||
saveFile->ReadInt( time );
|
||||
saveFile->ReadInt( stage );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
stateCall_t::Save
|
||||
=====================
|
||||
*/
|
||||
void stateCall_t::Save( idSaveGame* saveFile ) const
|
||||
{
|
||||
saveFile->WriteString( state );
|
||||
// TOSAVE: idLinkList<stateCall_t> node;
|
||||
saveFile->WriteInt( flags );
|
||||
saveFile->WriteInt( delay );
|
||||
parms.Save( saveFile );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
stateCall_t::Save
|
||||
=====================
|
||||
*/
|
||||
void stateCall_t::Restore( idRestoreGame* saveFile, const idClass* owner )
|
||||
{
|
||||
saveFile->ReadString( state );
|
||||
saveFile->ReadInt( flags );
|
||||
saveFile->ReadInt( delay );
|
||||
parms.Restore( saveFile );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::rvStateThread
|
||||
=====================
|
||||
*/
|
||||
rvStateThread::rvStateThread( void )
|
||||
{
|
||||
owner = NULL;
|
||||
insertAfter = NULL;
|
||||
lastResult = SRESULT_DONE;
|
||||
|
||||
states.Clear( );
|
||||
interrupted.Clear( );
|
||||
|
||||
memset( &fl, 0, sizeof( fl ) );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::~rvStateThread
|
||||
=====================
|
||||
*/
|
||||
rvStateThread::~rvStateThread( void )
|
||||
{
|
||||
Clear( true );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::SetOwner
|
||||
=====================
|
||||
*/
|
||||
void rvStateThread::SetOwner( idClass* _owner )
|
||||
{
|
||||
owner = _owner;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::Post
|
||||
=====================
|
||||
*/
|
||||
stateResult_t rvStateThread::PostState( const char* name, int blendFrames, int delay, int flags )
|
||||
{
|
||||
stateCall_t* call;
|
||||
call = new stateCall_t;
|
||||
call->state = name;
|
||||
call->delay = delay;
|
||||
call->flags = flags;
|
||||
call->parms.blendFrames = blendFrames;
|
||||
call->parms.time = -1;
|
||||
call->parms.stage = 0;
|
||||
call->parms.substage = 0;
|
||||
call->parms.param1 = 0;
|
||||
call->parms.param2 = 0;
|
||||
|
||||
call->parms.subparam1 = 0;
|
||||
call->parms.subparam2 = 0;
|
||||
|
||||
call->node.SetOwner( call );
|
||||
|
||||
if( fl.executing && insertAfter )
|
||||
{
|
||||
call->node.InsertAfter( insertAfter->node );
|
||||
}
|
||||
else
|
||||
{
|
||||
call->node.AddToEnd( states );
|
||||
}
|
||||
|
||||
insertAfter = call;
|
||||
|
||||
return SRESULT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::Set
|
||||
=====================
|
||||
*/
|
||||
stateResult_t rvStateThread::SetState( const char* name, int blendFrames, int delay, int flags )
|
||||
{
|
||||
Clear( );
|
||||
return PostState( name, blendFrames, delay, flags );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::InterruptState
|
||||
=====================
|
||||
*/
|
||||
stateResult_t rvStateThread::InterruptState( const char* name, int blendFrames, int delay, int flags )
|
||||
{
|
||||
stateCall_t* call;
|
||||
|
||||
// Move all states to the front of the interrupted list in the same order
|
||||
for( call = states.Prev(); call; call = states.Prev() )
|
||||
{
|
||||
call->node.Remove( );
|
||||
call->node.AddToFront( interrupted );
|
||||
}
|
||||
|
||||
// Nothing to insert after anymore
|
||||
insertAfter = NULL;
|
||||
fl.stateInterrupted = true;
|
||||
|
||||
// Post the state now
|
||||
return PostState( name, blendFrames, delay, flags );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::CurrentStateIs
|
||||
=====================
|
||||
*/
|
||||
bool rvStateThread::CurrentStateIs( const char* name ) const
|
||||
{
|
||||
return ( !IsIdle() ) ? name == GetState()->state : false;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::Clear
|
||||
=====================
|
||||
*/
|
||||
void rvStateThread::Clear( bool ignoreStateCalls )
|
||||
{
|
||||
stateCall_t* call;
|
||||
|
||||
// Clear all states from the main state list
|
||||
for( call = states.Next(); call != NULL; call = states.Next() )
|
||||
{
|
||||
if( !ignoreStateCalls && ( call->flags & ( SFLAG_ONCLEAR | SFLAG_ONCLEARONLY ) ) )
|
||||
{
|
||||
//owner->ProcessState ( call->state, call->parms );
|
||||
//owner->SetStateParms(call->parms);
|
||||
owner->Invoke( call->state, &call->parms );
|
||||
}
|
||||
call->node.Remove();
|
||||
delete call;
|
||||
}
|
||||
|
||||
// Clear all interrupted states
|
||||
for( call = interrupted.Next(); call != NULL; call = interrupted.Next() )
|
||||
{
|
||||
if( !ignoreStateCalls && ( call->flags & ( SFLAG_ONCLEAR | SFLAG_ONCLEARONLY ) ) )
|
||||
{
|
||||
//owner->ProcessState ( call->state, call->parms );
|
||||
// owner->SetStateParms(call->parms);
|
||||
owner->Invoke( call->state, &call->parms );
|
||||
}
|
||||
call->node.Remove();
|
||||
delete call;
|
||||
}
|
||||
|
||||
insertAfter = NULL;
|
||||
fl.stateCleared = true;
|
||||
|
||||
states.Clear( );
|
||||
interrupted.Clear( );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::Execute
|
||||
=====================
|
||||
*/
|
||||
stateResult_t rvStateThread::Execute( void )
|
||||
{
|
||||
stateCall_t* call = NULL;
|
||||
int count;
|
||||
const char* stateName;
|
||||
int stateStage;
|
||||
const char* historyState[HISTORY_COUNT];
|
||||
int historyStage[HISTORY_COUNT];
|
||||
int historyStart;
|
||||
int historyEnd;
|
||||
|
||||
// If our main state loop is empty copy over any states in the interrupted state
|
||||
if( !states.Next( ) )
|
||||
{
|
||||
for( call = interrupted.Next(); call; call = interrupted.Next() )
|
||||
{
|
||||
call->node.Remove( );
|
||||
call->node.AddToEnd( states );
|
||||
}
|
||||
assert( !interrupted.Next( ) );
|
||||
}
|
||||
|
||||
// State thread is idle if there are no states
|
||||
if( !states.Next() )
|
||||
{
|
||||
return SRESULT_IDLE;
|
||||
}
|
||||
|
||||
fl.executing = true;
|
||||
|
||||
// Run through the states until there are no more or one of them tells us to wait
|
||||
count = 0;
|
||||
historyStart = 0;
|
||||
historyEnd = 0;
|
||||
|
||||
for( call = states.Next(); call && count < HISTORY_COUNT; call = states.Next(), ++count )
|
||||
{
|
||||
insertAfter = call;
|
||||
fl.stateCleared = false;
|
||||
fl.stateInterrupted = false;
|
||||
|
||||
// If this state is only called when being cleared then just skip it
|
||||
if( call->flags & SFLAG_ONCLEARONLY )
|
||||
{
|
||||
call->node.Remove( );
|
||||
delete call;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the call has a delay on it the time will be set to negative initially and then
|
||||
// converted to game time.
|
||||
if( call->parms.time <= 0 )
|
||||
{
|
||||
call->parms.time = gameLocal.time;
|
||||
}
|
||||
|
||||
// Check for delayed states
|
||||
if( gameLocal.time < call->parms.time + call->delay )
|
||||
{
|
||||
fl.executing = false;
|
||||
return SRESULT_WAIT;
|
||||
}
|
||||
|
||||
// Debugging
|
||||
if( lastResult != SRESULT_WAIT )
|
||||
{
|
||||
// Keep a history of the called states so we can dump them on an overflow
|
||||
historyState[historyEnd] = call->state;
|
||||
historyStage[historyEnd] = call->parms.stage;
|
||||
historyEnd = ( historyEnd + 1 ) % HISTORY_COUNT;
|
||||
if( historyEnd == historyStart )
|
||||
{
|
||||
historyStart = ( historyEnd + 1 ) % HISTORY_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache name and stage for error messages
|
||||
stateName = call->state;
|
||||
stateStage = call->parms.stage;
|
||||
|
||||
if( g_debugState.GetBool() )
|
||||
{
|
||||
if( call->parms.stage )
|
||||
{
|
||||
gameLocal.Printf( "%s: %s (%d)\n", ((idEntity *)owner)->GetClassname(), call->state.c_str(), call->parms.stage );
|
||||
}
|
||||
else
|
||||
{
|
||||
gameLocal.Printf( "%s: %s\n", ((idEntity*)owner)->GetClassname(), call->state.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
// Actually call the state function
|
||||
lastResult = ( stateResult_t )owner->Invoke( call->state, &call->parms );
|
||||
switch( lastResult )
|
||||
{
|
||||
case SRESULT_DONE_FRAME:
|
||||
fl.executing = false;
|
||||
return SRESULT_DONE;
|
||||
case SRESULT_WAIT:
|
||||
fl.executing = false;
|
||||
return SRESULT_WAIT;
|
||||
|
||||
case SRESULT_ERROR:
|
||||
gameLocal.Error( "rvStateThread: error reported by state '%s (%d)'", stateName, stateStage );
|
||||
fl.executing = false;
|
||||
return SRESULT_ERROR;
|
||||
}
|
||||
|
||||
if (lastResult == SRESULT_DONE) {
|
||||
owner->StateThreadChanged();
|
||||
}
|
||||
|
||||
// Dont remove the node if it was interrupted or cleared in the last process
|
||||
if( !fl.stateCleared && !fl.stateInterrupted )
|
||||
{
|
||||
if( lastResult >= SRESULT_SETDELAY )
|
||||
{
|
||||
call->delay = lastResult - SRESULT_SETDELAY;
|
||||
call->parms.time = gameLocal.GetTime();
|
||||
continue;
|
||||
}
|
||||
else if( lastResult >= SRESULT_SETSTAGE )
|
||||
{
|
||||
call->parms.stage = lastResult - SRESULT_SETSTAGE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Done with state so remove it from list
|
||||
call->node.Remove( );
|
||||
delete call;
|
||||
}
|
||||
|
||||
// Finished the last state but wait a frame for next one
|
||||
if( lastResult == SRESULT_DONE_WAIT )
|
||||
{
|
||||
fl.executing = false;
|
||||
return SRESULT_WAIT;
|
||||
}
|
||||
}
|
||||
|
||||
// Runaway state loop?
|
||||
if( count >= HISTORY_COUNT )
|
||||
{
|
||||
idFile* file;
|
||||
|
||||
fileSystem->RemoveFile( "statedump.txt" );
|
||||
file = fileSystem->OpenFileWrite( "statedump.txt" );
|
||||
|
||||
for( ; historyStart != historyEnd; historyStart = ( historyStart + 1 ) % HISTORY_COUNT )
|
||||
{
|
||||
if( historyStage[historyStart] )
|
||||
{
|
||||
gameLocal.Printf( "rvStateThread: %s (%d)\n", historyState[historyStart], historyStage[historyStart] );
|
||||
}
|
||||
else
|
||||
{
|
||||
gameLocal.Printf( "rvStateThread: %s\n", historyState[historyStart] );
|
||||
}
|
||||
if( file )
|
||||
{
|
||||
if( historyStage[historyStart] )
|
||||
{
|
||||
file->Printf( "rvStateThread: %s (%d)\n", historyState[historyStart], historyStage[historyStart] );
|
||||
}
|
||||
else
|
||||
{
|
||||
file->Printf( "rvStateThread: %s\n", historyState[historyStart] );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( file )
|
||||
{
|
||||
fileSystem->CloseFile( file );
|
||||
}
|
||||
|
||||
gameLocal.Error( "rvStateThread: run away state loop '%s'", name.c_str() );
|
||||
}
|
||||
|
||||
insertAfter = NULL;
|
||||
fl.executing = false;
|
||||
|
||||
// Move interrupted states back into the main state list when the main state list is empty
|
||||
if( !states.Next() && interrupted.Next( ) )
|
||||
{
|
||||
return Execute( );
|
||||
}
|
||||
|
||||
return lastResult;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::Save
|
||||
=====================
|
||||
*/
|
||||
void rvStateThread::Save( idSaveGame* saveFile ) const
|
||||
{
|
||||
saveFile->WriteString( name.c_str() );
|
||||
|
||||
// No need to save owner, its setup in restore
|
||||
|
||||
saveFile->WriteInt( lastResult );
|
||||
saveFile->Write( &fl, sizeof( fl ) );
|
||||
|
||||
saveFile->WriteInt( states.Num() );
|
||||
for( idLinkList<stateCall_t>* node = states.NextNode(); node; node = node->NextNode() )
|
||||
{
|
||||
node->Owner()->Save( saveFile );
|
||||
}
|
||||
|
||||
saveFile->WriteInt( interrupted.Num() );
|
||||
for( idLinkList<stateCall_t>* node = interrupted.NextNode(); node; node = node->NextNode() )
|
||||
{
|
||||
node->Owner()->Save( saveFile );
|
||||
}
|
||||
|
||||
// TOSAVE: stateCall_t* insertAfter;
|
||||
// TOSAVE: stateResult_t lastResult;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvStateThread::Restore
|
||||
=====================
|
||||
*/
|
||||
void rvStateThread::Restore( idRestoreGame* saveFile, idClass* owner )
|
||||
{
|
||||
int numStates;
|
||||
stateCall_t* call = NULL;
|
||||
|
||||
saveFile->ReadString( name );
|
||||
|
||||
this->owner = owner;
|
||||
|
||||
saveFile->ReadInt( ( int& )lastResult );
|
||||
saveFile->Read( &fl, sizeof( fl ) );
|
||||
|
||||
saveFile->ReadInt( numStates );
|
||||
for( ; numStates > 0; numStates-- )
|
||||
{
|
||||
call = new stateCall_t;
|
||||
assert( call );
|
||||
|
||||
call->Restore( saveFile, owner );
|
||||
|
||||
call->node.SetOwner( call );
|
||||
call->node.AddToEnd( states );
|
||||
}
|
||||
|
||||
saveFile->ReadInt( numStates );
|
||||
for( ; numStates > 0; numStates-- )
|
||||
{
|
||||
call = new stateCall_t;
|
||||
assert( call );
|
||||
|
||||
call->Restore( saveFile, owner );
|
||||
|
||||
call->node.SetOwner( call );
|
||||
call->node.AddToEnd( interrupted );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user