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