Team Fortress 2 Source Code as on 22/4/2020
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.

268 lines
8.1 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A camera entity that's used by the -makedevshots system to take
  4. // dev screenshots everytime the map is checked into source control.
  5. //
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "tier0/icommandline.h"
  10. #include "igamesystem.h"
  11. #include "filesystem.h"
  12. #include <KeyValues.h>
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. int g_iDevShotCameraCount = 0;
  16. #define DEVSHOT_INITIAL_WAIT 5 // Time after the level spawn before the first devshot camera takes it's shot
  17. #define DEVSHOT_INTERVAL 5 // Time between each devshot camera taking it's shot
  18. //-----------------------------------------------------------------------------
  19. // Purpose: A camera entity that's used by the -makedevshots system to take
  20. // dev screenshots everytime the map is checked into source control.
  21. //-----------------------------------------------------------------------------
  22. class CPointDevShotCamera : public CBaseEntity
  23. {
  24. DECLARE_CLASS( CPointDevShotCamera, CBaseEntity );
  25. public:
  26. DECLARE_DATADESC();
  27. void Spawn( void );
  28. void DevShotThink_Setup( void );
  29. void DevShotThink_TakeShot( void );
  30. void DevShotThink_PostShot( void );
  31. // Always transmit to clients so they know where to move the view to
  32. virtual int UpdateTransmitState();
  33. private:
  34. string_t m_iszCameraName;
  35. int m_iFOV;
  36. };
  37. BEGIN_DATADESC( CPointDevShotCamera )
  38. DEFINE_FUNCTION( DevShotThink_Setup ),
  39. DEFINE_FUNCTION( DevShotThink_TakeShot ),
  40. DEFINE_FUNCTION( DevShotThink_PostShot ),
  41. DEFINE_KEYFIELD( m_iszCameraName, FIELD_STRING, "cameraname" ),
  42. DEFINE_KEYFIELD( m_iFOV, FIELD_INTEGER, "FOV" ),
  43. END_DATADESC()
  44. LINK_ENTITY_TO_CLASS( point_devshot_camera, CPointDevShotCamera );
  45. //-----------------------------------------------------------------------------
  46. // Purpose: Convenience function so we don't have to make this check all over
  47. //-----------------------------------------------------------------------------
  48. static CBasePlayer * UTIL_GetLocalPlayerOrListenServerHost( void )
  49. {
  50. if ( gpGlobals->maxClients > 1 )
  51. {
  52. if ( engine->IsDedicatedServer() )
  53. {
  54. return NULL;
  55. }
  56. return UTIL_GetListenServerHost();
  57. }
  58. return UTIL_GetLocalPlayer();
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose:
  62. //-----------------------------------------------------------------------------
  63. void CPointDevShotCamera::Spawn( void )
  64. {
  65. BaseClass::Spawn();
  66. // Remove this entity immediately if we're not making devshots
  67. if ( !CommandLine()->FindParm("-makedevshots") )
  68. {
  69. UTIL_Remove( this );
  70. return;
  71. }
  72. // Take a screenshot when it's my turn
  73. SetThink( &CPointDevShotCamera::DevShotThink_Setup );
  74. SetNextThink( gpGlobals->curtime + DEVSHOT_INITIAL_WAIT + (g_iDevShotCameraCount * DEVSHOT_INTERVAL) );
  75. g_iDevShotCameraCount++;
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Purpose:
  79. //-----------------------------------------------------------------------------
  80. int CPointDevShotCamera::UpdateTransmitState()
  81. {
  82. // always transmit if currently used by a monitor
  83. return SetTransmitState( FL_EDICT_ALWAYS );
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void CPointDevShotCamera::DevShotThink_Setup( void )
  89. {
  90. // Move the player to the devshot camera
  91. CBasePlayer *pPlayer = UTIL_GetLocalPlayerOrListenServerHost();
  92. if ( !pPlayer )
  93. return;
  94. // Hide stuff
  95. engine->ClientCommand( pPlayer->edict(), "developer 0" );
  96. engine->ClientCommand( pPlayer->edict(), "cl_drawhud 0" );
  97. engine->ClientCommand( pPlayer->edict(), "sv_cheats 1" );
  98. engine->ClientCommand( pPlayer->edict(), "god" );
  99. engine->ClientCommand( pPlayer->edict(), "notarget" );
  100. pPlayer->AddSolidFlags( FSOLID_NOT_SOLID );
  101. pPlayer->EnableControl(FALSE);
  102. pPlayer->SetViewEntity( this );
  103. pPlayer->SetFOV( this, m_iFOV );
  104. // Hide the player's viewmodel
  105. if ( pPlayer->GetActiveWeapon() )
  106. {
  107. pPlayer->GetActiveWeapon()->AddEffects( EF_NODRAW );
  108. }
  109. DispatchUpdateTransmitState();
  110. // Now take the shot next frame
  111. SetThink( &CPointDevShotCamera::DevShotThink_TakeShot );
  112. SetNextThink( gpGlobals->curtime );
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose:
  116. //-----------------------------------------------------------------------------
  117. void CPointDevShotCamera::DevShotThink_TakeShot( void )
  118. {
  119. // Take the screenshot
  120. CBasePlayer *pPlayer = UTIL_GetLocalPlayerOrListenServerHost();
  121. if ( !pPlayer )
  122. return;
  123. engine->ClientCommand( pPlayer->edict(), "devshots_screenshot \"%s\"", STRING(m_iszCameraName) );
  124. // Now take the shot next frame
  125. SetThink( &CPointDevShotCamera::DevShotThink_PostShot );
  126. SetNextThink( gpGlobals->curtime + (DEVSHOT_INTERVAL - 1) );
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose:
  130. //-----------------------------------------------------------------------------
  131. void CPointDevShotCamera::DevShotThink_PostShot( void )
  132. {
  133. // Take the screenshot
  134. CBasePlayer *pPlayer = UTIL_GetLocalPlayerOrListenServerHost();
  135. if ( !pPlayer )
  136. return;
  137. pPlayer->SetFOV( this, 0 );
  138. // If all cameras have taken their shots, move to the next map
  139. g_iDevShotCameraCount--;
  140. if ( !g_iDevShotCameraCount )
  141. {
  142. engine->ClientCommand( pPlayer->edict(), "devshots_nextmap" );
  143. }
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose: Game system to detect maps without cameras in them, and move on
  147. //-----------------------------------------------------------------------------
  148. class CDevShotSystem : public CAutoGameSystemPerFrame
  149. {
  150. public:
  151. CDevShotSystem( char const *name ) : CAutoGameSystemPerFrame( name )
  152. {
  153. }
  154. virtual void LevelInitPreEntity()
  155. {
  156. m_bIssuedNextMapCommand = false;
  157. g_iDevShotCameraCount = 0;
  158. m_bParsedMapFile = false;
  159. }
  160. virtual void SafeRemoveIfDesired( void )
  161. {
  162. // If we're not making devshots, remove this system immediately
  163. if ( !CommandLine()->FindParm("-makedevshots") )
  164. {
  165. Remove( this );
  166. return;
  167. }
  168. }
  169. virtual void FrameUpdatePostEntityThink( void )
  170. {
  171. // Wait until we're all spawned in
  172. if ( gpGlobals->curtime < 5 )
  173. return;
  174. if ( m_bIssuedNextMapCommand )
  175. return;
  176. if ( !m_bParsedMapFile )
  177. {
  178. m_bParsedMapFile = true;
  179. // See if we've got a camera file to import cameras from
  180. char szFullName[512];
  181. Q_snprintf(szFullName,sizeof(szFullName), "maps/%s.txt", STRING( gpGlobals->mapname ));
  182. KeyValues *pkvMapCameras = new KeyValues( "MapCameras" );
  183. if ( pkvMapCameras->LoadFromFile( filesystem, szFullName, "MOD" ) )
  184. {
  185. Warning( "Devshots: Loading point_devshot_camera positions from %s. \n", szFullName );
  186. // Get each camera, and add it to our list
  187. KeyValues *pkvCamera = pkvMapCameras->GetFirstSubKey();
  188. while ( pkvCamera )
  189. {
  190. // Get camera name
  191. const char *pCameraName = pkvCamera->GetName();
  192. // Make a camera, and move it to the position specified
  193. CPointDevShotCamera *pCamera = (CPointDevShotCamera*)CreateEntityByName( "point_devshot_camera" );
  194. Assert( pCamera );
  195. pCamera->KeyValue( "cameraname", pCameraName );
  196. pCamera->KeyValue( "origin", pkvCamera->GetString( "origin", "0 0 0" ) );
  197. pCamera->KeyValue( "angles", pkvCamera->GetString( "angles", "0 0 0" ) );
  198. pCamera->KeyValue( "FOV", pkvCamera->GetString( "FOV", "75" ) );
  199. DispatchSpawn( pCamera );
  200. pCamera->Activate();
  201. // Move to next camera
  202. pkvCamera = pkvCamera->GetNextKey();
  203. }
  204. }
  205. if ( !g_iDevShotCameraCount )
  206. {
  207. Warning( "Devshots: No point_devshot_camera in %s. Moving to next map.\n", STRING( gpGlobals->mapname ) );
  208. CBasePlayer *pPlayer = UTIL_GetLocalPlayerOrListenServerHost();
  209. if ( pPlayer )
  210. {
  211. engine->ClientCommand( pPlayer->edict(), "devshots_nextmap" );
  212. m_bIssuedNextMapCommand = true;
  213. return;
  214. }
  215. }
  216. }
  217. }
  218. private:
  219. bool m_bIssuedNextMapCommand;
  220. bool m_bParsedMapFile;
  221. };
  222. CDevShotSystem DevShotSystem( "CDevShotSystem" );