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