| 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 | |
| 74 | class CGameInfo |
| 75 | { |
| 76 | public: |
| 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 | |
| 122 | class CSnapEntities |
| 123 | { |
| 124 | public: |
| 125 | IClient::CSnapItem m_Item; |
| 126 | const CNetObj_EntityEx *m_pDataEx; |
| 127 | }; |
| 128 | |
| 129 | enum class EClientIdFormat |
| 130 | { |
| 131 | NO_INDENT, |
| 132 | INDENT_AUTO, |
| 133 | INDENT_FORCE, // for rendering settings preview |
| 134 | }; |
| 135 | |
| 136 | class CGameClient : public IGameClient |
| 137 | { |
| 138 | public: |
| 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 ; |
| 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 ; |
| 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 | |
| 189 | private: |
| 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 (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 | |
| 265 | public: |
| 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 (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 |
| 853 | { |
| 854 | IGraphics::CTextureHandle m_SpriteParticleSnowflake; |
| 855 | IGraphics::CTextureHandle m_SpriteParticleSparkle; |
| 856 | IGraphics::CTextureHandle ; |
| 857 | IGraphics::CTextureHandle ; |
| 858 | IGraphics::CTextureHandle m_aSpriteParticles[4]; |
| 859 | }; |
| 860 | |
| 861 | SClientExtrasSkin ; |
| 862 | bool = 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 | |
| 876 | private: |
| 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 | |
| 942 | ColorRGBA CalculateNameColor(ColorHSLA TextColorHSL); |
| 943 | |
| 944 | #endif |
| 945 | |