Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1173 lines
30 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "networkstringtable_clientdll.h"
  9. #include "dt_utlvector_recv.h"
  10. #include "choreoevent.h"
  11. #include "choreoactor.h"
  12. #include "choreochannel.h"
  13. #include "choreoscene.h"
  14. #include "filesystem.h"
  15. #include "ichoreoeventcallback.h"
  16. #include "scenefilecache/ISceneFileCache.h"
  17. #include "materialsystem/imaterialsystemhardwareconfig.h"
  18. #include "tier2/tier2.h"
  19. #include "hud_closecaption.h"
  20. #include "tier1/fmtstr.h"
  21. #include "../../common/blackbox_helper.h"
  22. #include "c_sceneentity.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. //-----------------------------------------------------------------------------
  26. // Purpose: Decodes animtime and notes when it changes
  27. // Input : *pStruct - ( C_BaseEntity * ) used to flag animtime is changine
  28. // *pVarData -
  29. // *pIn -
  30. // objectID -
  31. //-----------------------------------------------------------------------------
  32. void RecvProxy_ForcedClientTime( const CRecvProxyData *pData, void *pStruct, void *pOut )
  33. {
  34. C_SceneEntity *pScene = reinterpret_cast< C_SceneEntity * >( pStruct );
  35. *(float *)pOut = pData->m_Value.m_Float;
  36. pScene->OnResetClientTime();
  37. }
  38. #if defined( CSceneEntity )
  39. #undef CSceneEntity
  40. #endif
  41. IMPLEMENT_CLIENTCLASS_DT(C_SceneEntity, DT_SceneEntity, CSceneEntity)
  42. RecvPropInt(RECVINFO(m_nSceneStringIndex)),
  43. RecvPropBool(RECVINFO(m_bIsPlayingBack)),
  44. RecvPropBool(RECVINFO(m_bPaused)),
  45. RecvPropBool(RECVINFO(m_bMultiplayer)),
  46. RecvPropFloat(RECVINFO(m_flForceClientTime), 0, RecvProxy_ForcedClientTime ),
  47. RecvPropUtlVector(
  48. RECVINFO_UTLVECTOR( m_hActorList ),
  49. MAX_ACTORS_IN_SCENE,
  50. RecvPropEHandle(NULL, 0, 0)),
  51. END_RECV_TABLE()
  52. C_SceneEntity::C_SceneEntity( void )
  53. {
  54. m_pScene = NULL;
  55. m_bMultiplayer = false;
  56. m_hOwner = NULL;
  57. m_bClientOnly = false;
  58. }
  59. C_SceneEntity::~C_SceneEntity( void )
  60. {
  61. UnloadScene();
  62. }
  63. void C_SceneEntity::OnResetClientTime()
  64. {
  65. m_flCurrentTime = m_flForceClientTime;
  66. }
  67. char const *C_SceneEntity::GetSceneFileName()
  68. {
  69. char const *pStr = g_pStringTableClientSideChoreoScenes->GetString( m_nSceneStringIndex );
  70. if ( pStr )
  71. return pStr;
  72. static bool bFirst = true;
  73. if ( bFirst )
  74. {
  75. bFirst = false;
  76. Assert( 0 );
  77. Warning( "GetSceneFilename() failed for scene index %d\n", m_nSceneStringIndex );
  78. }
  79. return "";
  80. }
  81. 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
  82. ConVar scene_vcdautosave( "scene_vcdautosave", "0", 0, "Create a savegame before VCD playback" );
  83. bool UseHWMorphVCDs()
  84. {
  85. if ( mp_usehwmvcds.GetInt() == 0 )
  86. return g_pMaterialSystemHardwareConfig->HasFastVertexTextures();
  87. return mp_usehwmvcds.GetInt() > 0;
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Purpose:
  91. //-----------------------------------------------------------------------------
  92. bool C_SceneEntity::GetHWMorphSceneFileName( const char *pFilename, char *pHWMFilename )
  93. {
  94. // Are we even using hardware morph?
  95. if ( !UseHWMorphVCDs() )
  96. return false;
  97. // Multi-player only!
  98. if ( !m_bMultiplayer )
  99. return false;
  100. // Do we have a valid filename?
  101. if ( !( pFilename && pFilename[0] ) )
  102. return false;
  103. // Check to see if we already have an player/hwm/* filename.
  104. if ( ( V_strstr( pFilename, "/high" ) != NULL ) || ( V_strstr( pFilename, "\\high" ) != NULL ) )
  105. {
  106. V_strcpy( pHWMFilename, pFilename );
  107. return true;
  108. }
  109. // Find the hardware morph scene name and pass that along as well.
  110. char szScene[MAX_PATH];
  111. V_strcpy( szScene, pFilename );
  112. char szSceneHWM[MAX_PATH];
  113. szSceneHWM[0] = '\0';
  114. char *pszToken = strtok( szScene, "/\\" );
  115. while ( pszToken != NULL )
  116. {
  117. if ( !V_stricmp( pszToken, "low" ) )
  118. {
  119. V_strcat( szSceneHWM, "high", sizeof( szSceneHWM ) );
  120. }
  121. else
  122. {
  123. V_strcat( szSceneHWM, pszToken, sizeof( szSceneHWM ) );
  124. }
  125. pszToken = strtok( NULL, "/\\" );
  126. if ( pszToken != NULL )
  127. {
  128. V_strcat( szSceneHWM, "\\", sizeof( szSceneHWM ) );
  129. }
  130. }
  131. V_strcpy( pHWMFilename, szSceneHWM );
  132. return true;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose:
  136. //-----------------------------------------------------------------------------
  137. void C_SceneEntity::ResetActorFlexesForScene()
  138. {
  139. int nActorCount = m_pScene->GetNumActors();
  140. for( int iActor = 0; iActor < nActorCount; ++iActor )
  141. {
  142. CChoreoActor *pChoreoActor = m_pScene->GetActor( iActor );
  143. if ( !pChoreoActor )
  144. continue;
  145. C_BaseFlex *pFlexActor = FindNamedActor( pChoreoActor );
  146. if ( !pFlexActor )
  147. continue;
  148. CStudioHdr *pStudioHdr = pFlexActor->GetModelPtr();
  149. if ( !pStudioHdr )
  150. continue;
  151. if ( pStudioHdr->numflexdesc() == 0 )
  152. continue;
  153. // Reset the flex weights to their starting position.
  154. LocalFlexController_t iController;
  155. for ( iController = LocalFlexController_t(0); iController < pStudioHdr->numflexcontrollers(); ++iController )
  156. {
  157. pFlexActor->SetFlexWeight( iController, 0.0f );
  158. }
  159. // Reset the prediction interpolation values.
  160. pFlexActor->m_iv_flexWeight.Reset( gpGlobals->curtime );
  161. }
  162. }
  163. //-----------------------------------------------------------------------------
  164. // Purpose:
  165. //-----------------------------------------------------------------------------
  166. void C_SceneEntity::StopClientOnlyScene()
  167. {
  168. if ( m_pScene )
  169. {
  170. m_pScene->ResetSimulation();
  171. if ( m_hOwner.Get() )
  172. {
  173. m_hOwner->RemoveChoreoScene( m_pScene );
  174. }
  175. }
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose:
  179. //-----------------------------------------------------------------------------
  180. void C_SceneEntity::SetupClientOnlyScene( const char *pszFilename, C_BaseFlex *pOwner /* = NULL */, bool bMultiplayer /* = false */ )
  181. {
  182. m_bIsPlayingBack = true;
  183. m_bMultiplayer = bMultiplayer;
  184. m_hOwner = pOwner;
  185. m_bClientOnly = true;
  186. char szFilename[128];
  187. Assert( V_strlen( pszFilename ) < 128 );
  188. V_strcpy( szFilename, pszFilename );
  189. char szSceneHWM[128];
  190. if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) )
  191. {
  192. V_strcpy( szFilename, szSceneHWM );
  193. }
  194. Assert( szFilename && szFilename[ 0 ] );
  195. if ( szFilename && szFilename[ 0 ] )
  196. {
  197. LoadSceneFromFile( szFilename );
  198. Assert( m_pScene );
  199. // Should handle gestures and sequences client side.
  200. if ( m_bMultiplayer )
  201. {
  202. if ( m_pScene )
  203. {
  204. int types[6];
  205. types[0] = CChoreoEvent::FLEXANIMATION;
  206. types[1] = CChoreoEvent::EXPRESSION;
  207. types[2] = CChoreoEvent::GESTURE;
  208. types[3] = CChoreoEvent::SEQUENCE;
  209. types[4] = CChoreoEvent::SPEAK;
  210. types[5] = CChoreoEvent::LOOP;
  211. m_pScene->RemoveEventsExceptTypes( types, 6 );
  212. }
  213. PrefetchAnimBlocks( m_pScene );
  214. }
  215. else
  216. {
  217. if ( m_pScene )
  218. {
  219. int types[ 2 ];
  220. types[ 0 ] = CChoreoEvent::FLEXANIMATION;
  221. types[ 1 ] = CChoreoEvent::EXPRESSION;
  222. m_pScene->RemoveEventsExceptTypes( types, 2 );
  223. }
  224. }
  225. SetNextClientThink( CLIENT_THINK_ALWAYS );
  226. }
  227. if ( m_hOwner.Get() )
  228. {
  229. Assert( m_pScene );
  230. if ( m_pScene )
  231. {
  232. ClearSceneEvents( m_pScene, false );
  233. if ( m_bIsPlayingBack )
  234. {
  235. m_pScene->ResetSimulation();
  236. m_hOwner->StartChoreoScene( m_pScene );
  237. }
  238. else
  239. {
  240. m_pScene->ResetSimulation();
  241. m_hOwner->RemoveChoreoScene( m_pScene );
  242. }
  243. // Reset the flex weights when we start a new scene. This is normally done on the player model, but since
  244. // we don't have a player here yet - we need to do this!
  245. ResetActorFlexesForScene();
  246. }
  247. }
  248. else
  249. {
  250. for( int i = 0; i < m_hActorList.Count() ; ++i )
  251. {
  252. C_BaseFlex *actor = m_hActorList[ i ].Get();
  253. if ( !actor )
  254. continue;
  255. Assert( m_pScene );
  256. if ( m_pScene )
  257. {
  258. ClearSceneEvents( m_pScene, false );
  259. if ( m_bIsPlayingBack )
  260. {
  261. m_pScene->ResetSimulation();
  262. actor->StartChoreoScene( m_pScene );
  263. }
  264. else
  265. {
  266. m_pScene->ResetSimulation();
  267. actor->RemoveChoreoScene( m_pScene );
  268. }
  269. }
  270. }
  271. }
  272. }
  273. void C_SceneEntity::PostDataUpdate( DataUpdateType_t updateType )
  274. {
  275. BaseClass::PostDataUpdate( updateType );
  276. char const *str = GetSceneFileName();
  277. char szFilename[MAX_PATH];
  278. Assert( V_strlen( str ) < MAX_PATH );
  279. V_strcpy( szFilename, str );
  280. char szSceneHWM[MAX_PATH];
  281. if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) )
  282. {
  283. V_strcpy( szFilename, szSceneHWM );
  284. }
  285. if ( updateType == DATA_UPDATE_CREATED )
  286. {
  287. Assert( szFilename && szFilename[ 0 ] );
  288. if ( szFilename && szFilename[ 0 ] )
  289. {
  290. LoadSceneFromFile( szFilename );
  291. // Kill everything except flex events
  292. Assert( m_pScene );
  293. // Should handle gestures and sequences clientside.
  294. if ( m_bMultiplayer )
  295. {
  296. if ( m_pScene )
  297. {
  298. int types[6];
  299. types[0] = CChoreoEvent::FLEXANIMATION;
  300. types[1] = CChoreoEvent::EXPRESSION;
  301. types[2] = CChoreoEvent::GESTURE;
  302. types[3] = CChoreoEvent::SEQUENCE;
  303. types[4] = CChoreoEvent::SPEAK;
  304. types[5] = CChoreoEvent::LOOP;
  305. m_pScene->RemoveEventsExceptTypes( types, 6 );
  306. }
  307. PrefetchAnimBlocks( m_pScene );
  308. }
  309. else
  310. {
  311. if ( m_pScene )
  312. {
  313. int types[ 2 ];
  314. types[ 0 ] = CChoreoEvent::FLEXANIMATION;
  315. types[ 1 ] = CChoreoEvent::EXPRESSION;
  316. m_pScene->RemoveEventsExceptTypes( types, 2 );
  317. }
  318. }
  319. SetNextClientThink( CLIENT_THINK_ALWAYS );
  320. }
  321. }
  322. // Playback state changed...
  323. if ( m_bWasPlaying != m_bIsPlayingBack )
  324. {
  325. for(int i = 0; i < m_hActorList.Count() ; ++i )
  326. {
  327. C_BaseFlex *actor = m_hActorList[ i ].Get();
  328. if ( !actor )
  329. continue;
  330. Assert( m_pScene );
  331. if ( m_pScene )
  332. {
  333. ClearSceneEvents( m_pScene, false );
  334. if ( m_bIsPlayingBack )
  335. {
  336. m_pScene->ResetSimulation();
  337. actor->StartChoreoScene( m_pScene );
  338. }
  339. else
  340. {
  341. m_pScene->ResetSimulation();
  342. actor->RemoveChoreoScene( m_pScene );
  343. }
  344. }
  345. }
  346. }
  347. }
  348. void C_SceneEntity::PreDataUpdate( DataUpdateType_t updateType )
  349. {
  350. BaseClass::PreDataUpdate( updateType );
  351. m_bWasPlaying = m_bIsPlayingBack;
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose: Called every frame that an event is active (Start/EndEvent as also
  355. // called)
  356. // Input : *event -
  357. // Output : Returns true on success, false on failure.
  358. //-----------------------------------------------------------------------------
  359. void C_SceneEntity::ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  360. {
  361. return;
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose: Called for events that are part of a pause condition
  365. // Input : *event -
  366. // Output : Returns true on event completed, false on non-completion.
  367. //-----------------------------------------------------------------------------
  368. bool C_SceneEntity::CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  369. {
  370. return true;
  371. }
  372. C_BaseFlex *C_SceneEntity::FindNamedActor( CChoreoActor *pChoreoActor )
  373. {
  374. if ( !m_pScene )
  375. return NULL;
  376. if ( m_hOwner.Get() != NULL )
  377. {
  378. return m_hOwner.Get();
  379. }
  380. int idx = m_pScene->FindActorIndex( pChoreoActor );
  381. if ( idx < 0 || idx >= m_hActorList.Count() )
  382. return NULL;
  383. return m_hActorList[ idx ].Get();
  384. }
  385. //-----------------------------------------------------------------------------
  386. // Purpose: All events are leading edge triggered
  387. // Input : currenttime -
  388. // *event -
  389. //-----------------------------------------------------------------------------
  390. void C_SceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  391. {
  392. Assert( event );
  393. if ( !Q_stricmp( event->GetName(), "NULL" ) )
  394. {
  395. Scene_Printf( "%s : %8.2f: ignored %s\n", GetSceneFileName(), currenttime, event->GetDescription() );
  396. return;
  397. }
  398. C_BaseFlex *pActor = NULL;
  399. CChoreoActor *actor = event->GetActor();
  400. if ( actor )
  401. {
  402. pActor = FindNamedActor( actor );
  403. if ( NULL == pActor )
  404. {
  405. // This can occur if we haven't been networked an actor yet... we need to queue it so that we can
  406. // fire off the start event as soon as we have the actor resident on the client.
  407. QueueStartEvent( currenttime, scene, event );
  408. return;
  409. }
  410. }
  411. Scene_Printf( "%s : %8.2f: start %s\n", GetSceneFileName(), currenttime, event->GetDescription() );
  412. if ( IsPC() && event )
  413. {
  414. BlackBox_Record( "vcd", "%s : %8.2f: start %s", GetSceneFileName(), currenttime, event->GetDescription() );
  415. }
  416. switch ( event->GetType() )
  417. {
  418. case CChoreoEvent::FLEXANIMATION:
  419. {
  420. if ( pActor )
  421. {
  422. DispatchStartFlexAnimation( scene, pActor, event );
  423. }
  424. }
  425. break;
  426. case CChoreoEvent::EXPRESSION:
  427. {
  428. if ( pActor )
  429. {
  430. DispatchStartExpression( scene, pActor, event );
  431. }
  432. }
  433. break;
  434. case CChoreoEvent::GESTURE:
  435. {
  436. // Verify data.
  437. Assert( m_bMultiplayer );
  438. Assert( scene != NULL );
  439. Assert( event != NULL );
  440. if ( pActor )
  441. {
  442. DispatchStartGesture( scene, pActor, event );
  443. }
  444. }
  445. break;
  446. case CChoreoEvent::SEQUENCE:
  447. {
  448. // Verify data.
  449. Assert( m_bMultiplayer );
  450. Assert( scene != NULL );
  451. Assert( event != NULL );
  452. if ( pActor )
  453. {
  454. DispatchStartSequence( scene, pActor, event );
  455. }
  456. }
  457. break;
  458. case CChoreoEvent::LOOP:
  459. {
  460. // Verify data.
  461. Assert( m_bMultiplayer );
  462. Assert( scene != NULL );
  463. Assert( event != NULL );
  464. DispatchProcessLoop( scene, event );
  465. }
  466. case CChoreoEvent::SPEAK:
  467. {
  468. if ( IsClientOnly() && pActor )
  469. {
  470. // FIXME: dB hack. soundlevel needs to be moved into inside of wav?
  471. soundlevel_t iSoundlevel = SNDLVL_TALKING;
  472. if ( event->GetParameters2() )
  473. {
  474. iSoundlevel = (soundlevel_t)atoi( event->GetParameters2() );
  475. if ( iSoundlevel == SNDLVL_NONE )
  476. {
  477. iSoundlevel = SNDLVL_TALKING;
  478. }
  479. }
  480. DispatchStartSpeak( scene, pActor, event, iSoundlevel );
  481. }
  482. }
  483. break;
  484. default:
  485. break;
  486. }
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Purpose:
  490. // Input : *scene -
  491. // *event -
  492. //-----------------------------------------------------------------------------
  493. void C_SceneEntity::DispatchProcessLoop( CChoreoScene *scene, CChoreoEvent *event )
  494. {
  495. Assert( event->GetType() == CChoreoEvent::LOOP );
  496. float backtime = (float)atof( event->GetParameters() );
  497. bool process = true;
  498. int counter = event->GetLoopCount();
  499. if ( counter != -1 )
  500. {
  501. int remaining = event->GetNumLoopsRemaining();
  502. if ( remaining <= 0 )
  503. {
  504. process = false;
  505. }
  506. else
  507. {
  508. event->SetNumLoopsRemaining( --remaining );
  509. }
  510. }
  511. if ( !process )
  512. return;
  513. scene->LoopToTime( backtime );
  514. SetCurrentTime( backtime, true );
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Purpose: Playback sound file that contains phonemes
  518. // Input : *actor -
  519. // *parameters -
  520. //-----------------------------------------------------------------------------
  521. void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event, soundlevel_t iSoundlevel )
  522. {
  523. // Emit sound
  524. if ( IsClientOnly() && actor )
  525. {
  526. CSingleUserRecipientFilter filter( C_BasePlayer::GetLocalPlayer() );
  527. float time_in_past = m_flCurrentTime - event->GetStartTime() ;
  528. float soundtime = gpGlobals->curtime - time_in_past;
  529. EmitSound_t es;
  530. es.m_nChannel = CHAN_VOICE;
  531. es.m_flVolume = 1;
  532. es.m_SoundLevel = iSoundlevel;
  533. es.m_flSoundTime = soundtime;
  534. // No CC since we do it manually
  535. // FIXME: This will change
  536. es.m_bEmitCloseCaption = false;
  537. es.m_pSoundName = event->GetParameters();
  538. EmitSound( filter, actor->entindex(), es );
  539. actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this );
  540. // Close captioning only on master token no matter what...
  541. if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
  542. {
  543. char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  544. bool validtoken = event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) );
  545. if ( validtoken )
  546. {
  547. CRC32_t tokenCRC;
  548. CRC32_Init( &tokenCRC );
  549. char lowercase[ 256 ];
  550. Q_strncpy( lowercase, tok, sizeof( lowercase ) );
  551. Q_strlower( lowercase );
  552. CRC32_ProcessBuffer( &tokenCRC, lowercase, Q_strlen( lowercase ) );
  553. CRC32_Final( &tokenCRC );
  554. float endtime = event->GetLastSlaveEndTime();
  555. float durationShort = event->GetDuration();
  556. float durationLong = endtime - event->GetStartTime();
  557. float duration = MAX( durationShort, durationLong );
  558. CHudCloseCaption *hudCloseCaption = GET_FULLSCREEN_HUDELEMENT( CHudCloseCaption );
  559. if ( hudCloseCaption )
  560. {
  561. hudCloseCaption->ProcessCaption( lowercase, duration );
  562. }
  563. }
  564. }
  565. }
  566. }
  567. void C_SceneEntity::DispatchEndSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
  568. {
  569. if ( IsClientOnly() )
  570. {
  571. actor->RemoveSceneEvent( scene, event, false );
  572. }
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Purpose:
  576. // Input : currenttime -
  577. // *event -
  578. //-----------------------------------------------------------------------------
  579. void C_SceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  580. {
  581. Assert( event );
  582. if ( !Q_stricmp( event->GetName(), "NULL" ) )
  583. {
  584. return;
  585. }
  586. C_BaseFlex *pActor = NULL;
  587. CChoreoActor *actor = event->GetActor();
  588. if ( actor )
  589. {
  590. pActor = FindNamedActor( actor );
  591. }
  592. Scene_Printf( "%s : %8.2f: finish %s\n", GetSceneFileName(), currenttime, event->GetDescription() );
  593. switch ( event->GetType() )
  594. {
  595. case CChoreoEvent::FLEXANIMATION:
  596. {
  597. if ( pActor )
  598. {
  599. DispatchEndFlexAnimation( scene, pActor, event );
  600. }
  601. }
  602. break;
  603. case CChoreoEvent::EXPRESSION:
  604. {
  605. if ( pActor )
  606. {
  607. DispatchEndExpression( scene, pActor, event );
  608. }
  609. }
  610. break;
  611. case CChoreoEvent::GESTURE:
  612. {
  613. if ( pActor )
  614. {
  615. DispatchEndGesture( scene, pActor, event );
  616. }
  617. }
  618. break;
  619. case CChoreoEvent::SEQUENCE:
  620. {
  621. if ( pActor )
  622. {
  623. DispatchEndSequence( scene, pActor, event );
  624. }
  625. }
  626. break;
  627. case CChoreoEvent::SPEAK:
  628. {
  629. if ( IsClientOnly() && pActor )
  630. {
  631. DispatchEndSpeak( scene, pActor, event );
  632. }
  633. }
  634. break;
  635. default:
  636. break;
  637. }
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Binary compiled VCDs get their strings from a pool
  641. //-----------------------------------------------------------------------------
  642. class CChoreoStringPool : public IChoreoStringPool
  643. {
  644. public:
  645. short FindOrAddString( const char *pString )
  646. {
  647. // huh?, no compilation at run time, only fetches
  648. Assert( 0 );
  649. return -1;
  650. }
  651. bool GetString( short stringId, char *buff, int buffSize )
  652. {
  653. // fetch from compiled pool
  654. const char *pString = scenefilecache->GetSceneString( stringId );
  655. if ( !pString )
  656. {
  657. V_strncpy( buff, "", buffSize );
  658. return false;
  659. }
  660. V_strncpy( buff, pString, buffSize );
  661. return true;
  662. }
  663. };
  664. CChoreoStringPool g_ChoreoStringPool;
  665. CChoreoScene *C_SceneEntity::LoadScene( const char *filename )
  666. {
  667. char loadfile[ 512 ];
  668. Q_strncpy( loadfile, filename, sizeof( loadfile ) );
  669. Q_SetExtension( loadfile, ".vcd", sizeof( loadfile ) );
  670. Q_FixSlashes( loadfile );
  671. char *pBuffer = NULL;
  672. size_t bufsize = scenefilecache->GetSceneBufferSize( loadfile );
  673. if ( bufsize <= 0 )
  674. return NULL;
  675. pBuffer = new char[ bufsize ];
  676. if ( !scenefilecache->GetSceneData( filename, (byte *)pBuffer, bufsize ) )
  677. {
  678. delete[] pBuffer;
  679. return NULL;
  680. }
  681. CChoreoScene *pScene;
  682. if ( IsBufferBinaryVCD( pBuffer, bufsize ) )
  683. {
  684. pScene = new CChoreoScene( this );
  685. CUtlBuffer buf( pBuffer, bufsize, CUtlBuffer::READ_ONLY );
  686. if ( !pScene->RestoreFromBinaryBuffer( buf, loadfile, &g_ChoreoStringPool ) )
  687. {
  688. Warning( "Unable to restore binary scene '%s'\n", loadfile );
  689. delete pScene;
  690. pScene = NULL;
  691. }
  692. else
  693. {
  694. pScene->SetPrintFunc( Scene_Printf );
  695. pScene->SetEventCallbackInterface( this );
  696. }
  697. }
  698. else
  699. {
  700. g_TokenProcessor.SetBuffer( pBuffer );
  701. pScene = ChoreoLoadScene( loadfile, this, &g_TokenProcessor, Scene_Printf );
  702. }
  703. delete[] pBuffer;
  704. return pScene;
  705. }
  706. //-----------------------------------------------------------------------------
  707. // Purpose:
  708. // Input : *filename -
  709. //-----------------------------------------------------------------------------
  710. void C_SceneEntity::LoadSceneFromFile( const char *filename )
  711. {
  712. // Save game if convar is set - useful when iterating on a scene with Foundry
  713. if ( scene_vcdautosave.GetBool() )
  714. {
  715. char szVCDFileName[64];
  716. char szSaveFileName[64];
  717. char szClientCmd[128];
  718. // Create the faceposer sub-directory under the root savegame directory
  719. if (!g_pFullFileSystem->IsDirectory( "SAVE\\faceposer", "MOD" ))
  720. {
  721. g_pFullFileSystem->CreateDirHierarchy( "SAVE\\faceposer", "MOD" );
  722. }
  723. // Construct save command to send to the engine
  724. V_FileBase( filename, szVCDFileName, sizeof(szVCDFileName) );
  725. V_snprintf( szClientCmd, sizeof(szClientCmd), "save faceposer\\%s\n", szVCDFileName );
  726. // Construct name of file that would be created if savegame occurs
  727. V_snprintf( szSaveFileName, sizeof(szSaveFileName), "SAVE\\faceposer\\%s.sav", szVCDFileName );
  728. // Only create a savegame for this VCD if there isn't one already
  729. if (!g_pFullFileSystem->FileExists( szSaveFileName, "MOD" ))
  730. {
  731. engine->ClientCmd( szClientCmd );
  732. }
  733. }
  734. UnloadScene();
  735. m_pScene = LoadScene( filename );
  736. }
  737. void C_SceneEntity::ClearSceneEvents( CChoreoScene *scene, bool canceled )
  738. {
  739. if ( !m_pScene )
  740. return;
  741. Scene_Printf( "%s : %8.2f: clearing events\n", GetSceneFileName(), m_flCurrentTime );
  742. int i;
  743. for ( i = 0 ; i < m_pScene->GetNumActors(); i++ )
  744. {
  745. C_BaseFlex *pActor = FindNamedActor( m_pScene->GetActor( i ) );
  746. if ( !pActor )
  747. continue;
  748. // Clear any existing expressions
  749. pActor->ClearSceneEvents( scene, canceled );
  750. }
  751. WipeQueuedEvents();
  752. OnResetClientTime();
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Purpose:
  756. //-----------------------------------------------------------------------------
  757. void C_SceneEntity::UnloadScene( void )
  758. {
  759. WipeQueuedEvents();
  760. if ( m_pScene )
  761. {
  762. ClearSceneEvents( m_pScene, false );
  763. for ( int i = 0 ; i < m_pScene->GetNumActors(); i++ )
  764. {
  765. C_BaseFlex *pTestActor = FindNamedActor( m_pScene->GetActor( i ) );
  766. if ( !pTestActor )
  767. continue;
  768. pTestActor->RemoveChoreoScene( m_pScene );
  769. }
  770. }
  771. delete m_pScene;
  772. m_pScene = NULL;
  773. }
  774. //-----------------------------------------------------------------------------
  775. // Purpose:
  776. // Input : *actor -
  777. // *event -
  778. //-----------------------------------------------------------------------------
  779. void C_SceneEntity::DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
  780. {
  781. actor->AddSceneEvent( scene, event, NULL, IsClientOnly() || IsMultiplayer(), this );
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Purpose:
  785. // Input : *actor -
  786. // *event -
  787. //-----------------------------------------------------------------------------
  788. void C_SceneEntity::DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
  789. {
  790. actor->RemoveSceneEvent( scene, event, false );
  791. }
  792. //-----------------------------------------------------------------------------
  793. // Purpose:
  794. // Input : *actor -
  795. // *event -
  796. //-----------------------------------------------------------------------------
  797. void C_SceneEntity::DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
  798. {
  799. actor->AddSceneEvent( scene, event, NULL, IsClientOnly() || IsMultiplayer(), this );
  800. }
  801. //-----------------------------------------------------------------------------
  802. // Purpose:
  803. // Input : *actor -
  804. // *event -
  805. //-----------------------------------------------------------------------------
  806. void C_SceneEntity::DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
  807. {
  808. actor->RemoveSceneEvent( scene, event, false );
  809. }
  810. //-----------------------------------------------------------------------------
  811. // Purpose:
  812. // Input : *actor -
  813. // *parameters -
  814. //-----------------------------------------------------------------------------
  815. void C_SceneEntity::DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
  816. {
  817. // Ingore null gestures
  818. if ( !Q_stricmp( event->GetName(), "NULL" ) )
  819. return;
  820. actor->AddSceneEvent( scene, event, NULL, IsClientOnly() || IsMultiplayer(), this );
  821. }
  822. //-----------------------------------------------------------------------------
  823. // Purpose:
  824. // Input : *actor -
  825. //-----------------------------------------------------------------------------
  826. void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
  827. {
  828. actor->AddSceneEvent( scene, event, NULL, IsClientOnly() || IsMultiplayer(), this );
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Purpose:
  832. // Input : *actor -
  833. //-----------------------------------------------------------------------------
  834. void C_SceneEntity::DispatchEndSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event )
  835. {
  836. actor->RemoveSceneEvent( scene, event, false );
  837. }
  838. //-----------------------------------------------------------------------------
  839. // Purpose:
  840. // Input : *actor -
  841. // *parameters -
  842. //-----------------------------------------------------------------------------
  843. void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event )
  844. {
  845. // Ingore null gestures
  846. if ( !Q_stricmp( event->GetName(), "NULL" ) )
  847. return;
  848. actor->RemoveSceneEvent( scene, event, false );
  849. }
  850. //-----------------------------------------------------------------------------
  851. // Purpose:
  852. //-----------------------------------------------------------------------------
  853. void C_SceneEntity::DoThink( float frametime )
  854. {
  855. if ( !m_pScene )
  856. return;
  857. if ( !m_bIsPlayingBack )
  858. {
  859. WipeQueuedEvents();
  860. return;
  861. }
  862. CheckQueuedEvents();
  863. if ( m_bPaused )
  864. {
  865. return;
  866. }
  867. // Msg( "CL: %d, %f for %s\n", gpGlobals->tickcount, m_flCurrentTime, m_pScene->GetFilename() );
  868. // Tell scene to go
  869. m_pScene->Think( m_flCurrentTime );
  870. // Drive simulation time for scene
  871. m_flCurrentTime += gpGlobals->frametime;
  872. }
  873. void C_SceneEntity::ClientThink()
  874. {
  875. DoThink( gpGlobals->frametime );
  876. }
  877. void C_SceneEntity::CheckQueuedEvents()
  878. {
  879. // Check for duplicates
  880. CUtlVector< QueuedEvents_t > events;
  881. events = m_QueuedEvents;
  882. m_QueuedEvents.RemoveAll();
  883. int c = events.Count();
  884. for ( int i = 0; i < c; ++i )
  885. {
  886. const QueuedEvents_t& check = events[ i ];
  887. // Retry starting this event
  888. StartEvent( check.starttime, check.scene, check.event );
  889. }
  890. }
  891. void C_SceneEntity::WipeQueuedEvents()
  892. {
  893. m_QueuedEvents.Purge();
  894. }
  895. void C_SceneEntity::QueueStartEvent( float starttime, CChoreoScene *scene, CChoreoEvent *event )
  896. {
  897. // Check for duplicates
  898. int c = m_QueuedEvents.Count();
  899. for ( int i = 0; i < c; ++i )
  900. {
  901. const QueuedEvents_t& check = m_QueuedEvents[ i ];
  902. if ( check.scene == scene &&
  903. check.event == event )
  904. return;
  905. }
  906. QueuedEvents_t qe;
  907. qe.scene = scene;
  908. qe.event = event;
  909. qe.starttime = starttime;
  910. m_QueuedEvents.AddToTail( qe );
  911. }
  912. //-----------------------------------------------------------------------------
  913. // Purpose: Resets time such that the client version of the .vcd is also updated, if appropriate
  914. // Input : t -
  915. // forceClientSync - unused for now, we may want to reenable this at some point
  916. //-----------------------------------------------------------------------------
  917. void C_SceneEntity::SetCurrentTime( float t, bool forceClientSync )
  918. {
  919. m_flCurrentTime = t;
  920. m_flForceClientTime = t;
  921. }
  922. //-----------------------------------------------------------------------------
  923. // Purpose:
  924. //-----------------------------------------------------------------------------
  925. void C_SceneEntity::PrefetchAnimBlocks( CChoreoScene *pScene )
  926. {
  927. Assert( pScene && m_bMultiplayer );
  928. if ( !pScene || !m_bMultiplayer )
  929. return;
  930. // Build a fast lookup, too
  931. CUtlMap<CChoreoActor*,CBaseFlex*> actorMap( 0, 0, DefLessFunc( CChoreoActor* ) );
  932. int nSpew = 0;
  933. int nResident = 0;
  934. int nChecked = 0;
  935. // Iterate events and precache necessary resources
  936. for ( int i = 0; i < pScene->GetNumEvents(); i++ )
  937. {
  938. CChoreoEvent *pEvent = pScene->GetEvent( i );
  939. if ( !pEvent )
  940. continue;
  941. // load any necessary data
  942. switch ( pEvent->GetType() )
  943. {
  944. default:
  945. break;
  946. case CChoreoEvent::SEQUENCE:
  947. case CChoreoEvent::GESTURE:
  948. {
  949. CChoreoActor *pActor = pEvent->GetActor();
  950. if ( pActor )
  951. {
  952. CBaseFlex *pFlex = NULL;
  953. int idx = actorMap.Find( pActor );
  954. if ( idx == actorMap.InvalidIndex() )
  955. {
  956. pFlex = FindNamedActor( pActor );
  957. idx = actorMap.Insert( pActor, pFlex );
  958. }
  959. else
  960. {
  961. pFlex = actorMap[ idx ];
  962. }
  963. if ( pFlex )
  964. {
  965. int iSequence = pFlex->LookupSequence( pEvent->GetParameters() );
  966. if ( iSequence >= 0 )
  967. {
  968. CStudioHdr *pStudioHdr = pFlex->GetModelPtr();
  969. if ( pStudioHdr )
  970. {
  971. // Now look up the animblock
  972. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( iSequence );
  973. for ( int i = 0 ; i < seqdesc.groupsize[ 0 ] ; ++i )
  974. {
  975. for ( int j = 0; j < seqdesc.groupsize[ 1 ]; ++j )
  976. {
  977. int iAnimation = seqdesc.anim( i, j );
  978. int iBaseAnimation = pStudioHdr->iRelativeAnim( iSequence, iAnimation );
  979. mstudioanimdesc_t &animdesc = pStudioHdr->pAnimdesc( iBaseAnimation );
  980. ++nChecked;
  981. if ( nSpew != 0 )
  982. {
  983. Msg( "%s checking block %d\n", pStudioHdr->pszName(), animdesc.animblock );
  984. }
  985. // Async load the animation
  986. int iFrame = 0;
  987. const byte *panim = animdesc.pAnim( &iFrame );
  988. if ( panim )
  989. {
  990. ++nResident;
  991. if ( nSpew > 1 )
  992. {
  993. Msg( "%s:%s[%i:%i] was resident\n", pStudioHdr->pszName(), animdesc.pszName(), i, j );
  994. }
  995. }
  996. else
  997. {
  998. if ( nSpew != 0 )
  999. {
  1000. Msg( "%s:%s[%i:%i] async load\n", pStudioHdr->pszName(), animdesc.pszName(), i, j );
  1001. }
  1002. }
  1003. }
  1004. }
  1005. }
  1006. }
  1007. }
  1008. }
  1009. break;
  1010. }
  1011. }
  1012. }
  1013. if ( !nSpew || nChecked <= 0 )
  1014. return;
  1015. Msg( "%d of %d animations resident\n", nResident, nChecked );
  1016. }