aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/c_sceneentity.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/c_sceneentity.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/c_sceneentity.cpp')
-rw-r--r--mp/src/game/client/c_sceneentity.cpp2420
1 files changed, 1210 insertions, 1210 deletions
diff --git a/mp/src/game/client/c_sceneentity.cpp b/mp/src/game/client/c_sceneentity.cpp
index d56a67c8..b44b59fd 100644
--- a/mp/src/game/client/c_sceneentity.cpp
+++ b/mp/src/game/client/c_sceneentity.cpp
@@ -1,1211 +1,1211 @@
-//========= 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 );
+//========= 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 );
} \ No newline at end of file