1 /* 2 Copyright (c) 2013 yvt 3 based on code of pysnip (c) Mathias Kaerlev 2011-2012. 4 5 This file is part of OpenSpades. 6 7 OpenSpades is free software: you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation, either version 3 of the License, or 10 (at your option) any later version. 11 12 OpenSpades is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with OpenSpades. If not, see <http://www.gnu.org/licenses/>. 19 20 */ 21 22 #pragma once 23 24 #include <list> 25 #include <memory> 26 #include <string> 27 28 #include "ILocalEntity.h" 29 #include "IRenderer.h" 30 #include "IWorldListener.h" 31 #include "MumbleLink.h" 32 #include "NoiseSampler.h" 33 #include "Player.h" 34 #include <Core/Math.h> 35 #include <Core/ServerAddress.h> 36 #include <Core/Stopwatch.h> 37 #include <Gui/View.h> 38 #include "ClientCameraMode.h" 39 40 namespace spades { 41 class IStream; 42 class Stopwatch; 43 namespace client { 44 class IRenderer; 45 struct SceneDefinition; 46 class GameMap; 47 class GameMapWrapper; 48 class World; 49 struct PlayerInput; 50 struct WeaponInput; 51 class IAudioDevice; 52 class IAudioChunk; 53 class NetClient; 54 class IFont; 55 class FontManager; 56 class ChatWindow; 57 class CenterMessageView; 58 class Corpse; 59 class HurtRingView; 60 class MapView; 61 class ScoreboardView; 62 class LimboView; 63 class Player; 64 class PaletteView; 65 class TCProgressView; 66 class ClientPlayer; 67 68 class ClientUI; 69 70 class Client : public IWorldListener, public gui::View { 71 friend class ScoreboardView; 72 friend class LimboView; 73 friend class MapView; 74 friend class FallingBlock; 75 friend class PaletteView; 76 friend class TCProgressView; 77 friend class ClientPlayer; 78 friend class ClientUI; 79 80 /** used to keep the input state of keypad so that 81 * after user pressed left and right, and then 82 * released right, left is internally pressed. */ 83 struct KeypadInput { 84 bool left, right, forward, backward; KeypadInputKeypadInput85 KeypadInput() : left(false), right(false), forward(false), backward(false) {} 86 }; 87 88 class FPSCounter { 89 Stopwatch sw; 90 int numFrames; 91 double lastFps; 92 93 public: 94 FPSCounter(); 95 void MarkFrame(); GetFps()96 double GetFps() { return lastFps; } 97 }; 98 99 FPSCounter fpsCounter; 100 FPSCounter upsCounter; 101 102 std::unique_ptr<NetClient> net; 103 std::string playerName; 104 std::unique_ptr<IStream> logStream; 105 106 Handle<ClientUI> scriptedUI; 107 108 ServerAddress hostname; 109 110 std::unique_ptr<World> world; 111 Handle<GameMap> map; 112 std::unique_ptr<GameMapWrapper> mapWrapper; 113 Handle<IRenderer> renderer; 114 Handle<IAudioDevice> audioDevice; 115 float time; 116 bool readyToClose; 117 float worldSubFrame; 118 119 int frameToRendererInit; 120 float timeSinceInit; 121 122 MumbleLink mumbleLink; 123 124 // view/drawing state for some world objects 125 std::vector<Handle<ClientPlayer>> clientPlayers; 126 127 // other windows 128 std::unique_ptr<CenterMessageView> centerMessageView; 129 std::unique_ptr<HurtRingView> hurtRingView; 130 std::unique_ptr<MapView> mapView; 131 std::unique_ptr<MapView> largeMapView; 132 std::unique_ptr<ScoreboardView> scoreboard; 133 std::unique_ptr<LimboView> limbo; 134 std::unique_ptr<PaletteView> paletteView; 135 std::unique_ptr<TCProgressView> tcView; 136 137 // chat 138 std::unique_ptr<ChatWindow> chatWindow; 139 std::unique_ptr<ChatWindow> killfeedWindow; 140 141 // player state 142 PlayerInput playerInput; 143 WeaponInput weapInput; 144 KeypadInput keypadInput; 145 Player::ToolType lastTool; 146 bool hasLastTool; 147 Vector3 lastFront; 148 float lastPosSentTime; 149 int lastHealth; 150 float lastHurtTime; 151 float lastAliveTime; 152 int lastKills; 153 float worldSetTime; 154 bool hasDelayedReload; 155 struct HurtSprite { 156 float angle; 157 float horzShift; 158 float scale; 159 float strength; 160 }; 161 std::vector<HurtSprite> hurtSprites; 162 163 float GetAimDownState(); 164 float GetSprintState(); 165 166 /** 167 * Queries whether the local player is allowed to use a tool in this state. 168 * 169 * The following factors are considered by this function: 170 * 171 * - The player cannot use a tool while / soon after sprinting. 172 * - The player cannot use a tool while switching tools. 173 * - The player must exist and be alive to use a tool. 174 * 175 * The following factors also affect whether a tool can actually be used, but they 176 * do not affect the result of this function: 177 * 178 * - Tool-specific status — e.g., out of ammo, out of block, "cannot build there" 179 * - Firing rate limit imposed by the tool 180 */ 181 bool CanLocalPlayerUseToolNow(); 182 183 /** Retrieves `ClientPlayer` for the local player, or `nullptr` if it does not exist. */ 184 ClientPlayer *GetLocalClientPlayer(); 185 186 float toolRaiseState; 187 void SetSelectedTool(Player::ToolType, bool quiet = false); 188 189 // view 190 SceneDefinition lastSceneDef; 191 float localFireVibrationTime; 192 float grenadeVibration; 193 float grenadeVibrationSlow; 194 bool scoreboardVisible; 195 bool flashlightOn; 196 float flashlightOnTime; 197 CoherentNoiseSampler1D coherentNoiseSamplers[3]; 198 void KickCamera(float strength); 199 200 float hitFeedbackIconState; 201 bool hitFeedbackFriendly; 202 203 // manual focus 204 float focalLength; 205 float targetFocalLength; 206 bool autoFocusEnabled; 207 208 // Spectator camera control 209 /** The state of the following camera used for spectating. */ 210 struct { 211 /** 212 * Indicates whether the current camera mode is first-person or not. 213 * Ignored and locked to third-person when the target player 214 * (`followedPlayerId`) is dead. 215 */ 216 bool firstPerson = true; 217 218 /** Controls whether the follow camera is enabled. */ 219 bool enabled = false; 220 } followCameraState; 221 222 /** The state of the free floating camera used for spectating. */ 223 struct { 224 /** The temporally smoothed position (I guess). */ 225 Vector3 position {0.0f, 0.0f, 0.0f}; 226 227 /** The temporally smoothed velocity (I guess). */ 228 Vector3 velocity {0.0f, 0.0f, 0.0f}; 229 } freeCameraState; 230 231 /** 232 * The state shared by both of the third-person and free-floating cameras. 233 * 234 * Note: These values are not used in the `cg_thirdperson` mode. 235 */ 236 struct { 237 /** The yaw angle. */ 238 float yaw = 0.0f; 239 240 /** The pitch angle. */ 241 float pitch = 0.0f; 242 } followAndFreeCameraState; 243 244 /** 245 * The ID of the player being followed (in a spectator mode, or when the local player is 246 * dead). Must be valid as long as the follow cam is enabled. 247 * 248 * Must *not* specify a local player. 249 */ 250 int followedPlayerId; 251 252 /** 253 * Chooses the next player to follow and assigns it to `this->followingPlayerId`. 254 * Enables the follow cam by assigning `true` to `followCameraState.enabled`. 255 * If the next player is the local player, disables the follow cam. 256 */ 257 void FollowNextPlayer(bool reverse); 258 259 /** 260 * Retrieves the current camera mode. 261 */ 262 ClientCameraMode GetCameraMode(); 263 264 /** 265 * Retrieves the target player ID of the current camera mode (as returned by 266 * `GetCameraMode`). 267 * 268 * Throws an exception if the current camera mode does not have a player in concern. 269 */ 270 int GetCameraTargetPlayerId(); 271 272 /** 273 * Retrieves the target player of the current camera mode (as returned by 274 * `GetCameraMode`). 275 * 276 * Throws an exception if the current camera mode does not have a player in concern. 277 */ 278 Player &GetCameraTargetPlayer(); 279 280 /** 281 * Calculate the zoom value incorporating the effect of ADS for a first-person view. 282 * 283 * The camera mode must be first-person. 284 */ 285 float GetAimDownZoomScale(); 286 287 bool inGameLimbo; 288 289 float GetLocalFireVibration(); 290 void CaptureColor(); 291 bool IsLimboViewActive(); 292 void SpawnPressed(); 293 294 Player *HotTrackedPlayer(hitTag_t *hitFlag); 295 296 // effects (local entity, etc) 297 std::vector<DynamicLightParam> flashDlights; 298 std::vector<DynamicLightParam> flashDlightsOld; 299 void Bleed(Vector3); 300 void EmitBlockFragments(Vector3, IntVector3 color); 301 void EmitBlockDestroyFragments(IntVector3, IntVector3 color); 302 void GrenadeExplosion(Vector3); 303 void GrenadeExplosionUnderwater(Vector3); 304 void MuzzleFire(Vector3, Vector3 dir, bool local); 305 void BulletHitWaterSurface(Vector3); 306 307 // drawings 308 Handle<FontManager> fontManager; 309 310 enum class AlertType { Notice, Warning, Error }; 311 AlertType alertType; 312 std::string alertContents; 313 float alertDisappearTime; 314 float alertAppearTime; 315 316 std::list<std::unique_ptr<ILocalEntity>> localEntities; 317 std::list<std::unique_ptr<Corpse>> corpses; 318 Corpse *lastMyCorpse; 319 float corpseSoftTimeLimit; 320 unsigned int corpseSoftLimit; 321 unsigned int corpseHardLimit; 322 void RemoveAllCorpses(); 323 void RemoveInvisibleCorpses(); 324 void RemoveAllLocalEntities(); 325 void RemoveCorpseForPlayer(int playerId); 326 327 int nextScreenShotIndex; 328 int nextMapShotIndex; 329 330 Vector3 Project(Vector3); 331 332 void DrawSplash(); 333 void DrawStartupScreen(); 334 void DrawDisconnectScreen(); 335 void DoInit(); 336 337 void ShowAlert(const std::string &contents, AlertType type); 338 void ShowAlert(const std::string &contents, AlertType type, float timeout, 339 bool quiet = false); 340 void PlayAlertSound(); 341 342 void UpdateWorld(float dt); 343 void UpdateLocalSpectator(float dt); 344 void UpdateLocalPlayer(float dt); 345 void UpdateAutoFocus(float dt); 346 float RayCastForAutoFocus(const Vector3 &origin, const Vector3 &direction); 347 348 void Draw2D(); 349 350 void Draw2DWithoutWorld(); 351 void Draw2DWithWorld(); 352 353 /** Called when the local plyaer is alive. */ 354 void DrawJoinedAlivePlayerHUD(); 355 /** Called when the local plyaer is dead. */ 356 void DrawDeadPlayerHUD(); 357 358 /** 359 * Called when `IsFirstPerson(GetCameraMode()).` Renders the follwing element: 360 * - The center reticule 361 */ 362 void DrawFirstPersonHUD(); 363 364 /** 365 * Called when the local player is dead or a spectator. 366 */ 367 void DrawSpectateHUD(); 368 369 void DrawHottrackedPlayerName(); 370 void DrawHurtScreenEffect(); 371 void DrawHurtSprites(); 372 void DrawHealth(); 373 void DrawAlert(); 374 void DrawDebugAim(); 375 void DrawStats(); 376 377 void DrawScene(); 378 void AddGrenadeToScene(Grenade *); 379 void AddDebugObjectToScene(const OBB3 &, const Vector4 &col = MakeVector4(1, 1, 1, 1)); 380 void DrawCTFObjects(); 381 void DrawTCObjects(); 382 383 SceneDefinition CreateSceneDefinition(); 384 385 std::string ScreenShotPath(); 386 void TakeScreenShot(bool sceneOnly); 387 388 std::string MapShotPath(); 389 void TakeMapShot(); 390 391 void NetLog(const char *format, ...); 392 393 protected: 394 ~Client(); 395 396 public: 397 Client(IRenderer *, IAudioDevice *, const ServerAddress &host, FontManager *); 398 399 void RunFrame(float dt) override; 400 401 void Closing() override; 402 void MouseEvent(float x, float y) override; 403 void WheelEvent(float x, float y) override; 404 void KeyEvent(const std::string &, bool down) override; 405 void TextInputEvent(const std::string &) override; 406 void TextEditingEvent(const std::string &, int start, int len) override; 407 bool AcceptsTextInput() override; 408 AABB2 GetTextInputRect() override; 409 bool NeedsAbsoluteMouseCoordinate() override; 410 411 void SetWorld(World *); GetWorld()412 World *GetWorld() const { return world.get(); } AddLocalEntity(ILocalEntity * ent)413 void AddLocalEntity(ILocalEntity *ent) { localEntities.emplace_back(ent); } 414 415 void MarkWorldUpdate(); 416 GetRenderer()417 IRenderer *GetRenderer() { return renderer; } GetLastSceneDef()418 SceneDefinition GetLastSceneDef() { return lastSceneDef; } GetAudioDevice()419 IAudioDevice *GetAudioDevice() { return audioDevice; } 420 421 bool WantsToBeClosed() override; 422 bool IsMuted(); 423 424 void PlayerSentChatMessage(Player *, bool global, const std::string &); 425 void ServerSentMessage(const std::string &); 426 427 void PlayerCapturedIntel(Player *); 428 void PlayerCreatedBlock(Player *); 429 void PlayerPickedIntel(Player *); 430 void PlayerDropIntel(Player *); 431 void TeamCapturedTerritory(int teamId, int territoryId); 432 void TeamWon(int); 433 void JoinedGame(); 434 void LocalPlayerCreated(); 435 void PlayerDestroyedBlockWithWeaponOrTool(IntVector3); 436 void PlayerDiggedBlock(IntVector3); 437 void GrenadeDestroyedBlock(IntVector3); 438 void PlayerLeaving(Player *); 439 void PlayerJoinedTeam(Player *); 440 void PlayerSpawned(Player *); 441 442 void PlayerObjectSet(int) override; 443 void PlayerMadeFootstep(Player *) override; 444 void PlayerJumped(Player *) override; 445 void PlayerLanded(Player *, bool hurt) override; 446 void PlayerFiredWeapon(Player *) override; 447 void PlayerDryFiredWeapon(Player *) override; 448 void PlayerReloadingWeapon(Player *) override; 449 void PlayerReloadedWeapon(Player *) override; 450 void PlayerChangedTool(Player *) override; 451 void PlayerThrownGrenade(Player *, Grenade *) override; 452 void PlayerMissedSpade(Player *) override; 453 void PlayerRestocked(Player *) override; 454 455 /** @deprecated use BulletHitPlayer */ 456 void PlayerHitBlockWithSpade(Player *, Vector3 hitPos, IntVector3 blockPos, 457 IntVector3 normal) override; 458 void PlayerKilledPlayer(Player *killer, Player *victim, KillType) override; 459 460 void BulletHitPlayer(Player *hurtPlayer, HitType, Vector3 hitPos, Player *by) override; 461 void BulletHitBlock(Vector3, IntVector3 blockPos, IntVector3 normal) override; 462 void AddBulletTracer(Player *player, Vector3 muzzlePos, Vector3 hitPos) override; 463 void GrenadeExploded(Grenade *) override; 464 void GrenadeBounced(Grenade *) override; 465 void GrenadeDroppedIntoWater(Grenade *) override; 466 467 void BlocksFell(std::vector<IntVector3>) override; 468 469 void LocalPlayerPulledGrenadePin() override; 470 void LocalPlayerBlockAction(IntVector3, BlockActionType type) override; 471 void LocalPlayerCreatedLineBlock(IntVector3, IntVector3) override; 472 void LocalPlayerHurt(HurtType type, bool sourceGiven, Vector3 source) override; 473 void LocalPlayerBuildError(BuildFailureReason reason) override; 474 }; 475 } 476 } 477