1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef GAME_CLIENT_GAMECLIENT_H
4#define GAME_CLIENT_GAMECLIENT_H
5
6#include "render.h"
7
8#include <base/color.h>
9#include <base/types.h>
10#include <base/vmath.h>
11
12#include <engine/client.h>
13#include <engine/client/enums.h>
14#include <engine/console.h>
15#include <engine/shared/config.h>
16#include <engine/shared/snapshot.h>
17
18#include <generated/protocol7.h>
19#include <generated/protocolglue.h>
20
21#include <game/client/prediction/gameworld.h>
22#include <game/client/race.h>
23#include <game/collision.h>
24#include <game/gamecore.h>
25#include <game/layers.h>
26#include <game/map/render_map.h>
27#include <game/mapbugs.h>
28#include <game/teamscore.h>
29
30// components
31#include "components/background.h"
32#include "components/binds.h"
33#include "components/broadcast.h"
34#include "components/camera.h"
35#include "components/censor.h"
36#include "components/chat.h"
37#include "components/console.h"
38#include "components/controls.h"
39#include "components/countryflags.h"
40#include "components/damageind.h"
41#include "components/debughud.h"
42#include "components/effects.h"
43#include "components/emoticon.h"
44#include "components/flow.h"
45#include "components/freezebars.h"
46#include "components/ghost.h"
47#include "components/hud.h"
48#include "components/important_alert.h"
49#include "components/infomessages.h"
50#include "components/items.h"
51#include "components/key_binder.h"
52#include "components/local_server.h"
53#include "components/mapimages.h"
54#include "components/maplayers.h"
55#include "components/mapsounds.h"
56#include "components/menu_background.h"
57#include "components/menus.h"
58#include "components/motd.h"
59#include "components/nameplates.h"
60#include "components/particles.h"
61#include "components/players.h"
62#include "components/race_demo.h"
63#include "components/scoreboard.h"
64#include "components/skins.h"
65#include "components/skins7.h"
66#include "components/sounds.h"
67#include "components/spectator.h"
68#include "components/statboard.h"
69#include "components/tooltips.h"
70#include "components/touch_controls.h"
71#include "components/voting.h"
72
73#include <memory>
74#include <vector>
75
76class IMap;
77
78class CGameInfo
79{
80public:
81 bool m_FlagStartsRace;
82 bool m_TimeScore;
83 bool m_UnlimitedAmmo;
84 bool m_DDRaceRecordMessage;
85 bool m_RaceRecordMessage;
86 bool m_RaceSounds;
87
88 bool m_AllowEyeWheel;
89 bool m_AllowHookColl;
90 bool m_AllowZoom;
91
92 bool m_BugDDRaceGhost;
93 bool m_BugDDRaceInput;
94 bool m_BugFNGLaserRange;
95 bool m_BugVanillaBounce;
96
97 bool m_PredictFNG;
98 bool m_PredictDDRace;
99 bool m_PredictDDRaceTiles;
100 bool m_PredictVanilla;
101
102 bool m_EntitiesDDNet;
103 bool m_EntitiesDDRace;
104 bool m_EntitiesRace;
105 bool m_EntitiesFNG;
106 bool m_EntitiesVanilla;
107 bool m_EntitiesBW;
108 bool m_EntitiesFDDrace;
109
110 bool m_Race;
111 bool m_Pvp;
112
113 bool m_DontMaskEntities;
114 bool m_AllowXSkins;
115
116 bool m_HudHealthArmor;
117 bool m_HudAmmo;
118 bool m_HudDDRace;
119
120 bool m_NoWeakHookAndBounce;
121 bool m_NoSkinChangeForFrozen;
122
123 bool m_DDRaceTeam;
124
125 bool m_PredictEvents;
126};
127
128class CSnapEntities
129{
130public:
131 IClient::CSnapItem m_Item;
132 const CNetObj_EntityEx *m_pDataEx;
133};
134
135enum class EClientIdFormat
136{
137 NO_INDENT,
138 INDENT_AUTO,
139 INDENT_FORCE, // for rendering settings preview
140};
141
142class CGameClient : public IGameClient
143{
144public:
145 // all components
146 CInfoMessages m_InfoMessages;
147 CCamera m_Camera;
148 CChat m_Chat;
149 CCensor m_Censor;
150 CMotd m_Motd;
151 CBroadcast m_Broadcast;
152 CGameConsole m_GameConsole;
153 CBinds m_Binds;
154 CKeyBinder m_KeyBinder;
155 CParticles m_Particles;
156 CMenus m_Menus;
157 CSkins m_Skins;
158 CSkins7 m_Skins7;
159 CCountryFlags m_CountryFlags;
160 CFlow m_Flow;
161 CHud m_Hud;
162 CImportantAlert m_ImportantAlert;
163 CDebugHud m_DebugHud;
164 CControls m_Controls;
165 CEffects m_Effects;
166 CScoreboard m_Scoreboard;
167 CStatboard m_Statboard;
168 CSounds m_Sounds;
169 CEmoticon m_Emoticon;
170 CDamageInd m_DamageInd;
171 CTouchControls m_TouchControls;
172 CVoting m_Voting;
173 CSpectator m_Spectator;
174
175 CPlayers m_Players;
176 CNamePlates m_NamePlates;
177 CFreezeBars m_FreezeBars;
178 CItems m_Items;
179 CMapImages m_MapImages;
180
181 CMapLayers m_MapLayersBackground = CMapLayers{ERenderType::RENDERTYPE_BACKGROUND};
182 CMapLayers m_MapLayersForeground = CMapLayers{ERenderType::RENDERTYPE_FOREGROUND};
183 CBackground m_Background;
184 CMenuBackground m_MenuBackground;
185
186 CMapSounds m_MapSounds;
187
188 CRaceDemo m_RaceDemo;
189 CGhost m_Ghost;
190
191 CTooltips m_Tooltips;
192
193 CLocalServer m_LocalServer;
194
195private:
196 std::vector<class CComponent *> m_vpAll;
197 std::vector<class CComponent *> m_vpInput;
198 CNetObjHandler m_NetObjHandler;
199 protocol7::CNetObjHandler m_NetObjHandler7;
200
201 class IEngine *m_pEngine;
202 class IInput *m_pInput;
203 class IGraphics *m_pGraphics;
204 class ITextRender *m_pTextRender;
205 class IClient *m_pClient;
206 class ISound *m_pSound;
207 class IConfigManager *m_pConfigManager;
208 class CConfig *m_pConfig;
209 class IConsole *m_pConsole;
210 class IStorage *m_pStorage;
211 class IDemoPlayer *m_pDemoPlayer;
212 class IFavorites *m_pFavorites;
213 class IServerBrowser *m_pServerBrowser;
214 class IEditor *m_pEditor;
215 class IFriends *m_pFriends;
216 class IFriends *m_pFoes;
217 class IDiscord *m_pDiscord;
218#if defined(CONF_AUTOUPDATE)
219 class IUpdater *m_pUpdater;
220#endif
221 class IHttp *m_pHttp;
222
223 CLayers m_Layers;
224 CCollision m_Collision;
225 CUi m_UI;
226 CRaceHelper m_RaceHelper;
227
228 void ProcessEvents();
229 void UpdatePositions();
230
231 int m_EditorMovementDelay = 5;
232 void UpdateEditorIngameMoved();
233
234 int m_PredictedTick;
235 int m_aLastNewPredictedTick[NUM_DUMMIES];
236
237 int m_LastRoundStartTick;
238 int m_LastRaceTick;
239
240 int m_LastFlagCarrierRed;
241 int m_LastFlagCarrierBlue;
242
243 int m_aCheckInfo[NUM_DUMMIES];
244
245 char m_aDDNetVersionStr[64];
246
247 static void ConTeam(IConsole::IResult *pResult, void *pUserData);
248 static void ConKill(IConsole::IResult *pResult, void *pUserData);
249 static void ConReadyChange7(IConsole::IResult *pResult, void *pUserData);
250
251 static void ConchainLanguageUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
252 static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
253 static void ConchainSpecialDummyInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
254 static void ConchainRefreshSkins(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
255 static void ConchainRefreshEventSkins(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
256 static void ConchainSpecialDummy(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
257
258 static void ConTuneParam(IConsole::IResult *pResult, void *pUserData);
259 static void ConTuneZone(IConsole::IResult *pResult, void *pUserData);
260 static void ConMapbug(IConsole::IResult *pResult, void *pUserData);
261
262 static void ConchainMenuMap(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
263
264 static std::function<bool(int, int, int, int)> GetScoreComparator(bool TimeScore, bool ReceivedMillisecondFinishTimes, bool Race7);
265
266 // only used in OnPredict
267 vec2 m_aLastPos[MAX_CLIENTS];
268 bool m_aLastActive[MAX_CLIENTS];
269
270 // only used in OnNewSnapshot
271 bool m_GameOver = false;
272 bool m_GamePaused = false;
273
274public:
275 IKernel *Kernel() { return IInterface::Kernel(); }
276 IEngine *Engine() const { return m_pEngine; }
277 class IGraphics *Graphics() const { return m_pGraphics; }
278 class IClient *Client() const { return m_pClient; }
279 class CUi *Ui() { return &m_UI; }
280 class ISound *Sound() const { return m_pSound; }
281 class IInput *Input() const { return m_pInput; }
282 class IStorage *Storage() const { return m_pStorage; }
283 class IConfigManager *ConfigManager() const { return m_pConfigManager; }
284 class CConfig *Config() const { return m_pConfig; }
285 class IConsole *Console() { return m_pConsole; }
286 class ITextRender *TextRender() const { return m_pTextRender; }
287 class IDemoPlayer *DemoPlayer() const { return m_pDemoPlayer; }
288 class IDemoRecorder *DemoRecorder(int Recorder) const { return Client()->DemoRecorder(Recorder); }
289 class IFavorites *Favorites() const { return m_pFavorites; }
290 class IServerBrowser *ServerBrowser() const { return m_pServerBrowser; }
291 class CRenderTools *RenderTools() { return &m_RenderTools; }
292 class CRenderMap *RenderMap() { return &m_RenderMap; }
293 class CLayers *Layers() { return &m_Layers; }
294 CCollision *Collision() { return &m_Collision; }
295 const CCollision *Collision() const { return &m_Collision; }
296 const CRaceHelper *RaceHelper() const { return &m_RaceHelper; }
297 class IEditor *Editor() { return m_pEditor; }
298 class IFriends *Friends() { return m_pFriends; }
299 class IFriends *Foes() { return m_pFoes; }
300#if defined(CONF_AUTOUPDATE)
301 class IUpdater *Updater()
302 {
303 return m_pUpdater;
304 }
305#endif
306 class IHttp *Http()
307 {
308 return m_pHttp;
309 }
310
311 int NetobjNumCorrections()
312 {
313 return m_NetObjHandler.NumObjCorrections();
314 }
315 const char *NetobjCorrectedOn() { return m_NetObjHandler.CorrectedObjOn(); }
316
317 bool m_SuppressEvents;
318 bool m_NewTick;
319 bool m_NewPredictedTick;
320 int m_aFlagDropTick[2];
321
322 enum
323 {
324 SERVERMODE_PURE = 0,
325 SERVERMODE_MOD,
326 SERVERMODE_PUREMOD,
327 };
328 int m_ServerMode;
329 CGameInfo m_GameInfo;
330
331 int m_DemoSpecId;
332
333 vec2 m_LocalCharacterPos;
334
335 // predicted players
336 CCharacterCore m_PredictedPrevChar;
337 CCharacterCore m_PredictedChar;
338
339 // snap pointers
340 class CSnapState
341 {
342 public:
343 const CNetObj_Character *m_pLocalCharacter;
344 const CNetObj_Character *m_pLocalPrevCharacter;
345 const CNetObj_PlayerInfo *m_pLocalInfo;
346 const CNetObj_SpectatorInfo *m_pSpectatorInfo;
347 const CNetObj_SpectatorInfo *m_pPrevSpectatorInfo;
348 const CNetObj_SpectatorCount *m_pSpectatorCount;
349 int m_NumFlags;
350 const CNetObj_Flag *m_apFlags[CSnapshot::MAX_ITEMS];
351 const CNetObj_Flag *m_apPrevFlags[CSnapshot::MAX_ITEMS];
352 const CNetObj_GameInfo *m_pGameInfoObj;
353 const CNetObj_GameData *m_pGameDataObj;
354 const CNetObj_GameData *m_pPrevGameDataObj;
355
356 const CNetObj_PlayerInfo *m_apPlayerInfos[MAX_CLIENTS];
357 const CNetObj_PlayerInfo *m_apPrevPlayerInfos[MAX_CLIENTS];
358
359 const CNetObj_PlayerInfo *m_apInfoByScore[MAX_CLIENTS];
360 const CNetObj_PlayerInfo *m_apInfoByName[MAX_CLIENTS];
361 const CNetObj_PlayerInfo *m_apInfoByDDTeamScore[MAX_CLIENTS];
362 const CNetObj_PlayerInfo *m_apInfoByDDTeamName[MAX_CLIENTS];
363
364 int m_LocalClientId;
365 int m_NumPlayers;
366 int m_aTeamSize[2];
367 int m_HighestClientId;
368
369 class CSpectateInfo
370 {
371 public:
372 bool m_Active;
373 int m_SpectatorId;
374 bool m_UsePosition;
375 vec2 m_Position;
376
377 bool m_HasCameraInfo;
378 float m_Zoom;
379 int m_Deadzone;
380 int m_FollowFactor;
381 };
382 CSpectateInfo m_SpecInfo;
383
384 class CCharacterInfo
385 {
386 public:
387 bool m_Active;
388
389 // snapshots
390 CNetObj_Character m_Prev;
391 CNetObj_Character m_Cur;
392
393 CNetObj_DDNetCharacter m_ExtendedData;
394 const CNetObj_DDNetCharacter *m_pPrevExtendedData;
395 bool m_HasExtendedData;
396 bool m_HasExtendedDisplayInfo;
397 };
398 CCharacterInfo m_aCharacters[MAX_CLIENTS];
399 };
400
401 CSnapState m_Snap;
402 int m_aLocalTuneZone[NUM_DUMMIES]; // current tunezone (0-255)
403 bool m_aReceivedTuning[NUM_DUMMIES]; // was tuning message received after zone change
404 int m_aExpectingTuningForZone[NUM_DUMMIES]; // tunezone changed, waiting for tuning for that zone
405 int m_aExpectingTuningSince[NUM_DUMMIES]; // how many snaps received since tunezone changed
406 CTuningParams m_aTuning[NUM_DUMMIES]; // current local player tuning, only what the player/dummy has
407
408 std::bitset<RECORDER_MAX> m_ActiveRecordings;
409
410 // spectate cursor data
411 class CCursorInfo
412 {
413 friend class CGameClient;
414 static constexpr int CURSOR_SAMPLES = 8; // how many samples to keep
415 static constexpr int SAMPLE_FRAME_WINDOW = 3; // how many samples should be used for polynomial interpolation
416 static constexpr int SAMPLE_FRAME_OFFSET = 2; // how many samples in the past should be included
417 static constexpr double INTERP_DELAY = 4.25; // how many ticks in the past to show, enables extrapolation with smaller value (<= SAMPLE_FRAME_WINDOW - SAMPLE_FRAME_OFFSET + 3)
418 static constexpr double REST_THRESHOLD = 3.0; // how many ticks of the same samples are considered to be resting
419
420 int m_CursorOwnerId;
421 double m_aTargetSamplesTime[CURSOR_SAMPLES];
422 vec2 m_aTargetSamplesData[CURSOR_SAMPLES];
423 int m_NumSamples;
424
425 bool m_Available;
426 int m_Weapon;
427 vec2 m_Target;
428 vec2 m_WorldTarget;
429 vec2 m_Position;
430
431 public:
432 bool IsAvailable() const { return m_Available; }
433 int Weapon() const { return m_Weapon; }
434 vec2 Target() const { return m_Target; }
435 vec2 WorldTarget() const { return m_WorldTarget; }
436 vec2 Position() const { return m_Position; }
437 } m_CursorInfo;
438
439 // client data
440 class CClientData
441 {
442 friend class CGameClient;
443 CGameClient *m_pGameClient;
444 int m_ClientId;
445
446 public:
447 int m_UseCustomColor;
448 int m_ColorBody;
449 int m_ColorFeet;
450
451 char m_aName[MAX_NAME_LENGTH];
452 char m_aClan[MAX_CLAN_LENGTH];
453 int m_Country;
454 char m_aSkinName[MAX_SKIN_LENGTH];
455 int m_Team;
456 int m_Emoticon;
457 float m_EmoticonStartFraction;
458 int m_EmoticonStartTick;
459
460 bool m_Solo;
461 bool m_Jetpack;
462 bool m_CollisionDisabled;
463 bool m_EndlessHook;
464 bool m_EndlessJump;
465 bool m_HammerHitDisabled;
466 bool m_GrenadeHitDisabled;
467 bool m_LaserHitDisabled;
468 bool m_ShotgunHitDisabled;
469 bool m_HookHitDisabled;
470 bool m_Super;
471 bool m_Invincible;
472 bool m_HasTelegunGun;
473 bool m_HasTelegunGrenade;
474 bool m_HasTelegunLaser;
475 int m_FreezeEnd;
476 bool m_DeepFrozen;
477 bool m_LiveFrozen;
478
479 CCharacterCore m_Predicted;
480 CCharacterCore m_PrevPredicted;
481
482 std::shared_ptr<CManagedTeeRenderInfo> m_pSkinInfo = nullptr; // this is what the server reports
483 CTeeRenderInfo m_RenderInfo; // this is what we use
484
485 float m_Angle;
486 bool m_Active;
487 bool m_ChatIgnore;
488 bool m_EmoticonIgnore;
489 bool m_Friend;
490 bool m_Foe;
491
492 int m_AuthLevel;
493 bool m_Afk;
494 bool m_Paused;
495 bool m_Spec;
496
497 int m_FinishTimeSeconds;
498 int m_FinishTimeMillis;
499
500 // Editor allows 256 switches for now.
501 bool m_aSwitchStates[256];
502
503 CNetObj_Character m_Snapped;
504 CNetObj_Character m_Evolved;
505
506 CNetMsg_Sv_PreInput m_aPreInputs[200];
507
508 // rendered characters
509 CNetObj_Character m_RenderCur;
510 CNetObj_Character m_RenderPrev;
511 vec2 m_RenderPos;
512 bool m_IsPredicted;
513 bool m_IsPredictedLocal;
514 int64_t m_aSmoothStart[2];
515 int64_t m_aSmoothLen[2];
516 vec2 m_aPredPos[200];
517 int m_aPredTick[200];
518 bool m_SpecCharPresent;
519 vec2 m_SpecChar;
520
521 void UpdateSkinInfo();
522 void UpdateSkin7HatSprite(int Dummy);
523 void UpdateSkin7BotDecoration(int Dummy);
524 void UpdateRenderInfo();
525 void Reset();
526 CSkinDescriptor ToSkinDescriptor() const;
527
528 int ClientId() const { return m_ClientId; }
529
530 class CSixup
531 {
532 public:
533 void Reset();
534
535 char m_aaSkinPartNames[protocol7::NUM_SKINPARTS][protocol7::MAX_SKIN_LENGTH];
536 int m_aUseCustomColors[protocol7::NUM_SKINPARTS];
537 int m_aSkinPartColors[protocol7::NUM_SKINPARTS];
538 };
539
540 // 0.7 Skin
541 CSixup m_aSixup[NUM_DUMMIES];
542 };
543
544 CClientData m_aClients[MAX_CLIENTS];
545
546 class CClientStats
547 {
548 int m_IngameTicks;
549 int m_JoinTick;
550 bool m_Active;
551
552 public:
553 CClientStats();
554
555 int m_aFragsWith[NUM_WEAPONS];
556 int m_aDeathsFrom[NUM_WEAPONS];
557 int m_Frags;
558 int m_Deaths;
559 int m_Suicides;
560 int m_BestSpree;
561 int m_CurrentSpree;
562
563 int m_FlagGrabs;
564 int m_FlagCaptures;
565
566 void Reset();
567
568 bool IsActive() const { return m_Active; }
569 void JoinGame(int Tick)
570 {
571 m_Active = true;
572 m_JoinTick = Tick;
573 }
574 void JoinSpec(int Tick)
575 {
576 m_Active = false;
577 m_IngameTicks += Tick - m_JoinTick;
578 }
579 int GetIngameTicks(int Tick) const { return m_IngameTicks + Tick - m_JoinTick; }
580 float GetFPM(int Tick, int TickSpeed) const { return (float)(m_Frags * TickSpeed * 60) / GetIngameTicks(Tick); }
581 };
582
583 CClientStats m_aStats[MAX_CLIENTS];
584
585 CRenderTools m_RenderTools;
586 CRenderMap m_RenderMap;
587
588 bool m_BackButtonHandledKeyBind = false;
589
590 void OnReset();
591
592 size_t ComponentCount() const { return m_vpAll.size(); }
593
594 // hooks
595 void OnConnected() override;
596 void OnRender() override;
597 void OnUpdate() override;
598 void OnDummyDisconnect() override;
599 virtual void OnRelease();
600 void OnInit() override;
601 void OnConsoleInit() override;
602 void OnStateChange(int NewState, int OldState) override;
603 template<typename T>
604 void ApplySkin7InfoFromGameMsg(const T *pMsg, int ClientId, int Conn);
605 void ApplySkin7InfoFromSnapObj(const protocol7::CNetObj_De_ClientInfo *pObj, int ClientId) override;
606 int OnDemoRecSnap7(CSnapshot *pFrom, CSnapshotBuffer *pTo, int Conn) override;
607 void *TranslateGameMsg(int *pMsgId, CUnpacker *pUnpacker, int Conn);
608 int TranslateSnap(CSnapshotBuffer *pSnapDstSix, CSnapshot *pSnapSrcSeven, int Conn, bool Dummy) override;
609 void OnMessage(int MsgId, CUnpacker *pUnpacker, int Conn, bool Dummy) override;
610 void InvalidateSnapshot() override;
611 void OnNewSnapshot(bool DummySwapped) override;
612 void OnPredict() override;
613 void OnActivateEditor() override;
614 void OnDummySwap() override;
615 int OnSnapInput(int *pData, bool Dummy, bool Force) override;
616 void OnShutdown() override;
617 void OnEnterGame() override;
618 void OnRconType(bool UsernameReq) override;
619 void OnRconLine(const char *pLine) override;
620 virtual void OnGameOver();
621 virtual void OnStartGame();
622 virtual void OnStartRound();
623 virtual void OnFlagGrab(int TeamId);
624 void OnWindowResize() override;
625
626 void InitializeLanguage() override;
627 bool m_LanguageChanged = false;
628 void OnLanguageChange();
629 void HandleLanguageChanged();
630
631 void ForceUpdateConsoleRemoteCompletionSuggestions() override;
632
633 void RefreshSkin(const std::shared_ptr<CManagedTeeRenderInfo> &pManagedTeeRenderInfo);
634 void RefreshSkins(int SkinDescriptorFlags);
635 void OnSkinUpdate(const char *pSkinName);
636 std::shared_ptr<CManagedTeeRenderInfo> CreateManagedTeeRenderInfo(const CTeeRenderInfo &TeeRenderInfo, const CSkinDescriptor &SkinDescriptor);
637 std::shared_ptr<CManagedTeeRenderInfo> CreateManagedTeeRenderInfo(const CClientData &Client);
638 void CollectManagedTeeRenderInfos(const std::function<void(const char *pSkinName)> &ActiveSkinAcceptor);
639
640 void RenderShutdownMessage() override;
641 void ProcessDemoSnapshot(CSnapshot *pSnap) override;
642
643 const char *GetItemName(int Type) const override;
644 const char *Version() const override;
645 const char *NetVersion() const override;
646 const char *NetVersion7() const override;
647 int DDNetVersion() const override;
648 const char *DDNetVersionStr() const override;
649 int ClientVersion7() const override;
650
651 void DoTeamChangeMessage7(const char *pName, int ClientId, int Team, const char *pPrefix = "");
652
653 // actions
654 // TODO: move these
655 void SendSwitchTeam(int Team) const;
656 void SendStartInfo7(bool Dummy);
657 void SendSkinChange7(bool Dummy);
658 // Returns true if the requested skin change got applied by the server
659 bool GotWantedSkin7(bool Dummy);
660 void SendInfo(bool Start);
661 void SendDummyInfo(bool Start) override;
662 void SendKill() const;
663 void SendReadyChange7();
664
665 void ApplyPreInputs(int Tick, bool Direct, CGameWorld &GameWorld);
666
667 int m_aNextChangeInfo[NUM_DUMMIES];
668
669 // DDRace
670
671 int m_aLocalIds[NUM_DUMMIES];
672 CNetObj_PlayerInput m_DummyInput;
673 CNetObj_PlayerInput m_HammerInput;
674 unsigned int m_DummyFire;
675 bool m_ReceivedDDNetPlayer;
676 bool m_ReceivedDDNetPlayerFinishTimes;
677 bool m_ReceivedDDNetPlayerFinishTimesMillis;
678
679 CTeamsCore m_Teams;
680
681 int IntersectCharacter(vec2 HookPos, vec2 NewPos, vec2 &NewPos2, int OwnId, vec2 *pPlayerPosition = nullptr);
682
683 int LastRaceTick() const;
684 int CurrentRaceTime() const;
685
686 bool IsTeamPlay() const;
687 bool IsWorldPaused() const;
688 bool IsDemoPlaybackPaused() const;
689 float GetAnimationPlaybackSpeed() const;
690
691 bool AntiPingPlayers() const;
692 bool AntiPingGrenade() const;
693 bool AntiPingWeapons() const;
694 bool AntiPingGunfire() const;
695 bool Predict() const;
696 bool PredictDummy() const;
697
698 const CTuningParams *GetTuning(int i) const { return &m_aTuningList[i]; }
699 ColorRGBA GetDDTeamColor(int DDTeam, float Lightness = 0.5f) const;
700 void FormatClientId(int ClientId, char (&aClientId)[16], EClientIdFormat Format) const;
701
702 CGameWorld m_GameWorld;
703 CGameWorld m_PredictedWorld;
704 CGameWorld m_PrevPredictedWorld;
705
706 std::vector<SSwitchers> &Switchers() { return m_GameWorld.m_Core.m_vSwitchers; }
707 std::vector<SSwitchers> &PredSwitchers() { return m_PredictedWorld.m_Core.m_vSwitchers; }
708
709 void DummyResetInput() override;
710 void Echo(const char *pString) override;
711 bool IsOtherTeam(int ClientId) const;
712 int SwitchStateTeam() const;
713 bool IsLocalCharSuper() const;
714 bool CanDisplayWarning() const override;
715
716 IMap *Map() override { return m_pMap.get(); }
717 const IMap *Map() const override { return m_pMap.get(); }
718 CNetObjHandler *GetNetObjHandler() override;
719 protocol7::CNetObjHandler *GetNetObjHandler7() override;
720
721 void LoadGameSkin(const char *pPath, bool AsDir = false);
722 void LoadEmoticonsSkin(const char *pPath, bool AsDir = false);
723 void LoadParticlesSkin(const char *pPath, bool AsDir = false);
724 void LoadHudSkin(const char *pPath, bool AsDir = false);
725 void LoadExtrasSkin(const char *pPath, bool AsDir = false);
726
727 struct SClientGameSkin
728 {
729 // health armor hud
730 IGraphics::CTextureHandle m_SpriteHealthFull;
731 IGraphics::CTextureHandle m_SpriteHealthEmpty;
732 IGraphics::CTextureHandle m_SpriteArmorFull;
733 IGraphics::CTextureHandle m_SpriteArmorEmpty;
734
735 // cursors
736 IGraphics::CTextureHandle m_SpriteWeaponHammerCursor;
737 IGraphics::CTextureHandle m_SpriteWeaponGunCursor;
738 IGraphics::CTextureHandle m_SpriteWeaponShotgunCursor;
739 IGraphics::CTextureHandle m_SpriteWeaponGrenadeCursor;
740 IGraphics::CTextureHandle m_SpriteWeaponNinjaCursor;
741 IGraphics::CTextureHandle m_SpriteWeaponLaserCursor;
742
743 IGraphics::CTextureHandle m_aSpriteWeaponCursors[6];
744
745 // weapons and hook
746 IGraphics::CTextureHandle m_SpriteHookChain;
747 IGraphics::CTextureHandle m_SpriteHookHead;
748 IGraphics::CTextureHandle m_SpriteWeaponHammer;
749 IGraphics::CTextureHandle m_SpriteWeaponGun;
750 IGraphics::CTextureHandle m_SpriteWeaponShotgun;
751 IGraphics::CTextureHandle m_SpriteWeaponGrenade;
752 IGraphics::CTextureHandle m_SpriteWeaponNinja;
753 IGraphics::CTextureHandle m_SpriteWeaponLaser;
754
755 IGraphics::CTextureHandle m_aSpriteWeapons[6];
756
757 // particles
758 IGraphics::CTextureHandle m_aSpriteParticles[9];
759
760 // stars
761 IGraphics::CTextureHandle m_aSpriteStars[3];
762
763 // projectiles
764 IGraphics::CTextureHandle m_SpriteWeaponGunProjectile;
765 IGraphics::CTextureHandle m_SpriteWeaponShotgunProjectile;
766 IGraphics::CTextureHandle m_SpriteWeaponGrenadeProjectile;
767 IGraphics::CTextureHandle m_SpriteWeaponHammerProjectile;
768 IGraphics::CTextureHandle m_SpriteWeaponNinjaProjectile;
769 IGraphics::CTextureHandle m_SpriteWeaponLaserProjectile;
770
771 IGraphics::CTextureHandle m_aSpriteWeaponProjectiles[6];
772
773 // muzzles
774 IGraphics::CTextureHandle m_aSpriteWeaponGunMuzzles[3];
775 IGraphics::CTextureHandle m_aSpriteWeaponShotgunMuzzles[3];
776 IGraphics::CTextureHandle m_aaSpriteWeaponNinjaMuzzles[3];
777
778 IGraphics::CTextureHandle m_aaSpriteWeaponsMuzzles[6][3];
779
780 // pickups
781 IGraphics::CTextureHandle m_SpritePickupHealth;
782 IGraphics::CTextureHandle m_SpritePickupArmor;
783 IGraphics::CTextureHandle m_SpritePickupArmorShotgun;
784 IGraphics::CTextureHandle m_SpritePickupArmorGrenade;
785 IGraphics::CTextureHandle m_SpritePickupArmorNinja;
786 IGraphics::CTextureHandle m_SpritePickupArmorLaser;
787 IGraphics::CTextureHandle m_SpritePickupGrenade;
788 IGraphics::CTextureHandle m_SpritePickupShotgun;
789 IGraphics::CTextureHandle m_SpritePickupLaser;
790 IGraphics::CTextureHandle m_SpritePickupNinja;
791 IGraphics::CTextureHandle m_SpritePickupGun;
792 IGraphics::CTextureHandle m_SpritePickupHammer;
793
794 IGraphics::CTextureHandle m_aSpritePickupWeapons[6];
795 IGraphics::CTextureHandle m_aSpritePickupWeaponArmor[4];
796
797 // flags
798 IGraphics::CTextureHandle m_SpriteFlagBlue;
799 IGraphics::CTextureHandle m_SpriteFlagRed;
800
801 // ninja bar (0.7)
802 IGraphics::CTextureHandle m_SpriteNinjaBarFullLeft;
803 IGraphics::CTextureHandle m_SpriteNinjaBarFull;
804 IGraphics::CTextureHandle m_SpriteNinjaBarEmpty;
805 IGraphics::CTextureHandle m_SpriteNinjaBarEmptyRight;
806
807 bool IsSixup() const
808 {
809 return m_SpriteNinjaBarFullLeft.IsValid();
810 }
811 };
812
813 SClientGameSkin m_GameSkin;
814 bool m_GameSkinLoaded = false;
815
816 struct SClientParticlesSkin
817 {
818 IGraphics::CTextureHandle m_SpriteParticleSlice;
819 IGraphics::CTextureHandle m_SpriteParticleBall;
820 IGraphics::CTextureHandle m_aSpriteParticleSplat[3];
821 IGraphics::CTextureHandle m_SpriteParticleSmoke;
822 IGraphics::CTextureHandle m_SpriteParticleShell;
823 IGraphics::CTextureHandle m_SpriteParticleExpl;
824 IGraphics::CTextureHandle m_SpriteParticleAirJump;
825 IGraphics::CTextureHandle m_SpriteParticleHit;
826 IGraphics::CTextureHandle m_aSpriteParticles[10];
827 };
828
829 SClientParticlesSkin m_ParticlesSkin;
830 bool m_ParticlesSkinLoaded = false;
831
832 struct SClientEmoticonsSkin
833 {
834 IGraphics::CTextureHandle m_aSpriteEmoticons[16];
835 };
836
837 SClientEmoticonsSkin m_EmoticonsSkin;
838 bool m_EmoticonsSkinLoaded = false;
839
840 struct SClientHudSkin
841 {
842 IGraphics::CTextureHandle m_SpriteHudAirjump;
843 IGraphics::CTextureHandle m_SpriteHudAirjumpEmpty;
844 IGraphics::CTextureHandle m_SpriteHudSolo;
845 IGraphics::CTextureHandle m_SpriteHudCollisionDisabled;
846 IGraphics::CTextureHandle m_SpriteHudEndlessJump;
847 IGraphics::CTextureHandle m_SpriteHudEndlessHook;
848 IGraphics::CTextureHandle m_SpriteHudJetpack;
849 IGraphics::CTextureHandle m_SpriteHudFreezeBarFullLeft;
850 IGraphics::CTextureHandle m_SpriteHudFreezeBarFull;
851 IGraphics::CTextureHandle m_SpriteHudFreezeBarEmpty;
852 IGraphics::CTextureHandle m_SpriteHudFreezeBarEmptyRight;
853 IGraphics::CTextureHandle m_SpriteHudNinjaBarFullLeft;
854 IGraphics::CTextureHandle m_SpriteHudNinjaBarFull;
855 IGraphics::CTextureHandle m_SpriteHudNinjaBarEmpty;
856 IGraphics::CTextureHandle m_SpriteHudNinjaBarEmptyRight;
857 IGraphics::CTextureHandle m_SpriteHudHookHitDisabled;
858 IGraphics::CTextureHandle m_SpriteHudHammerHitDisabled;
859 IGraphics::CTextureHandle m_SpriteHudShotgunHitDisabled;
860 IGraphics::CTextureHandle m_SpriteHudGrenadeHitDisabled;
861 IGraphics::CTextureHandle m_SpriteHudLaserHitDisabled;
862 IGraphics::CTextureHandle m_SpriteHudGunHitDisabled;
863 IGraphics::CTextureHandle m_SpriteHudDeepFrozen;
864 IGraphics::CTextureHandle m_SpriteHudLiveFrozen;
865 IGraphics::CTextureHandle m_SpriteHudTeleportGrenade;
866 IGraphics::CTextureHandle m_SpriteHudTeleportGun;
867 IGraphics::CTextureHandle m_SpriteHudTeleportLaser;
868 IGraphics::CTextureHandle m_SpriteHudPracticeMode;
869 IGraphics::CTextureHandle m_SpriteHudLockMode;
870 IGraphics::CTextureHandle m_SpriteHudTeam0Mode;
871 IGraphics::CTextureHandle m_SpriteHudDummyHammer;
872 IGraphics::CTextureHandle m_SpriteHudDummyCopy;
873 };
874
875 SClientHudSkin m_HudSkin;
876 bool m_HudSkinLoaded = false;
877
878 struct SClientExtrasSkin
879 {
880 IGraphics::CTextureHandle m_SpriteParticleSnowflake;
881 IGraphics::CTextureHandle m_SpriteParticleSparkle;
882 IGraphics::CTextureHandle m_SpritePulley;
883 IGraphics::CTextureHandle m_SpriteHectagon;
884 IGraphics::CTextureHandle m_aSpriteParticles[4];
885 };
886
887 SClientExtrasSkin m_ExtrasSkin;
888 bool m_ExtrasSkinLoaded = false;
889
890 const std::vector<CSnapEntities> &SnapEntities() { return m_vSnapEntities; }
891
892 int m_MultiViewTeam;
893 float m_MultiViewPersonalZoom;
894 bool m_MultiViewShowHud;
895 bool m_MultiViewActivated;
896 bool m_aMultiViewId[MAX_CLIENTS];
897
898 void ResetMultiView();
899 int FindFirstMultiViewId();
900 void CleanMultiViewId(int ClientId);
901 int m_MapBestTimeSeconds;
902 int m_MapBestTimeMillis;
903 char m_aMapDescription[512];
904
905private:
906 std::unique_ptr<IMap> m_pMap;
907
908 std::vector<CSnapEntities> m_vSnapEntities;
909 void SnapCollectEntities();
910
911 bool m_aDDRaceMsgSent[NUM_DUMMIES];
912 int m_aShowOthers[NUM_DUMMIES];
913 int m_aEnableSpectatorCount[NUM_DUMMIES]; // current setting as sent to the server, -1 if not yet sent
914
915 class CImageAsset
916 {
917 public:
918 bool IsLoaded() const { return m_ImageInfo.m_pData != nullptr; }
919
920 char m_aPath[IO_MAX_PATH_LENGTH];
921 bool m_IsDefault;
922 CImageInfo m_ImageInfo;
923 };
924
925 CImageAsset LoadAssetFromPath(const char *pPath, bool AsDir, int AssetId, const char *pDirectory) const;
926
927 std::vector<std::shared_ptr<CManagedTeeRenderInfo>> m_vpManagedTeeRenderInfos;
928 void UpdateManagedTeeRenderInfos();
929
930 void UpdateLocalTuning();
931 void UpdatePrediction();
932 void UpdateSpectatorCursor();
933 void UpdateRenderedCharacters();
934 void HandlePredictedEvents(int Tick);
935
936 void OnInput(const IInput::CEvent &Event);
937
938 int m_aLastUpdateTick[MAX_CLIENTS] = {0};
939 void DetectStrongHook();
940
941 vec2 GetSmoothPos(int ClientId);
942
943 int m_IsDummySwapping;
944 CCharOrder m_CharOrder;
945 int m_aSwitchStateTeam[NUM_DUMMIES];
946
947 void LoadMapSettings();
948 CMapBugs m_MapBugs;
949
950 // tunings for every zone on the map, 0 is a global tune
951 CTuningParams m_aTuningList[TuneZone::NUM];
952 CTuningParams *TuningList() { return m_aTuningList; }
953
954 float m_LastShowDistanceZoom;
955 float m_LastZoom;
956 float m_LastScreenAspect;
957 float m_LastDeadzone;
958 float m_LastFollowFactor;
959 bool m_LastDummyConnected;
960
961 void HandleMultiView();
962 bool IsMultiViewIdSet();
963 void CleanMultiViewIds();
964 bool InitMultiView(int Team);
965 float CalculateMultiViewMultiplier(vec2 TargetPos);
966 float CalculateMultiViewZoom(vec2 MinPos, vec2 MaxPos, float Vel);
967 float MapValue(float MaxValue, float MinValue, float MaxRange, float MinRange, float Value);
968
969 struct SMultiView
970 {
971 bool m_Solo;
972 bool m_IsInit;
973 bool m_Teleported;
974 bool m_aVanish[MAX_CLIENTS];
975 vec2 m_OldPos;
976 int m_OldPersonalZoom;
977 float m_SecondChance;
978 float m_OldCameraDistance;
979 float m_aLastFreeze[MAX_CLIENTS];
980 };
981
982 SMultiView m_MultiView;
983
984 void OnSaveCodeNetMessage(const CNetMsg_Sv_SaveCode *pMsg);
985 void StoreSave(const char *pTeamMembers, const char *pGeneratedCode) const;
986};
987
988ColorRGBA CalculateNameColor(ColorHSLA TextColorHSL);
989
990#endif
991