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.

235 lines
6.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "serverbenchmark_tf.h"
  8. #include "tf_shareddefs.h"
  9. #include "tf_bot_temp.h"
  10. #include "entity_tfstart.h"
  11. #include "tf_player.h"
  12. static ConVar sv_benchmark_freeroam( "sv_benchmark_freeroam", "0", 0, "Allow the local player to move freely in the benchmark. Only used for debugging. Don't use for real benchmarks because it will make the timing inconsistent." );
  13. class CTFServerBenchmark : public CServerBenchmarkHook
  14. {
  15. public:
  16. virtual void StartBenchmark()
  17. {
  18. ConVarRef cvBotFlipout( "bot_flipout" );
  19. cvBotFlipout.SetValue( 3 );
  20. extern ConVar bot_forceattack_down;
  21. bot_forceattack_down.SetValue( true );
  22. extern ConVar mp_teams_unbalance_limit;
  23. mp_teams_unbalance_limit.SetValue( (int)0 );
  24. m_nBotsCreated = 0;
  25. m_bSetupLocalPlayer = false;
  26. }
  27. virtual void GetPhysicsModelNames( CUtlVector<char*> &modelNames )
  28. {
  29. modelNames.AddToTail( "models/props_farm/wooden_barrel.mdl" );
  30. modelNames.AddToTail( "models/props_gameplay/orange_cone001.mdl" );
  31. }
  32. virtual CBaseEntity* GetBlueSpawnPoint( bool bBest )
  33. {
  34. CUtlVector<CTFTeamSpawn*> spawns;
  35. for ( int i=0; i<ITFTeamSpawnAutoList::AutoList().Count(); ++i )
  36. {
  37. CTFTeamSpawn *pTFSpawn = static_cast< CTFTeamSpawn* >( ITFTeamSpawnAutoList::AutoList()[i] );
  38. if ( !pTFSpawn->IsDisabled() && pTFSpawn->GetTeamNumber() == TF_TEAM_BLUE )
  39. spawns.AddToTail( pTFSpawn );
  40. }
  41. // If we're not looking for the BEST one, return a random one.
  42. if ( !bBest )
  43. {
  44. if ( spawns.Count() == 0 )
  45. return NULL;
  46. return spawns[ g_pServerBenchmark->RandomInt( 0, spawns.Count()-1 ) ];
  47. }
  48. float flBestSpawn = 0;
  49. CTFTeamSpawn *pBestSpawn = NULL;
  50. for ( int i=0; i < spawns.Count(); i++ )
  51. {
  52. Vector vForward;
  53. AngleVectors( spawns[i]->GetLocalAngles(), &vForward );
  54. float flCurSpawn = 0;
  55. for ( int j=0; j < spawns.Count(); j++ )
  56. {
  57. if ( j == i )
  58. continue;
  59. Vector vTo = spawns[j]->GetAbsOrigin() - spawns[i]->GetAbsOrigin();
  60. VectorNormalize( vTo );
  61. flCurSpawn += vForward.Dot( vTo );
  62. }
  63. if ( flCurSpawn > flBestSpawn )
  64. {
  65. flBestSpawn = flCurSpawn;
  66. pBestSpawn = spawns[i];
  67. }
  68. }
  69. return pBestSpawn;
  70. }
  71. virtual void UpdateBenchmark()
  72. {
  73. if ( m_nBotsCreated == 0 )
  74. {
  75. return;
  76. }
  77. RandomSeed( 0 );
  78. // Put the player at a blue spawn point.
  79. if ( !engine->IsDedicatedServer() )
  80. {
  81. CTFPlayer *pLocalPlayer = dynamic_cast< CTFPlayer* >( UTIL_GetListenServerHost() );
  82. if ( pLocalPlayer )
  83. {
  84. if ( !m_bSetupLocalPlayer )
  85. {
  86. m_bSetupLocalPlayer = true;
  87. pLocalPlayer->ChangeTeam( TEAM_SPECTATOR );
  88. pLocalPlayer->SetDesiredPlayerClassIndex( TF_CLASS_SNIPER );
  89. pLocalPlayer->ForceRespawn();
  90. // Now pick whatever blue spawn point has the most other spawn points in front of it.
  91. CBaseEntity *pBestSpawn = GetBlueSpawnPoint( true );
  92. if ( !pBestSpawn )
  93. Error( "Can't find spawn position for local player." );
  94. m_vLocalPlayerOrigin = pBestSpawn->GetLocalOrigin() + Vector(0,0,80);
  95. m_vLocalPlayerEyeAngles = pBestSpawn->GetLocalAngles();
  96. }
  97. ((CBasePlayer*)pLocalPlayer)->SetObserverMode( OBS_MODE_ROAMING );
  98. // Lock the player in place for a little bit, then let them go free when we have some bots.
  99. if ( !sv_benchmark_freeroam.GetBool() || m_nBotsCreated < 2 )
  100. {
  101. pLocalPlayer->Teleport( &m_vLocalPlayerOrigin, &m_vLocalPlayerEyeAngles, NULL );
  102. pLocalPlayer->SetObserverTarget( NULL );
  103. if ( !sv_benchmark_freeroam.GetBool() )
  104. pLocalPlayer->AddFlag( FL_FROZEN );
  105. }
  106. }
  107. }
  108. RespawnDeadPlayers();
  109. MoveRedPlayersToBlueArea();
  110. AddSentries();
  111. }
  112. void RespawnDeadPlayers()
  113. {
  114. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  115. {
  116. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  117. if ( pPlayer && pPlayer->IsDead() && !g_pServerBenchmark->IsLocalBenchmarkPlayer( pPlayer ) )
  118. {
  119. pPlayer->ForceRespawn();
  120. }
  121. }
  122. }
  123. void AddSentries()
  124. {
  125. const char *pSentryClassName = "obj_sentrygun";
  126. for ( int iTeamIteration=0; iTeamIteration < 2; iTeamIteration++ )
  127. {
  128. int iTeam = (iTeamIteration == 0) ? TF_TEAM_BLUE : TF_TEAM_RED;
  129. // Get the current # of sentries.
  130. int nSentries = 0;
  131. CBaseEntity *pSpot = gEntList.FindEntityByClassname( NULL, pSentryClassName );
  132. while( pSpot )
  133. {
  134. if ( pSpot->GetTeamNumber() == iTeam )
  135. ++nSentries;
  136. pSpot = gEntList.FindEntityByClassname( pSpot, pSentryClassName );
  137. }
  138. // Make new ones if necessary.
  139. if ( nSentries < 2 )
  140. {
  141. // Find an engineer..
  142. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  143. {
  144. CTFPlayer *pPlayer = dynamic_cast< CTFPlayer* >( UTIL_PlayerByIndex( i ) );
  145. if ( pPlayer && pPlayer->GetTeamNumber() == iTeam && pPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_ENGINEER )
  146. {
  147. pPlayer->StartBuildingObjectOfType( OBJ_SENTRYGUN );
  148. if ( pPlayer->GetActiveWeapon() )
  149. pPlayer->GetActiveWeapon()->PrimaryAttack();
  150. break;
  151. }
  152. }
  153. }
  154. }
  155. }
  156. void MoveRedPlayersToBlueArea()
  157. {
  158. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  159. {
  160. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  161. if ( pPlayer && pPlayer->GetTeamNumber() == TF_TEAM_RED )
  162. {
  163. // If too far from the spawns, then teleport into the blue area.
  164. CBaseEntity *pSpawn = GetBlueSpawnPoint( false );
  165. if ( pPlayer->GetAbsOrigin().DistTo( pSpawn->GetAbsOrigin() ) > 2000 )
  166. {
  167. pPlayer->Teleport( &pSpawn->GetAbsOrigin(), NULL, NULL );
  168. }
  169. }
  170. }
  171. }
  172. virtual CBasePlayer* CreateBot()
  173. {
  174. int iTeam = (g_pServerBenchmark->RandomInt( 0, 1 ) == 1) ? TF_TEAM_BLUE : TF_TEAM_RED;
  175. if ( m_nBotsCreated == 0 )
  176. iTeam = TF_TEAM_BLUE;
  177. int iClass = g_pServerBenchmark->RandomInt( TF_FIRST_NORMAL_CLASS, ( TF_LAST_NORMAL_CLASS - 1 ) ); //( TF_LAST_NORMAL_CLASS - 1 ) to exclude the new civilian class
  178. if ( m_nBotsCreated < 4 )
  179. iClass = TF_CLASS_ENGINEER; // Make engineers first so they'll build sentries.
  180. CBasePlayer *pPlayer = BotPutInServer( false, false, iTeam, iClass, NULL );
  181. if ( !pPlayer )
  182. Error( "Server benchmark: Can't create bot." );
  183. ++m_nBotsCreated;
  184. return pPlayer;
  185. }
  186. private:
  187. int m_nBotsCreated;
  188. bool m_bSetupLocalPlayer;
  189. Vector m_vLocalPlayerOrigin;
  190. QAngle m_vLocalPlayerEyeAngles;
  191. };
  192. static CTFServerBenchmark g_TFServerBenchmark;