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