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