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