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_SERVER_GAMECONTEXT_H
4#define GAME_SERVER_GAMECONTEXT_H
5
6#include "eventhandler.h"
7#include "gameworld.h"
8#include "playermapping.h"
9#include "teehistorian.h"
10
11#include <base/types.h>
12
13#include <engine/console.h>
14#include <engine/server.h>
15
16#include <generated/protocol.h>
17
18#include <game/collision.h>
19#include <game/layers.h>
20#include <game/mapbugs.h>
21#include <game/voting.h>
22
23#include <map>
24#include <memory>
25#include <optional>
26#include <string>
27
28/*
29 Tick
30 Game Context (CGameContext::tick)
31 Game World (GAMEWORLD::tick)
32 Reset world if requested (GAMEWORLD::reset)
33 All entities in the world (ENTITY::tick)
34 All entities in the world (ENTITY::tick_deferred)
35 Remove entities marked for deletion (GAMEWORLD::remove_entities)
36 Game Controller (GAMECONTROLLER::tick)
37 All players (CPlayer::tick)
38
39
40 Snap
41 Game Context (CGameContext::snap)
42 Game World (GAMEWORLD::snap)
43 All entities in the world (ENTITY::snap)
44 Game Controller (GAMECONTROLLER::snap)
45 Events handler (EVENT_HANDLER::snap)
46 All players (CPlayer::snap)
47
48*/
49
50class CCharacter;
51class IConfigManager;
52class CConfig;
53class CHeap;
54class CPlayer;
55class CScore;
56class CUnpacker;
57class IAntibot;
58class IGameController;
59class IMap;
60class IEngine;
61class IStorage;
62struct CAntibotRoundData;
63struct CScoreRandomMapResult;
64struct CScorePlayerResult;
65
66struct CSnapContext
67{
68 CSnapContext(int Version, bool Sixup, int ClientId) :
69 m_ClientVersion(Version), m_Sixup(Sixup), m_ClientId(ClientId)
70 {
71 }
72
73 int GetClientVersion() const { return m_ClientVersion; }
74 bool IsSixup() const { return m_Sixup; }
75 int ClientId() const { return m_ClientId; }
76
77private:
78 int m_ClientVersion;
79 bool m_Sixup;
80 int m_ClientId;
81};
82
83class CMute
84{
85public:
86 int64_t m_Expire;
87 bool m_Initialized = false;
88 bool m_InitialDelay;
89 char m_aReason[128];
90 char m_aClientName[MAX_NAME_LENGTH];
91 bool m_NameKnown;
92
93 int SecondsLeft() const;
94};
95
96class CMutes
97{
98public:
99 CMutes(const char *pSystemName);
100
101 bool Mute(const NETADDR *pAddr, int Seconds, const char *pReason, const char *pClientName, bool InitialDelay);
102 void UnmuteIndex(int Index);
103 void UnmuteAddr(const NETADDR *pAddr);
104 void UnmuteExpired();
105 std::optional<CMute> IsMuted(const NETADDR *pAddr, bool RespectInitialDelay) const;
106 void Print(int Page) const;
107
108private:
109 const char *m_pSystemName;
110 std::map<NETADDR, CMute> m_Mutes;
111};
112
113class CGameContext : public IGameServer
114{
115 IServer *m_pServer;
116 IConfigManager *m_pConfigManager;
117 CConfig *m_pConfig;
118 IConsole *m_pConsole;
119 IEngine *m_pEngine;
120 IStorage *m_pStorage;
121 IAntibot *m_pAntibot;
122 std::unique_ptr<IMap> m_pMap;
123 CLayers m_Layers;
124 CCollision m_Collision;
125 protocol7::CNetObjHandler m_NetObjHandler7;
126 CNetObjHandler m_NetObjHandler;
127 CTuningParams m_aTuningList[TuneZone::NUM];
128 std::vector<std::string> m_vCensorlist;
129
130 bool m_TeeHistorianActive;
131 CTeeHistorian m_TeeHistorian;
132 ASYNCIO *m_pTeeHistorianFile;
133 CUuid m_GameUuid;
134 CMapBugs m_MapBugs;
135 CPrng m_Prng;
136
137 bool m_Resetting;
138
139 static std::optional<std::vector<int>> ClientsForVictim(int ClientId, const char *pVictim, void *pUser);
140 static void CommandCallback(int ClientId, int FlagMask, const char *pCmd, IConsole::IResult *pResult, void *pUser);
141 static void TeeHistorianWrite(const void *pData, int DataSize, void *pUser);
142
143 static void ConTuneParam(IConsole::IResult *pResult, void *pUserData);
144 static void ConToggleTuneParam(IConsole::IResult *pResult, void *pUserData);
145 static void ConTuneReset(IConsole::IResult *pResult, void *pUserData);
146 static void ConTunes(IConsole::IResult *pResult, void *pUserData);
147 static void ConTuneZone(IConsole::IResult *pResult, void *pUserData);
148 static void ConTuneDumpZone(IConsole::IResult *pResult, void *pUserData);
149 static void ConTuneResetZone(IConsole::IResult *pResult, void *pUserData);
150 static void ConTuneSetZoneMsgEnter(IConsole::IResult *pResult, void *pUserData);
151 static void ConTuneSetZoneMsgLeave(IConsole::IResult *pResult, void *pUserData);
152 static void ConMapbug(IConsole::IResult *pResult, void *pUserData);
153 static void ConSwitchOpen(IConsole::IResult *pResult, void *pUserData);
154 static void ConPause(IConsole::IResult *pResult, void *pUserData);
155 static void ConChangeMap(IConsole::IResult *pResult, void *pUserData);
156 static void ConRandomMap(IConsole::IResult *pResult, void *pUserData);
157 static void ConRandomUnfinishedMap(IConsole::IResult *pResult, void *pUserData);
158 static void ConRestart(IConsole::IResult *pResult, void *pUserData);
159 static void ConServerAlert(IConsole::IResult *pResult, void *pUserData);
160 static void ConModAlert(IConsole::IResult *pResult, void *pUserData);
161 static void ConBroadcast(IConsole::IResult *pResult, void *pUserData);
162 static void ConSay(IConsole::IResult *pResult, void *pUserData);
163 static void ConSetTeam(IConsole::IResult *pResult, void *pUserData);
164 static void ConSetTeamAll(IConsole::IResult *pResult, void *pUserData);
165 static void ConHotReload(IConsole::IResult *pResult, void *pUserData);
166 static void ConAddVote(IConsole::IResult *pResult, void *pUserData);
167 static void ConRemoveVote(IConsole::IResult *pResult, void *pUserData);
168 static void ConForceVote(IConsole::IResult *pResult, void *pUserData);
169 static void ConClearVotes(IConsole::IResult *pResult, void *pUserData);
170 static void ConAddMapVotes(IConsole::IResult *pResult, void *pUserData);
171 static void ConVote(IConsole::IResult *pResult, void *pUserData);
172 static void ConVotes(IConsole::IResult *pResult, void *pUserData);
173 static void ConVoteNo(IConsole::IResult *pResult, void *pUserData);
174 static void ConDrySave(IConsole::IResult *pResult, void *pUserData);
175 static void ConDumpAntibot(IConsole::IResult *pResult, void *pUserData);
176 static void ConAntibot(IConsole::IResult *pResult, void *pUserData);
177 static void ConchainSpecialMotdupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
178 static void ConchainSettingUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
179 static void ConchainPracticeByDefaultUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
180 static void ConDumpLog(IConsole::IResult *pResult, void *pUserData);
181
182 void AddVote(const char *pDescription, const char *pCommand);
183 static int MapScan(const char *pName, int IsDir, int DirType, void *pUserData);
184
185 class CPersistentData
186 {
187 public:
188 CUuid m_PrevGameUuid;
189 };
190
191 class CPersistentClientData
192 {
193 public:
194 bool m_IsSpectator;
195 bool m_IsAfk;
196 int m_LastWhisperTo;
197 };
198
199public:
200 IServer *Server() const { return m_pServer; }
201 IConfigManager *ConfigManager() const { return m_pConfigManager; }
202 CConfig *Config() { return m_pConfig; }
203 IConsole *Console() { return m_pConsole; }
204 IEngine *Engine() { return m_pEngine; }
205 IStorage *Storage() { return m_pStorage; }
206 IMap *Map() override { return m_pMap.get(); }
207 const IMap *Map() const override { return m_pMap.get(); }
208 CCollision *Collision() { return &m_Collision; }
209 CTuningParams *GlobalTuning() { return &m_aTuningList[0]; }
210 CTuningParams *TuningList() { return m_aTuningList; }
211 IAntibot *Antibot() { return m_pAntibot; }
212 CTeeHistorian *TeeHistorian() { return &m_TeeHistorian; }
213 bool TeeHistorianActive() const { return m_TeeHistorianActive; }
214 CNetObjHandler *GetNetObjHandler() override { return &m_NetObjHandler; }
215 protocol7::CNetObjHandler *GetNetObjHandler7() override { return &m_NetObjHandler7; }
216
217 CGameContext(bool Resetting = false);
218 ~CGameContext() override;
219
220 void Clear();
221
222 CEventHandler m_Events;
223 CPlayer *m_apPlayers[MAX_CLIENTS];
224 // keep last input to always apply when none is sent
225 CNetObj_PlayerInput m_aLastPlayerInput[MAX_CLIENTS];
226 bool m_aPlayerHasInput[MAX_CLIENTS];
227 CSaveTeam *m_apSavedTeams[MAX_CLIENTS];
228 CSaveHotReloadTee *m_apSavedTees[MAX_CLIENTS];
229 int m_aTeamMapping[MAX_CLIENTS];
230
231 // returns last input if available otherwise nulled PlayerInput object
232 // ClientId has to be valid
233 CNetObj_PlayerInput GetLastPlayerInput(int ClientId) const;
234
235 IGameController *m_pController;
236 CGameWorld m_World;
237 CPlayerMapping m_PlayerMapping;
238
239 // helper functions
240 CCharacter *GetPlayerChar(int ClientId);
241 const CCharacter *GetPlayerChar(int ClientId) const;
242 const CPlayer *FindPlayerByName(const char *pName) const;
243 // Returns `nullptr` if no player is found.
244 CPlayer *FindPlayerByName(const char *pName);
245 std::optional<int> FindClientIdByName(const char *pName) const;
246 bool EmulateBug(int Bug) const;
247 std::vector<SSwitchers> &Switchers() { return m_World.m_Core.m_vSwitchers; }
248
249 // voting
250 void StartVote(const char *pDesc, const char *pCommand, const char *pReason, const char *pSixupDesc);
251 void EndVote();
252 void SendVoteSet(int ClientId);
253 void SendVoteStatus(int ClientId, int Total, int Yes, int No);
254 void AbortVoteKickOnDisconnect(int ClientId);
255
256 int m_VoteCreator;
257 int m_VoteType;
258 int64_t m_VoteCloseTime;
259 bool m_VoteUpdate;
260 int m_VotePos;
261 char m_aVoteDescription[VOTE_DESC_LENGTH];
262 char m_aSixupVoteDescription[VOTE_DESC_LENGTH];
263 char m_aVoteCommand[VOTE_CMD_LENGTH];
264 char m_aVoteReason[VOTE_REASON_LENGTH];
265 int m_NumVoteOptions;
266 int m_VoteEnforce;
267 char m_aaZoneEnterMsg[TuneZone::NUM][256]; // 0 is used for switching from or to area without tunings
268 char m_aaZoneLeaveMsg[TuneZone::NUM][256];
269
270 void CreateAllEntities(bool Initial);
271 CPlayer *CreatePlayer(int ClientId, int StartTeam, bool Afk, int LastWhisperTo);
272
273 char m_aDeleteTempfile[128];
274 void DeleteTempfile();
275
276 enum
277 {
278 VOTE_ENFORCE_UNKNOWN = 0,
279 VOTE_ENFORCE_NO,
280 VOTE_ENFORCE_YES,
281 VOTE_ENFORCE_NO_ADMIN,
282 VOTE_ENFORCE_YES_ADMIN,
283 VOTE_ENFORCE_ABORT,
284 VOTE_ENFORCE_CANCEL,
285 };
286 CHeap *m_pVoteOptionHeap;
287 CVoteOptionServer *m_pVoteOptionFirst;
288 CVoteOptionServer *m_pVoteOptionLast;
289
290 // helper functions
291 void CreateDamageInd(vec2 Pos, float AngleMod, int Amount, CClientMask Mask = CClientMask().set());
292 void CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int ActivatedTeam, CClientMask Mask = CClientMask().set());
293 void CreateHammerHit(vec2 Pos, CClientMask Mask = CClientMask().set());
294 void CreatePlayerSpawn(vec2 Pos, CClientMask Mask = CClientMask().set());
295 void CreateDeath(vec2 Pos, int ClientId, CClientMask Mask = CClientMask().set());
296 void CreateBirthdayEffect(vec2 Pos, CClientMask Mask = CClientMask().set());
297 void CreateFinishEffect(vec2 Pos, CClientMask Mask = CClientMask().set());
298 void CreateSound(vec2 Pos, int Sound, CClientMask Mask = CClientMask().set());
299 void CreateSoundGlobal(int Sound, int Target = -1) const;
300
301 void SnapSwitchers(int SnappingClient);
302 void SnapLaserObject(const CSnapContext &Context, int SnapId, const vec2 &To, const vec2 &From, int StartTick, int Owner = -1, int LaserType = -1, int Subtype = -1, int SwitchNumber = -1) const;
303 void SnapPickup(const CSnapContext &Context, int SnapId, const vec2 &Pos, int Type, int SubType, int SwitchNumber, int Flags) const;
304
305 enum
306 {
307 FLAG_SIX = 1 << 0,
308 FLAG_SIXUP = 1 << 1,
309 };
310
311 // network
312 void CallVote(int ClientId, const char *pDesc, const char *pCmd, const char *pReason, const char *pChatmsg, const char *pSixupDesc = nullptr);
313 void SendChatTarget(int To, const char *pText, int VersionFlags = FLAG_SIX | FLAG_SIXUP) const;
314 void SendChatTeam(int Team, const char *pText) const;
315 void SendChat(int ClientId, int Team, const char *pText, int SpamProtectionClientId = -1, int VersionFlags = FLAG_SIX | FLAG_SIXUP);
316 void SendStartWarning(int ClientId, const char *pMessage);
317 void SendEmoticon(int ClientId, int Emoticon, int TargetClientId) const;
318 void SendWeaponPickup(int ClientId, int Weapon) const;
319 void SendMotd(int ClientId) const;
320 void SendSettings(int ClientId) const;
321 void SendServerAlert(const char *pMessage);
322 void SendModeratorAlert(int ToClientId, const char *pMessage);
323 void SendBroadcast(const char *pText, int ClientId, bool IsImportant = true);
324
325 /**
326 * The 0.7 protocol does not support renaming connected clients (or changing clan/country).
327 * But the 0.6 protocol does allow that. And the server supports both.
328 * So when a 0.6 client renames we update the state for 0.7 clients
329 * by reconnecting the renamed client. This is abstracted away by this method.
330 * During the reconnect also other properties than name are being resent and potentially
331 * updated. Those are: name, country, clan, team and skin
332 *
333 * @param ClientId This is the id of the client that will be updated. Not the id that will receive the message. The message gets broadcasted to all 0.7 clients.
334 */
335 void SendRename7(int ClientId);
336 void SendSkinChange7(int ClientId);
337
338 void List(int ClientId, const char *pFilter);
339
340 void SendTuningParams(int ClientId, int Zone = 0);
341
342 const CVoteOptionServer *GetVoteOption(int Index) const;
343 void ProgressVoteOptions(int ClientId);
344
345 //
346 void LoadMapSettings();
347
348 // engine events
349 void OnInit(const void *pPersistentData) override;
350 void OnConsoleInit() override;
351 void RegisterDDRaceCommands();
352 void RegisterChatCommands();
353 [[nodiscard]] bool OnMapChange(char *pNewMapName, int MapNameSize) override;
354 void OnShutdown(void *pPersistentData) override;
355
356 void OnTick() override;
357 void OnSnap(int ClientId, bool GlobalSnap, bool RecordingDemo) override;
358 void OnPostGlobalSnap() override;
359
360 void *PreProcessMsg(int *pMsgId, CUnpacker *pUnpacker, int ClientId);
361 void CensorMessage(char *pCensoredMessage, const char *pMessage, int Size);
362 void OnMessage(int MsgId, CUnpacker *pUnpacker, int ClientId) override;
363 void OnSayNetMessage(const CNetMsg_Cl_Say *pMsg, int ClientId, const CUnpacker *pUnpacker);
364 void OnCallVoteNetMessage(const CNetMsg_Cl_CallVote *pMsg, int ClientId);
365 void OnVoteNetMessage(const CNetMsg_Cl_Vote *pMsg, int ClientId);
366 void OnSetTeamNetMessage(const CNetMsg_Cl_SetTeam *pMsg, int ClientId);
367 void OnIsDDNetLegacyNetMessage(const CNetMsg_Cl_IsDDNetLegacy *pMsg, int ClientId, CUnpacker *pUnpacker);
368 void OnShowOthersLegacyNetMessage(const CNetMsg_Cl_ShowOthersLegacy *pMsg, int ClientId);
369 void OnShowOthersNetMessage(const CNetMsg_Cl_ShowOthers *pMsg, int ClientId);
370 void OnShowDistanceNetMessage(const CNetMsg_Cl_ShowDistance *pMsg, int ClientId);
371 void OnCameraInfoNetMessage(const CNetMsg_Cl_CameraInfo *pMsg, int ClientId);
372 void OnSetSpectatorModeNetMessage(const CNetMsg_Cl_SetSpectatorMode *pMsg, int ClientId);
373 void OnChangeInfoNetMessage(const CNetMsg_Cl_ChangeInfo *pMsg, int ClientId);
374 void OnEmoticonNetMessage(const CNetMsg_Cl_Emoticon *pMsg, int ClientId);
375 void OnKillNetMessage(const CNetMsg_Cl_Kill *pMsg, int ClientId);
376 void OnEnableSpectatorCountNetMessage(const CNetMsg_Cl_EnableSpectatorCount *pMsg, int ClientId);
377 void OnStartInfoNetMessage(const CNetMsg_Cl_StartInfo *pMsg, int ClientId);
378
379 bool OnClientDataPersist(int ClientId, void *pData) override;
380 void OnClientConnected(int ClientId, void *pData) override;
381 void OnClientEnter(int ClientId) override;
382 void OnClientDrop(int ClientId, const char *pReason) override;
383 void OnClientPrepareInput(int ClientId, void *pInput) override;
384 void OnClientDirectInput(int ClientId, const void *pInput) override;
385 void OnClientPredictedInput(int ClientId, const void *pInput) override;
386 void OnClientPredictedEarlyInput(int ClientId, const void *pInput) override;
387
388 void PreInputClients(int ClientId, bool *pClients) override;
389
390 void TeehistorianRecordAntibot(const void *pData, int DataSize) override;
391 void TeehistorianRecordPlayerJoin(int ClientId, bool Sixup) override;
392 void TeehistorianRecordPlayerDrop(int ClientId, const char *pReason) override;
393 void TeehistorianRecordPlayerRejoin(int ClientId) override;
394 void TeehistorianRecordPlayerName(int ClientId, const char *pName) override;
395 void TeehistorianRecordPlayerFinish(int ClientId, int TimeTicks) override;
396 void TeehistorianRecordTeamFinish(int TeamId, int TimeTicks) override;
397 void TeehistorianRecordAuthLogin(int ClientId, int Level, const char *pAuthName) override;
398
399 bool IsClientReady(int ClientId) const override;
400 bool IsClientPlayer(int ClientId) const override;
401 // Whether the client is allowed to have high bandwidth.
402 bool IsClientHighBandwidth(int ClientId) const override;
403 int PersistentDataSize() const override { return sizeof(CPersistentData); }
404 int PersistentClientDataSize() const override { return sizeof(CPersistentClientData); }
405
406 CUuid GameUuid() const override;
407 const char *GameType() const override;
408 char m_aVersionString[32];
409 const char *Version() const override;
410 const char *NetVersion() const override;
411
412 // DDRace
413 void OnPreTickTeehistorian() override;
414 bool OnClientDDNetVersionKnown(int ClientId);
415 void FillAntibot(CAntibotRoundData *pData) override;
416 bool ProcessSpamProtection(int ClientId, bool RespectChatInitialDelay = true);
417 int GetDDRaceTeam(int ClientId) const;
418 // Describes the time when the first player joined the server.
419 int64_t m_NonEmptySince;
420 int64_t m_LastMapVote;
421 int GetClientVersion(int ClientId) const;
422 CClientMask ClientsMaskExcludeClientVersionAndHigher(int Version) const;
423 bool PlayerExists(int ClientId) const override { return m_apPlayers[ClientId]; }
424 // Returns true if someone is actively moderating.
425 bool PlayerModerating() const;
426 void ForceVote(bool Success);
427
428 // Checks if player can vote and notify them about the reason
429 bool RateLimitPlayerVote(int ClientId);
430 bool RateLimitPlayerMapVote(int ClientId) const;
431
432 void OnUpdatePlayerServerInfo(CJsonWriter *pJsonWriter, int ClientId) override;
433 void ReadCensorList();
434
435 bool PracticeByDefault() const;
436
437 std::shared_ptr<CScoreRandomMapResult> m_SqlRandomMapResult;
438
439 // cached map info from database
440 std::shared_ptr<CScorePlayerResult> m_pLoadMapInfoResult;
441 char m_aMapInfoMessage[512];
442
443private:
444 // starting 1 to make 0 the special value "no client id"
445 uint32_t m_NextUniqueClientId = 1;
446 bool m_VoteWillPass;
447 CScore *m_pScore;
448
449 // DDRace Console Commands
450
451 static void ConKillPlayer(IConsole::IResult *pResult, void *pUserData);
452
453 static void ConNinja(IConsole::IResult *pResult, void *pUserData);
454 static void ConUnNinja(IConsole::IResult *pResult, void *pUserData);
455 static void ConEndlessHook(IConsole::IResult *pResult, void *pUserData);
456 static void ConUnEndlessHook(IConsole::IResult *pResult, void *pUserData);
457 static void ConSolo(IConsole::IResult *pResult, void *pUserData);
458 static void ConUnSolo(IConsole::IResult *pResult, void *pUserData);
459 static void ConFreeze(IConsole::IResult *pResult, void *pUserData);
460 static void ConUnfreeze(IConsole::IResult *pResult, void *pUserData);
461 static void ConDeep(IConsole::IResult *pResult, void *pUserData);
462 static void ConUnDeep(IConsole::IResult *pResult, void *pUserData);
463 static void ConLiveFreeze(IConsole::IResult *pResult, void *pUserData);
464 static void ConUnLiveFreeze(IConsole::IResult *pResult, void *pUserData);
465 static void ConUnSuper(IConsole::IResult *pResult, void *pUserData);
466 static void ConSuper(IConsole::IResult *pResult, void *pUserData);
467 static void ConToggleInvincible(IConsole::IResult *pResult, void *pUserData);
468 static void ConShotgun(IConsole::IResult *pResult, void *pUserData);
469 static void ConGrenade(IConsole::IResult *pResult, void *pUserData);
470 static void ConLaser(IConsole::IResult *pResult, void *pUserData);
471 static void ConJetpack(IConsole::IResult *pResult, void *pUserData);
472 static void ConEndlessJump(IConsole::IResult *pResult, void *pUserData);
473 static void ConSetJumps(IConsole::IResult *pResult, void *pUserData);
474 static void ConWeapons(IConsole::IResult *pResult, void *pUserData);
475 static void ConUnShotgun(IConsole::IResult *pResult, void *pUserData);
476 static void ConUnGrenade(IConsole::IResult *pResult, void *pUserData);
477 static void ConUnLaser(IConsole::IResult *pResult, void *pUserData);
478 static void ConUnJetpack(IConsole::IResult *pResult, void *pUserData);
479 static void ConUnEndlessJump(IConsole::IResult *pResult, void *pUserData);
480 static void ConSetSwitch(IConsole::IResult *pResult, void *pUserData);
481 static void ConUnWeapons(IConsole::IResult *pResult, void *pUserData);
482 static void ConAddWeapon(IConsole::IResult *pResult, void *pUserData);
483 static void ConRemoveWeapon(IConsole::IResult *pResult, void *pUserData);
484 void ModifyWeapons(IConsole::IResult *pResult, void *pUserData, int Weapon, bool Remove);
485 void MoveCharacter(int ClientId, int X, int Y, bool Raw = false);
486 static void ConGoLeft(IConsole::IResult *pResult, void *pUserData);
487 static void ConGoRight(IConsole::IResult *pResult, void *pUserData);
488 static void ConGoUp(IConsole::IResult *pResult, void *pUserData);
489 static void ConGoDown(IConsole::IResult *pResult, void *pUserData);
490 static void ConMove(IConsole::IResult *pResult, void *pUserData);
491 static void ConMoveRaw(IConsole::IResult *pResult, void *pUserData);
492
493 static void ConToTeleporter(IConsole::IResult *pResult, void *pUserData);
494 static void ConToCheckTeleporter(IConsole::IResult *pResult, void *pUserData);
495 void Teleport(CCharacter *pChr, vec2 Pos);
496 static void ConTeleport(IConsole::IResult *pResult, void *pUserData);
497
498 static void ConInfo(IConsole::IResult *pResult, void *pUserData);
499 static void ConHelp(IConsole::IResult *pResult, void *pUserData);
500 static void ConSettings(IConsole::IResult *pResult, void *pUserData);
501 static void ConRules(IConsole::IResult *pResult, void *pUserData);
502 static void ConKill(IConsole::IResult *pResult, void *pUserData);
503 static void ConTogglePause(IConsole::IResult *pResult, void *pUserData);
504 static void ConTogglePauseVoted(IConsole::IResult *pResult, void *pUserData);
505 static void ConToggleSpec(IConsole::IResult *pResult, void *pUserData);
506 static void ConToggleSpecVoted(IConsole::IResult *pResult, void *pUserData);
507 static void ConForcePause(IConsole::IResult *pResult, void *pUserData);
508 static void ConTeamTop5(IConsole::IResult *pResult, void *pUserData);
509 static void ConTop(IConsole::IResult *pResult, void *pUserData);
510 static void ConTimes(IConsole::IResult *pResult, void *pUserData);
511 static void ConPoints(IConsole::IResult *pResult, void *pUserData);
512 static void ConTopPoints(IConsole::IResult *pResult, void *pUserData);
513 static void ConTimeCP(IConsole::IResult *pResult, void *pUserData);
514
515 static void ConDND(IConsole::IResult *pResult, void *pUserData);
516 static void ConWhispers(IConsole::IResult *pResult, void *pUserData);
517 static void ConMapInfo(IConsole::IResult *pResult, void *pUserData);
518 static void ConTimeout(IConsole::IResult *pResult, void *pUserData);
519 static void ConPractice(IConsole::IResult *pResult, void *pUserData);
520 static void ConUnPractice(IConsole::IResult *pResult, void *pUserData);
521 static void ConPracticeCmdList(IConsole::IResult *pResult, void *pUserData);
522 static void ConSwap(IConsole::IResult *pResult, void *pUserData);
523 static void ConCancelSwap(IConsole::IResult *pResult, void *pUserData);
524 static void ConSave(IConsole::IResult *pResult, void *pUserData);
525 static void ConLoad(IConsole::IResult *pResult, void *pUserData);
526 static void ConMap(IConsole::IResult *pResult, void *pUserData);
527 static void ConTeamRank(IConsole::IResult *pResult, void *pUserData);
528 static void ConRank(IConsole::IResult *pResult, void *pUserData);
529 static void ConTeam(IConsole::IResult *pResult, void *pUserData);
530 static void ConLock(IConsole::IResult *pResult, void *pUserData);
531 static void ConUnlock(IConsole::IResult *pResult, void *pUserData);
532 static void ConInvite(IConsole::IResult *pResult, void *pUserData);
533 static void ConJoin(IConsole::IResult *pResult, void *pUserData);
534 static void ConTeam0Mode(IConsole::IResult *pResult, void *pUserData);
535 static void ConWhisper(IConsole::IResult *pResult, void *pUserData);
536 static void ConConverse(IConsole::IResult *pResult, void *pUserData);
537 static void ConSetEyeEmote(IConsole::IResult *pResult, void *pUserData);
538 static void ConEyeEmote(IConsole::IResult *pResult, void *pUserData);
539 static void ConShowOthers(IConsole::IResult *pResult, void *pUserData);
540 static void ConShowAll(IConsole::IResult *pResult, void *pUserData);
541 static void ConSpecTeam(IConsole::IResult *pResult, void *pUserData);
542 static void ConNinjaJetpack(IConsole::IResult *pResult, void *pUserData);
543 static void ConSayTime(IConsole::IResult *pResult, void *pUserData);
544 static void ConSayTimeAll(IConsole::IResult *pResult, void *pUserData);
545 static void ConTime(IConsole::IResult *pResult, void *pUserData);
546 static void ConSetTimerType(IConsole::IResult *pResult, void *pUserData);
547 static void ConRescue(IConsole::IResult *pResult, void *pUserData);
548 static void ConRescueMode(IConsole::IResult *pResult, void *pUserData);
549 static void ConBack(IConsole::IResult *pResult, void *pUserData);
550 static void ConTeleTo(IConsole::IResult *pResult, void *pUserData);
551 static void ConTeleXY(IConsole::IResult *pResult, void *pUserData);
552 static void ConTeleCursor(IConsole::IResult *pResult, void *pUserData);
553 static void ConLastTele(IConsole::IResult *pResult, void *pUserData);
554
555 // Chat commands for practice mode
556 static void ConPracticeToTeleporter(IConsole::IResult *pResult, void *pUserData);
557 static void ConPracticeToCheckTeleporter(IConsole::IResult *pResult, void *pUserData);
558 static void ConPracticeUnSolo(IConsole::IResult *pResult, void *pUserData);
559 static void ConPracticeSolo(IConsole::IResult *pResult, void *pUserData);
560 static void ConPracticeUnDeep(IConsole::IResult *pResult, void *pUserData);
561 static void ConPracticeDeep(IConsole::IResult *pResult, void *pUserData);
562 static void ConPracticeUnLiveFreeze(IConsole::IResult *pResult, void *pUserData);
563 static void ConPracticeLiveFreeze(IConsole::IResult *pResult, void *pUserData);
564 static void ConPracticeShotgun(IConsole::IResult *pResult, void *pUserData);
565 static void ConPracticeGrenade(IConsole::IResult *pResult, void *pUserData);
566 static void ConPracticeLaser(IConsole::IResult *pResult, void *pUserData);
567 static void ConPracticeJetpack(IConsole::IResult *pResult, void *pUserData);
568 static void ConPracticeEndlessJump(IConsole::IResult *pResult, void *pUserData);
569 static void ConPracticeSetJumps(IConsole::IResult *pResult, void *pUserData);
570 static void ConPracticeWeapons(IConsole::IResult *pResult, void *pUserData);
571 static void ConPracticeUnShotgun(IConsole::IResult *pResult, void *pUserData);
572 static void ConPracticeUnGrenade(IConsole::IResult *pResult, void *pUserData);
573 static void ConPracticeUnLaser(IConsole::IResult *pResult, void *pUserData);
574 static void ConPracticeUnJetpack(IConsole::IResult *pResult, void *pUserData);
575 static void ConPracticeUnEndlessJump(IConsole::IResult *pResult, void *pUserData);
576 static void ConPracticeUnWeapons(IConsole::IResult *pResult, void *pUserData);
577 static void ConPracticeNinja(IConsole::IResult *pResult, void *pUserData);
578 static void ConPracticeUnNinja(IConsole::IResult *pResult, void *pUserData);
579 static void ConPracticeEndlessHook(IConsole::IResult *pResult, void *pUserData);
580 static void ConPracticeUnEndlessHook(IConsole::IResult *pResult, void *pUserData);
581 static void ConPracticeSetSwitch(IConsole::IResult *pResult, void *pUserData);
582 static void ConPracticeToggleInvincible(IConsole::IResult *pResult, void *pUserData);
583 static void ConPracticeToggleCollision(IConsole::IResult *pResult, void *pUserData);
584 static void ConPracticeToggleHookCollision(IConsole::IResult *pResult, void *pUserData);
585 static void ConPracticeToggleHitOthers(IConsole::IResult *pResult, void *pUserData);
586
587 static void ConPracticeAddWeapon(IConsole::IResult *pResult, void *pUserData);
588 static void ConPracticeRemoveWeapon(IConsole::IResult *pResult, void *pUserData);
589
590 static void ConProtectedKill(IConsole::IResult *pResult, void *pUserData);
591 static void ConModerate(IConsole::IResult *pResult, void *pUserData);
592
593 static void ConList(IConsole::IResult *pResult, void *pUserData);
594 static void ConSetDDRTeam(IConsole::IResult *pResult, void *pUserData);
595 static void ConUninvite(IConsole::IResult *pResult, void *pUserData);
596
597 static void ConReloadCensorlist(IConsole::IResult *pResult, void *pUserData);
598
599 CCharacter *GetPracticeCharacter(IConsole::IResult *pResult);
600
601 CMutes m_Mutes;
602 CMutes m_VoteMutes;
603 void MuteWithMessage(const NETADDR *pAddr, int Seconds, const char *pReason, const char *pDisplayName);
604 void VoteMuteWithMessage(const NETADDR *pAddr, int Seconds, const char *pReason, const char *pDisplayName);
605
606 static void ConMute(IConsole::IResult *pResult, void *pUserData);
607 static void ConMuteId(IConsole::IResult *pResult, void *pUserData);
608 static void ConMuteIp(IConsole::IResult *pResult, void *pUserData);
609 static void ConUnmute(IConsole::IResult *pResult, void *pUserData);
610 static void ConUnmuteId(IConsole::IResult *pResult, void *pUserData);
611 static void ConUnmuteIp(IConsole::IResult *pResult, void *pUserData);
612 static void ConMutes(IConsole::IResult *pResult, void *pUserData);
613
614 static void ConVoteMute(IConsole::IResult *pResult, void *pUserData);
615 static void ConVoteMuteId(IConsole::IResult *pResult, void *pUserData);
616 static void ConVoteMuteIp(IConsole::IResult *pResult, void *pUserData);
617 static void ConVoteUnmute(IConsole::IResult *pResult, void *pUserData);
618 static void ConVoteUnmuteId(IConsole::IResult *pResult, void *pUserData);
619 static void ConVoteUnmuteIp(IConsole::IResult *pResult, void *pUserData);
620 static void ConVoteMutes(IConsole::IResult *pResult, void *pUserData);
621
622 void Whisper(int ClientId, char *pStr);
623 int WhisperRecordFlag(int ClientId) const;
624 void WhisperId(int ClientId, int VictimId, const char *pMessage);
625 void Converse(int ClientId, char *pStr);
626 bool IsVersionBanned(int Version);
627 void UnlockTeam(int ClientId, int Team) const;
628 void AttemptJoinTeam(int ClientId, int Team);
629
630 enum
631 {
632 MAX_LOG_SECONDS = 600,
633 MAX_LOGS = 512,
634 };
635 struct CLog
636 {
637 int64_t m_Timestamp;
638 bool m_FromServer;
639 char m_aDescription[256 + 8];
640 int m_ClientVersion;
641 char m_aClientName[MAX_NAME_LENGTH];
642 char m_aClientAddrStr[NETADDR_MAXSTRSIZE];
643 };
644 CLog m_aLogs[MAX_LOGS];
645 int m_LatestLog;
646
647 void LogEvent(const char *Description, int ClientId);
648
649public:
650 CLayers *Layers() { return &m_Layers; }
651 CScore *Score() { return m_pScore; }
652
653 enum
654 {
655 VOTE_TYPE_UNKNOWN = 0,
656 VOTE_TYPE_OPTION,
657 VOTE_TYPE_KICK,
658 VOTE_TYPE_SPECTATE,
659 };
660 int m_VoteVictim;
661
662 bool IsOptionVote() const { return m_VoteType == VOTE_TYPE_OPTION; }
663 bool IsKickVote() const { return m_VoteType == VOTE_TYPE_KICK; }
664 bool IsSpecVote() const { return m_VoteType == VOTE_TYPE_SPECTATE; }
665
666 bool IsRunningVote(int ClientId) const;
667 bool IsRunningKickOrSpecVote(int ClientId) const;
668
669 void SendRecord(int ClientId);
670 void SendFinish(int ClientId, float Time, std::optional<float> PreviousBestTime);
671 void SendSaveCode(int Team, int TeamSize, int State, const char *pError, const char *pSaveRequester, const char *pServerName, const char *pGeneratedCode, const char *pCode);
672 void OnSetAuthed(int ClientId, int Level) override;
673 void OnSetTimedOut(int ClientId) override;
674
675 void ResetTuning();
676};
677
678static inline bool CheckClientId(int ClientId)
679{
680 return ClientId >= 0 && ClientId < MAX_CLIENTS;
681}
682
683#endif
684