//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
# include "cbase.h"
# include "networkstringtable_clientdll.h"
# include "dt_utlvector_recv.h"
# include "choreoevent.h"
# include "choreoactor.h"
# include "choreochannel.h"
# include "filesystem.h"
# include "ichoreoeventcallback.h"
# include "scenefilecache/ISceneFileCache.h"
# include "materialsystem/imaterialsystemhardwareconfig.h"
# include "tier2/tier2.h"
# include "hud_closecaption.h"
# include "tier0/icommandline.h"
# include "c_sceneentity.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Decodes animtime and notes when it changes
// Input : *pStruct - ( C_BaseEntity * ) used to flag animtime is changine
// *pVarData -
// *pIn -
// objectID -
//-----------------------------------------------------------------------------
void RecvProxy_ForcedClientTime ( const CRecvProxyData * pData , void * pStruct , void * pOut )
{
C_SceneEntity * pScene = reinterpret_cast < C_SceneEntity * > ( pStruct ) ;
* ( float * ) pOut = pData - > m_Value . m_Float ;
pScene - > OnResetClientTime ( ) ;
}
# if defined( CSceneEntity )
# undef CSceneEntity
# endif
IMPLEMENT_CLIENTCLASS_DT ( C_SceneEntity , DT_SceneEntity , CSceneEntity )
RecvPropInt ( RECVINFO ( m_nSceneStringIndex ) ) ,
RecvPropBool ( RECVINFO ( m_bIsPlayingBack ) ) ,
RecvPropBool ( RECVINFO ( m_bPaused ) ) ,
RecvPropBool ( RECVINFO ( m_bMultiplayer ) ) ,
RecvPropFloat ( RECVINFO ( m_flForceClientTime ) , 0 , RecvProxy_ForcedClientTime ) ,
RecvPropUtlVector (
RECVINFO_UTLVECTOR ( m_hActorList ) ,
MAX_ACTORS_IN_SCENE ,
RecvPropEHandle ( NULL , 0 , 0 ) ) ,
END_RECV_TABLE ( )
C_SceneEntity : : C_SceneEntity ( void )
{
m_pScene = NULL ;
m_bMultiplayer = false ;
m_hOwner = NULL ;
m_bClientOnly = false ;
}
C_SceneEntity : : ~ C_SceneEntity ( void )
{
UnloadScene ( ) ;
}
void C_SceneEntity : : OnResetClientTime ( )
{
// In TF2 we ignore this as the scene is played entirely client-side.
# ifndef TF_CLIENT_DLL
m_flCurrentTime = m_flForceClientTime ;
# endif
}
char const * C_SceneEntity : : GetSceneFileName ( )
{
return g_pStringTableClientSideChoreoScenes - > GetString ( m_nSceneStringIndex ) ;
}
ConVar mp_usehwmvcds ( " mp_usehwmvcds " , " 0 " , NULL , " Enable the use of the hw morph vcd(s) . ( - 1 = never , 1 = always , 0 = based upon GPU ) " ) ; // -1 = never, 0 = if hasfastvertextextures, 1 = always
bool UseHWMorphVCDs ( )
{
// if ( mp_usehwmvcds.GetInt() == 0 )
// return g_pMaterialSystemHardwareConfig->HasFastVertexTextures();
// return mp_usehwmvcds.GetInt() > 0;
return false ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_SceneEntity : : GetHWMorphSceneFileName ( const char * pFilename , char * pHWMFilename )
{
// Are we even using hardware morph?
if ( ! UseHWMorphVCDs ( ) )
return false ;
// Multi-player only!
if ( ! m_bMultiplayer )
return false ;
// Do we have a valid filename?
if ( ! ( pFilename & & pFilename [ 0 ] ) )
return false ;
// Check to see if we already have an player/hwm/* filename.
if ( ( V_strstr ( pFilename , " /high " ) ! = NULL ) | | ( V_strstr ( pFilename , " \\ high " ) ! = NULL ) )
{
V_strcpy ( pHWMFilename , pFilename ) ;
return true ;
}
// Find the hardware morph scene name and pass that along as well.
char szScene [ MAX_PATH ] ;
V_strcpy ( szScene , pFilename ) ;
char szSceneHWM [ MAX_PATH ] ;
szSceneHWM [ 0 ] = ' \0 ' ;
char * pszToken = strtok ( szScene , " / \\ " ) ;
while ( pszToken ! = NULL )
{
if ( ! V_stricmp ( pszToken , " low " ) )
{
V_strcat ( szSceneHWM , " high " , sizeof ( szSceneHWM ) ) ;
}
else
{
V_strcat ( szSceneHWM , pszToken , sizeof ( szSceneHWM ) ) ;
}
pszToken = strtok ( NULL , " / \\ " ) ;
if ( pszToken ! = NULL )
{
V_strcat ( szSceneHWM , " \\ " , sizeof ( szSceneHWM ) ) ;
}
}
V_strcpy ( pHWMFilename , szSceneHWM ) ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_SceneEntity : : ResetActorFlexesForScene ( )
{
int nActorCount = m_pScene - > GetNumActors ( ) ;
for ( int iActor = 0 ; iActor < nActorCount ; + + iActor )
{
CChoreoActor * pChoreoActor = m_pScene - > GetActor ( iActor ) ;
if ( ! pChoreoActor )
continue ;
C_BaseFlex * pFlexActor = FindNamedActor ( pChoreoActor ) ;
if ( ! pFlexActor )
continue ;
CStudioHdr * pStudioHdr = pFlexActor - > GetModelPtr ( ) ;
if ( ! pStudioHdr )
continue ;
if ( pStudioHdr - > numflexdesc ( ) = = 0 )
continue ;
// Reset the flex weights to their starting position.
LocalFlexController_t iController ;
for ( iController = LocalFlexController_t ( 0 ) ; iController < pStudioHdr - > numflexcontrollers ( ) ; + + iController )
{
pFlexActor - > SetFlexWeight ( iController , 0.0f ) ;
}
// Reset the prediction interpolation values.
pFlexActor - > m_iv_flexWeight . Reset ( ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_SceneEntity : : StopClientOnlyScene ( )
{
if ( m_pScene )
{
m_pScene - > ResetSimulation ( ) ;
if ( m_hOwner . Get ( ) )
{
m_hOwner - > RemoveChoreoScene ( m_pScene ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_SceneEntity : : SetupClientOnlyScene ( const char * pszFilename , C_BaseFlex * pOwner /* = NULL */ , bool bMultiplayer /* = false */ )
{
m_bIsPlayingBack = true ;
m_bMultiplayer = bMultiplayer ;
m_hOwner = pOwner ;
m_bClientOnly = true ;
char szFilename [ 128 ] ;
Assert ( V_strlen ( pszFilename ) < 128 ) ;
V_strcpy ( szFilename , pszFilename ) ;
char szSceneHWM [ 128 ] ;
if ( GetHWMorphSceneFileName ( szFilename , szSceneHWM ) )
{
V_strcpy ( szFilename , szSceneHWM ) ;
}
Assert ( szFilename & & szFilename [ 0 ] ) ;
if ( szFilename & & szFilename [ 0 ] )
{
LoadSceneFromFile ( szFilename ) ;
if ( ! CommandLine ( ) - > FindParm ( " -hushasserts " ) )
{
Assert ( m_pScene ) ;
}
// Should handle gestures and sequences client side.
if ( m_bMultiplayer )
{
if ( m_pScene )
{
int types [ 6 ] ;
types [ 0 ] = CChoreoEvent : : FLEXANIMATION ;
types [ 1 ] = CChoreoEvent : : EXPRESSION ;
types [ 2 ] = CChoreoEvent : : GESTURE ;
types [ 3 ] = CChoreoEvent : : SEQUENCE ;
types [ 4 ] = CChoreoEvent : : SPEAK ;
types [ 5 ] = CChoreoEvent : : LOOP ;
m_pScene - > RemoveEventsExceptTypes ( types , 6 ) ;
}
PrefetchAnimBlocks ( m_pScene ) ;
}
else
{
if ( m_pScene )
{
int types [ 2 ] ;
types [ 0 ] = CChoreoEvent : : FLEXANIMATION ;
types [ 1 ] = CChoreoEvent : : EXPRESSION ;
m_pScene - > RemoveEventsExceptTypes ( types , 2 ) ;
}
}
SetNextClientThink ( CLIENT_THINK_ALWAYS ) ;
}
if ( m_hOwner . Get ( ) )
{
if ( ! CommandLine ( ) - > FindParm ( " -hushasserts " ) )
{
Assert ( m_pScene ) ;
}
if ( m_pScene )
{
ClearSceneEvents ( m_pScene , false ) ;
if ( m_bIsPlayingBack )
{
m_pScene - > ResetSimulation ( ) ;
m_hOwner - > StartChoreoScene ( m_pScene ) ;
}
else
{
m_pScene - > ResetSimulation ( ) ;
m_hOwner - > RemoveChoreoScene ( m_pScene ) ;
}
// Reset the flex weights when we start a new scene. This is normally done on the player model, but since
// we don't have a player here yet - we need to do this!
ResetActorFlexesForScene ( ) ;
}
}
else
{
for ( int i = 0 ; i < m_hActorList . Count ( ) ; + + i )
{
C_BaseFlex * actor = m_hActorList [ i ] . Get ( ) ;
if ( ! actor )
continue ;
Assert ( m_pScene ) ;
if ( m_pScene )
{
ClearSceneEvents ( m_pScene , false ) ;
if ( m_bIsPlayingBack )
{
m_pScene - > ResetSimulation ( ) ;
actor - > StartChoreoScene ( m_pScene ) ;
}
else
{
m_pScene - > ResetSimulation ( ) ;
actor - > RemoveChoreoScene ( m_pScene ) ;
}
}
}
}
}
void C_SceneEntity : : PostDataUpdate ( DataUpdateType_t updateType )
{
BaseClass : : PostDataUpdate ( updateType ) ;
char const * str = GetSceneFileName ( ) ;
char szFilename [ MAX_PATH ] ;
if ( str )
{
Assert ( V_strlen ( str ) < MAX_PATH ) ;
V_strcpy ( szFilename , str ) ;
}
else
{
szFilename [ 0 ] = ' \0 ' ;
}
char szSceneHWM [ MAX_PATH ] ;
if ( GetHWMorphSceneFileName ( szFilename , szSceneHWM ) )
{
V_strcpy ( szFilename , szSceneHWM ) ;
}
if ( updateType = = DATA_UPDATE_CREATED )
{
Assert ( szFilename & & szFilename [ 0 ] ) ;
if ( szFilename & & szFilename [ 0 ] )
{
LoadSceneFromFile ( szFilename ) ;
// Kill everything except flex events
Assert ( m_pScene ) ;
// Should handle gestures and sequences clientside.
if ( m_bMultiplayer )
{
if ( m_pScene )
{
int types [ 6 ] ;
types [ 0 ] = CChoreoEvent : : FLEXANIMATION ;
types [ 1 ] = CChoreoEvent : : EXPRESSION ;
types [ 2 ] = CChoreoEvent : : GESTURE ;
types [ 3 ] = CChoreoEvent : : SEQUENCE ;
types [ 4 ] = CChoreoEvent : : SPEAK ;
types [ 5 ] = CChoreoEvent : : LOOP ;
m_pScene - > RemoveEventsExceptTypes ( types , 6 ) ;
}
PrefetchAnimBlocks ( m_pScene ) ;
}
else
{
if ( m_pScene )
{
int types [ 2 ] ;
types [ 0 ] = CChoreoEvent : : FLEXANIMATION ;
types [ 1 ] = CChoreoEvent : : EXPRESSION ;
m_pScene - > RemoveEventsExceptTypes ( types , 2 ) ;
}
}
SetNextClientThink ( CLIENT_THINK_ALWAYS ) ;
}
}
// Playback state changed...
if ( m_bWasPlaying ! = m_bIsPlayingBack )
{
for ( int i = 0 ; i < m_hActorList . Count ( ) ; + + i )
{
C_BaseFlex * actor = m_hActorList [ i ] . Get ( ) ;
if ( ! actor )
continue ;
Assert ( m_pScene ) ;
if ( m_pScene )
{
ClearSceneEvents ( m_pScene , false ) ;
if ( m_bIsPlayingBack )
{
m_pScene - > ResetSimulation ( ) ;
actor - > StartChoreoScene ( m_pScene ) ;
}
else
{
m_pScene - > ResetSimulation ( ) ;
actor - > RemoveChoreoScene ( m_pScene ) ;
}
}
}
}
}
void C_SceneEntity : : PreDataUpdate ( DataUpdateType_t updateType )
{
BaseClass : : PreDataUpdate ( updateType ) ;
m_bWasPlaying = m_bIsPlayingBack ;
}
//-----------------------------------------------------------------------------
// Purpose: Called every frame that an event is active (Start/EndEvent as also
// called)
// Input : *event -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
void C_SceneEntity : : ProcessEvent ( float currenttime , CChoreoScene * scene , CChoreoEvent * event )
{
// For now we only need to process events if we go back in time.
if ( currenttime < event - > m_flPrevTime )
{
//if ( !V_strstr( scene->GetFilename(), "idleloop" ) )
//{
// Msg( "ProcessEvent( %6.4f, %32s %6.4f ) %6.4f\n", currenttime, event->GetName(), event->m_flPrevTime, m_flCurrentTime );
//}
C_BaseFlex * pActor = NULL ;
CChoreoActor * actor = event - > GetActor ( ) ;
if ( actor )
{
pActor = FindNamedActor ( actor ) ;
if ( NULL = = pActor )
{
// TODO: QueueProcessEvent
// This can occur if we haven't been networked an actor yet... we need to queue it so that we can
// fire off the process event as soon as we have the actor resident on the client.
return ;
}
}
switch ( event - > GetType ( ) )
{
case CChoreoEvent : : GESTURE :
{
// Verify data.
Assert ( m_bMultiplayer ) ;
Assert ( scene ! = NULL ) ;
Assert ( event ! = NULL ) ;
if ( pActor )
{
DispatchProcessGesture ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : SEQUENCE :
{
// Verify data.
Assert ( m_bMultiplayer ) ;
Assert ( scene ! = NULL ) ;
Assert ( event ! = NULL ) ;
if ( pActor )
{
DispatchProcessSequence ( scene , pActor , event ) ;
}
}
break ;
}
}
event - > m_flPrevTime = currenttime ;
}
//-----------------------------------------------------------------------------
// Purpose: Called for events that are part of a pause condition
// Input : *event -
// Output : Returns true on event completed, false on non-completion.
//-----------------------------------------------------------------------------
bool C_SceneEntity : : CheckEvent ( float currenttime , CChoreoScene * scene , CChoreoEvent * event )
{
return true ;
}
C_BaseFlex * C_SceneEntity : : FindNamedActor ( CChoreoActor * pChoreoActor )
{
if ( ! m_pScene )
return NULL ;
if ( m_hOwner . Get ( ) ! = NULL )
{
return m_hOwner . Get ( ) ;
}
int idx = m_pScene - > FindActorIndex ( pChoreoActor ) ;
if ( idx < 0 | | idx > = m_hActorList . Count ( ) )
return NULL ;
return m_hActorList [ idx ] . Get ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: All events are leading edge triggered
// Input : currenttime -
// *event -
//-----------------------------------------------------------------------------
void C_SceneEntity : : StartEvent ( float currenttime , CChoreoScene * scene , CChoreoEvent * event )
{
Assert ( event ) ;
if ( ! Q_stricmp ( event - > GetName ( ) , " NULL " ) )
{
Scene_Printf ( " %s : %8.2f: ignored %s \n " , GetSceneFileName ( ) , currenttime , event - > GetDescription ( ) ) ;
return ;
}
C_BaseFlex * pActor = NULL ;
CChoreoActor * actor = event - > GetActor ( ) ;
if ( actor )
{
pActor = FindNamedActor ( actor ) ;
if ( NULL = = pActor )
{
// This can occur if we haven't been networked an actor yet... we need to queue it so that we can
// fire off the start event as soon as we have the actor resident on the client.
QueueStartEvent ( currenttime , scene , event ) ;
return ;
}
}
Scene_Printf ( " %s : %8.2f: start %s \n " , GetSceneFileName ( ) , currenttime , event - > GetDescription ( ) ) ;
switch ( event - > GetType ( ) )
{
case CChoreoEvent : : FLEXANIMATION :
{
if ( pActor )
{
DispatchStartFlexAnimation ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : EXPRESSION :
{
if ( pActor )
{
DispatchStartExpression ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : GESTURE :
{
// Verify data.
Assert ( m_bMultiplayer ) ;
Assert ( scene ! = NULL ) ;
Assert ( event ! = NULL ) ;
if ( pActor )
{
DispatchStartGesture ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : SEQUENCE :
{
// Verify data.
Assert ( m_bMultiplayer ) ;
Assert ( scene ! = NULL ) ;
Assert ( event ! = NULL ) ;
if ( pActor )
{
DispatchStartSequence ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : LOOP :
{
// Verify data.
Assert ( m_bMultiplayer ) ;
Assert ( scene ! = NULL ) ;
Assert ( event ! = NULL ) ;
DispatchProcessLoop ( scene , event ) ;
}
case CChoreoEvent : : SPEAK :
{
if ( IsClientOnly ( ) & & pActor )
{
// FIXME: dB hack. soundlevel needs to be moved into inside of wav?
soundlevel_t iSoundlevel = SNDLVL_TALKING ;
if ( event - > GetParameters2 ( ) )
{
iSoundlevel = ( soundlevel_t ) atoi ( event - > GetParameters2 ( ) ) ;
if ( iSoundlevel = = SNDLVL_NONE )
{
iSoundlevel = SNDLVL_TALKING ;
}
}
DispatchStartSpeak ( scene , pActor , event , iSoundlevel ) ;
}
}
break ;
default :
break ;
}
event - > m_flPrevTime = currenttime ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *scene -
// *event -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchProcessLoop ( CChoreoScene * scene , CChoreoEvent * event )
{
Assert ( event - > GetType ( ) = = CChoreoEvent : : LOOP ) ;
float backtime = ( float ) atof ( event - > GetParameters ( ) ) ;
bool process = true ;
int counter = event - > GetLoopCount ( ) ;
if ( counter ! = - 1 )
{
int remaining = event - > GetNumLoopsRemaining ( ) ;
if ( remaining < = 0 )
{
process = false ;
}
else
{
event - > SetNumLoopsRemaining ( - - remaining ) ;
}
}
if ( ! process )
return ;
scene - > LoopToTime ( backtime ) ;
SetCurrentTime ( backtime , true ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Playback sound file that contains phonemes
// Input : *actor -
// *parameters -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchStartSpeak ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event , soundlevel_t iSoundlevel )
{
// Emit sound
if ( IsClientOnly ( ) & & actor )
{
CSingleUserRecipientFilter filter ( C_BasePlayer : : GetLocalPlayer ( ) ) ;
float time_in_past = m_flCurrentTime - event - > GetStartTime ( ) ;
float soundtime = gpGlobals - > curtime - time_in_past ;
EmitSound_t es ;
es . m_nChannel = CHAN_VOICE ;
es . m_flVolume = 1 ;
es . m_SoundLevel = iSoundlevel ;
es . m_flSoundTime = soundtime ;
// No CC since we do it manually
// FIXME: This will change
es . m_bEmitCloseCaption = false ;
es . m_pSoundName = event - > GetParameters ( ) ;
EmitSound ( filter , actor - > entindex ( ) , es ) ;
actor - > AddSceneEvent ( scene , event , NULL , IsClientOnly ( ) ) ;
// Close captioning only on master token no matter what...
if ( event - > GetCloseCaptionType ( ) = = CChoreoEvent : : CC_MASTER )
{
char tok [ CChoreoEvent : : MAX_CCTOKEN_STRING ] ;
bool validtoken = event - > GetPlaybackCloseCaptionToken ( tok , sizeof ( tok ) ) ;
if ( validtoken )
{
CRC32_t tokenCRC ;
CRC32_Init ( & tokenCRC ) ;
char lowercase [ 256 ] ;
Q_strncpy ( lowercase , tok , sizeof ( lowercase ) ) ;
Q_strlower ( lowercase ) ;
CRC32_ProcessBuffer ( & tokenCRC , lowercase , Q_strlen ( lowercase ) ) ;
CRC32_Final ( & tokenCRC ) ;
float endtime = event - > GetLastSlaveEndTime ( ) ;
float durationShort = event - > GetDuration ( ) ;
float durationLong = endtime - event - > GetStartTime ( ) ;
float duration = MAX ( durationShort , durationLong ) ;
CHudCloseCaption * hudCloseCaption = GET_HUDELEMENT ( CHudCloseCaption ) ;
if ( hudCloseCaption )
{
hudCloseCaption - > ProcessCaption ( lowercase , duration ) ;
}
}
}
}
}
void C_SceneEntity : : DispatchEndSpeak ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event )
{
if ( IsClientOnly ( ) )
{
actor - > RemoveSceneEvent ( scene , event , false ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : currenttime -
// *event -
//-----------------------------------------------------------------------------
void C_SceneEntity : : EndEvent ( float currenttime , CChoreoScene * scene , CChoreoEvent * event )
{
Assert ( event ) ;
if ( ! Q_stricmp ( event - > GetName ( ) , " NULL " ) )
{
return ;
}
C_BaseFlex * pActor = NULL ;
CChoreoActor * actor = event - > GetActor ( ) ;
if ( actor )
{
pActor = FindNamedActor ( actor ) ;
}
Scene_Printf ( " %s : %8.2f: finish %s \n " , GetSceneFileName ( ) , currenttime , event - > GetDescription ( ) ) ;
switch ( event - > GetType ( ) )
{
case CChoreoEvent : : FLEXANIMATION :
{
if ( pActor )
{
DispatchEndFlexAnimation ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : EXPRESSION :
{
if ( pActor )
{
DispatchEndExpression ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : GESTURE :
{
if ( pActor )
{
DispatchEndGesture ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : SEQUENCE :
{
if ( pActor )
{
DispatchEndSequence ( scene , pActor , event ) ;
}
}
break ;
case CChoreoEvent : : SPEAK :
{
if ( IsClientOnly ( ) & & pActor )
{
DispatchEndSpeak ( scene , pActor , event ) ;
}
}
break ;
default :
break ;
}
}
bool CChoreoStringPool : : GetString ( short stringId , char * buff , int buffSize )
{
// fetch from compiled pool
const char * pString = scenefilecache - > GetSceneString ( stringId ) ;
if ( ! pString )
{
V_strncpy ( buff , " " , buffSize ) ;
return false ;
}
V_strncpy ( buff , pString , buffSize ) ;
return true ;
}
CChoreoStringPool g_ChoreoStringPool ;
CChoreoScene * C_SceneEntity : : LoadScene ( const char * filename )
{
char loadfile [ 512 ] ;
Q_strncpy ( loadfile , filename , sizeof ( loadfile ) ) ;
Q_SetExtension ( loadfile , " .vcd " , sizeof ( loadfile ) ) ;
Q_FixSlashes ( loadfile ) ;
char * pBuffer = NULL ;
size_t bufsize = scenefilecache - > GetSceneBufferSize ( loadfile ) ;
if ( bufsize < = 0 )
return NULL ;
pBuffer = new char [ bufsize ] ;
if ( ! scenefilecache - > GetSceneData ( filename , ( byte * ) pBuffer , bufsize ) )
{
delete [ ] pBuffer ;
return NULL ;
}
CChoreoScene * pScene ;
if ( IsBufferBinaryVCD ( pBuffer , bufsize ) )
{
pScene = new CChoreoScene ( this ) ;
CUtlBuffer buf ( pBuffer , bufsize , CUtlBuffer : : READ_ONLY ) ;
if ( ! pScene - > RestoreFromBinaryBuffer ( buf , loadfile , & g_ChoreoStringPool ) )
{
Warning ( " Unable to restore binary scene '%s' \n " , loadfile ) ;
delete pScene ;
pScene = NULL ;
}
else
{
pScene - > SetPrintFunc ( Scene_Printf ) ;
pScene - > SetEventCallbackInterface ( this ) ;
}
}
else
{
g_TokenProcessor . SetBuffer ( pBuffer ) ;
pScene = ChoreoLoadScene ( loadfile , this , & g_TokenProcessor , Scene_Printf ) ;
}
delete [ ] pBuffer ;
return pScene ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *filename -
//-----------------------------------------------------------------------------
void C_SceneEntity : : LoadSceneFromFile ( const char * filename )
{
UnloadScene ( ) ;
m_pScene = LoadScene ( filename ) ;
}
void C_SceneEntity : : ClearSceneEvents ( CChoreoScene * scene , bool canceled )
{
if ( ! m_pScene )
return ;
Scene_Printf ( " %s : %8.2f: clearing events \n " , GetSceneFileName ( ) , m_flCurrentTime ) ;
int i ;
for ( i = 0 ; i < m_pScene - > GetNumActors ( ) ; i + + )
{
C_BaseFlex * pActor = FindNamedActor ( m_pScene - > GetActor ( i ) ) ;
if ( ! pActor )
continue ;
// Clear any existing expressions
pActor - > ClearSceneEvents ( scene , canceled ) ;
}
WipeQueuedEvents ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_SceneEntity : : UnloadScene ( void )
{
WipeQueuedEvents ( ) ;
if ( m_pScene )
{
ClearSceneEvents ( m_pScene , false ) ;
for ( int i = 0 ; i < m_pScene - > GetNumActors ( ) ; i + + )
{
C_BaseFlex * pTestActor = FindNamedActor ( m_pScene - > GetActor ( i ) ) ;
if ( ! pTestActor )
continue ;
pTestActor - > RemoveChoreoScene ( m_pScene ) ;
}
}
delete m_pScene ;
m_pScene = NULL ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
// *event -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchStartFlexAnimation ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event )
{
actor - > AddSceneEvent ( scene , event , NULL , IsClientOnly ( ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
// *event -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchEndFlexAnimation ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event )
{
actor - > RemoveSceneEvent ( scene , event , false ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
// *event -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchStartExpression ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event )
{
actor - > AddSceneEvent ( scene , event , NULL , IsClientOnly ( ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
// *event -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchEndExpression ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event )
{
actor - > RemoveSceneEvent ( scene , event , false ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
// *parameters -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchStartGesture ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event )
{
// Ingore null gestures
if ( ! Q_stricmp ( event - > GetName ( ) , " NULL " ) )
return ;
actor - > AddSceneEvent ( scene , event , NULL , IsClientOnly ( ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
// *parameters -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchProcessGesture ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event )
{
// Ingore null gestures
if ( ! Q_stricmp ( event - > GetName ( ) , " NULL " ) )
return ;
actor - > RemoveSceneEvent ( scene , event , false ) ;
actor - > AddSceneEvent ( scene , event , NULL , IsClientOnly ( ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
// *parameters -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchEndGesture ( CChoreoScene * scene , C_BaseFlex * actor , CChoreoEvent * event )
{
// Ingore null gestures
if ( ! Q_stricmp ( event - > GetName ( ) , " NULL " ) )
return ;
actor - > RemoveSceneEvent ( scene , event , false ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchStartSequence ( CChoreoScene * scene , CBaseFlex * actor , CChoreoEvent * event )
{
actor - > AddSceneEvent ( scene , event , NULL , IsClientOnly ( ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchProcessSequence ( CChoreoScene * scene , CBaseFlex * actor , CChoreoEvent * event )
{
actor - > RemoveSceneEvent ( scene , event , false ) ;
actor - > AddSceneEvent ( scene , event , NULL , IsClientOnly ( ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *actor -
//-----------------------------------------------------------------------------
void C_SceneEntity : : DispatchEndSequence ( CChoreoScene * scene , CBaseFlex * actor , CChoreoEvent * event )
{
actor - > RemoveSceneEvent ( scene , event , false ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_SceneEntity : : DoThink ( float frametime )
{
if ( ! m_pScene )
return ;
if ( ! m_bIsPlayingBack )
{
WipeQueuedEvents ( ) ;
return ;
}
CheckQueuedEvents ( ) ;
if ( m_bPaused )
{
return ;
}
// Msg( "CL: %d, %f for %s\n", gpGlobals->tickcount, m_flCurrentTime, m_pScene->GetFilename() );
// Tell scene to go
m_pScene - > Think ( m_flCurrentTime ) ;
// Drive simulation time for scene
m_flCurrentTime + = gpGlobals - > frametime ;
}
void C_SceneEntity : : ClientThink ( )
{
DoThink ( gpGlobals - > frametime ) ;
}
void C_SceneEntity : : CheckQueuedEvents ( )
{
// Check for duplicates
CUtlVector < QueuedEvents_t > events ;
events = m_QueuedEvents ;
m_QueuedEvents . RemoveAll ( ) ;
int c = events . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
const QueuedEvents_t & check = events [ i ] ;
// Retry starting this event
StartEvent ( check . starttime , check . scene , check . event ) ;
}
}
void C_SceneEntity : : WipeQueuedEvents ( )
{
m_QueuedEvents . Purge ( ) ;
}
void C_SceneEntity : : QueueStartEvent ( float starttime , CChoreoScene * scene , CChoreoEvent * event )
{
// Check for duplicates
int c = m_QueuedEvents . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
const QueuedEvents_t & check = m_QueuedEvents [ i ] ;
if ( check . scene = = scene & &
check . event = = event )
return ;
}
QueuedEvents_t qe ;
qe . scene = scene ;
qe . event = event ;
qe . starttime = starttime ;
m_QueuedEvents . AddToTail ( qe ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Resets time such that the client version of the .vcd is also updated, if appropriate
// Input : t -
// forceClientSync - unused for now, we may want to reenable this at some point
//-----------------------------------------------------------------------------
void C_SceneEntity : : SetCurrentTime ( float t , bool forceClientSync )
{
m_flCurrentTime = t ;
m_flForceClientTime = t ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_SceneEntity : : PrefetchAnimBlocks ( CChoreoScene * pScene )
{
if ( ! CommandLine ( ) - > FindParm ( " -hushasserts " ) )
{
Assert ( pScene & & m_bMultiplayer ) ;
}
if ( ! pScene | | ! m_bMultiplayer )
return ;
// Build a fast lookup, too
CUtlMap < CChoreoActor * , CBaseFlex * > actorMap ( 0 , 0 , DefLessFunc ( CChoreoActor * ) ) ;
int nSpew = 0 ;
int nResident = 0 ;
int nChecked = 0 ;
// Iterate events and precache necessary resources
for ( int i = 0 ; i < pScene - > GetNumEvents ( ) ; i + + )
{
CChoreoEvent * pEvent = pScene - > GetEvent ( i ) ;
if ( ! pEvent )
continue ;
// load any necessary data
switch ( pEvent - > GetType ( ) )
{
default :
break ;
case CChoreoEvent : : SEQUENCE :
case CChoreoEvent : : GESTURE :
{
CChoreoActor * pActor = pEvent - > GetActor ( ) ;
if ( pActor )
{
CBaseFlex * pFlex = NULL ;
int idx = actorMap . Find ( pActor ) ;
if ( idx = = actorMap . InvalidIndex ( ) )
{
pFlex = FindNamedActor ( pActor ) ;
idx = actorMap . Insert ( pActor , pFlex ) ;
}
else
{
pFlex = actorMap [ idx ] ;
}
if ( pFlex )
{
int iSequence = pFlex - > LookupSequence ( pEvent - > GetParameters ( ) ) ;
if ( iSequence > = 0 )
{
CStudioHdr * pStudioHdr = pFlex - > GetModelPtr ( ) ;
if ( pStudioHdr )
{
// Now look up the animblock
mstudioseqdesc_t & seqdesc = pStudioHdr - > pSeqdesc ( iSequence ) ;
for ( int i = 0 ; i < seqdesc . groupsize [ 0 ] ; + + i )
{
for ( int j = 0 ; j < seqdesc . groupsize [ 1 ] ; + + j )
{
int iAnimation = seqdesc . anim ( i , j ) ;
int iBaseAnimation = pStudioHdr - > iRelativeAnim ( iSequence , iAnimation ) ;
mstudioanimdesc_t & animdesc = pStudioHdr - > pAnimdesc ( iBaseAnimation ) ;
+ + nChecked ;
if ( nSpew ! = 0 )
{
Msg ( " %s checking block %d \n " , pStudioHdr - > pszName ( ) , animdesc . animblock ) ;
}
// Async load the animation
int iFrame = 0 ;
const mstudioanim_t * panim = animdesc . pAnim ( & iFrame ) ;
if ( panim )
{
+ + nResident ;
if ( nSpew > 1 )
{
Msg ( " %s:%s[%i:%i] was resident \n " , pStudioHdr - > pszName ( ) , animdesc . pszName ( ) , i , j ) ;
}
}
else
{
if ( nSpew ! = 0 )
{
Msg ( " %s:%s[%i:%i] async load \n " , pStudioHdr - > pszName ( ) , animdesc . pszName ( ) , i , j ) ;
}
}
}
}
}
}
}
}
break ;
}
}
}
if ( ! nSpew | | nChecked < = 0 )
return ;
Msg ( " %d of %d animations resident \n " , nResident , nChecked ) ;
}