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 ENGINE_SHARED_CONSOLE_H
4#define ENGINE_SHARED_CONSOLE_H
5
6#include "memheap.h"
7
8#include <engine/console.h>
9#include <engine/storage.h>
10
11#include <optional>
12#include <vector>
13
14class CConsole : public IConsole
15{
16 class CCommand : public ICommandInfo
17 {
18 EAccessLevel m_AccessLevel;
19 CCommand *m_pNext;
20
21 public:
22 const char *m_pName;
23 const char *m_pHelp;
24 const char *m_pParams;
25
26 const CCommand *Next() const { return m_pNext; }
27 CCommand *Next() { return m_pNext; }
28 void SetNext(CCommand *pNext) { m_pNext = pNext; }
29 int m_Flags;
30 bool m_Temp;
31 FCommandCallback m_pfnCallback;
32 void *m_pUserData;
33
34 const char *Name() const override { return m_pName; }
35 const char *Help() const override { return m_pHelp; }
36 const char *Params() const override { return m_pParams; }
37 int Flags() const override { return m_Flags; }
38 EAccessLevel GetAccessLevel() const override { return m_AccessLevel; }
39 void SetAccessLevel(EAccessLevel AccessLevel);
40 };
41
42 class CChain
43 {
44 public:
45 FChainCommandCallback m_pfnChainCallback;
46 FCommandCallback m_pfnCallback;
47 void *m_pCallbackUserData;
48 void *m_pUserData;
49 };
50
51 int m_FlagMask;
52 bool m_StoreCommands;
53 const char *m_apStrokeStr[2];
54 CCommand *m_pFirstCommand;
55
56 class CExecFile
57 {
58 public:
59 const char *m_pFilename;
60 CExecFile *m_pPrev;
61 };
62
63 CExecFile *m_pFirstExec;
64 IStorage *m_pStorage;
65
66 CCommand *m_pRecycleList;
67 CHeap m_TempCommands;
68
69 static void TraverseChain(FCommandCallback *ppfnCallback, void **ppUserData);
70
71 static void Con_Chain(IResult *pResult, void *pUserData);
72 static void Con_Echo(IResult *pResult, void *pUserData);
73 static void Con_Exec(IResult *pResult, void *pUserData);
74 static void ConCommandAccess(IResult *pResult, void *pUser);
75 static void ConCommandStatus(IConsole::IResult *pResult, void *pUser);
76 void PrintCommandList(EAccessLevel MinAccessLevel, int ExcludeFlagMask);
77
78 void ExecuteLineStroked(int Stroke, const char *pStr, int ClientId = IConsole::CLIENT_ID_UNSPECIFIED, bool InterpretSemicolons = true) override;
79
80 FTeeHistorianCommandCallback m_pfnTeeHistorianCommandCallback;
81 void *m_pTeeHistorianCommandUserdata;
82
83 FUnknownCommandCallback m_pfnUnknownCommandCallback = EmptyUnknownCommandCallback;
84 void *m_pUnknownCommandUserdata = nullptr;
85
86 FCanUseCommandCallback m_pfnCanUseCommandCallback = nullptr;
87 void *m_pCanUseCommandUserData;
88
89 bool CanUseCommand(int ClientId, const IConsole::ICommandInfo *pCommand) const;
90
91 enum
92 {
93 CONSOLE_MAX_STR_LENGTH = 8192,
94 MAX_PARTS = (CONSOLE_MAX_STR_LENGTH + 1) / 2
95 };
96
97 class CResult : public IResult
98 {
99 public:
100 char m_aStringStorage[CONSOLE_MAX_STR_LENGTH + 1];
101 char *m_pArgsStart;
102
103 const char *m_pCommand;
104 const char *m_apArgs[MAX_PARTS];
105
106 CResult(int ClientId);
107 CResult(const CResult &Other);
108
109 void AddArgument(const char *pArg);
110 void RemoveArgument(unsigned Index) override;
111
112 const char *GetString(unsigned Index) const override;
113 int GetInteger(unsigned Index) const override;
114 float GetFloat(unsigned Index) const override;
115 ColorHSLA GetColor(unsigned Index, float DarkestLighting) const override;
116
117 // DDRace
118
119 enum
120 {
121 VICTIM_NONE = -3,
122 VICTIM_ME = -2,
123 VICTIM_ALL = -1,
124 };
125
126 int m_Victim;
127 void ResetVictim();
128 bool HasVictim() const;
129 void SetVictim(int Victim);
130 void SetVictim(const char *pVictim);
131 int GetVictim() const override;
132 };
133
134 int ParseStart(CResult *pResult, const char *pString, int Length);
135
136 enum
137 {
138 PARSEARGS_OK = 0,
139 PARSEARGS_MISSING_VALUE,
140 PARSEARGS_INVALID_INTEGER,
141 PARSEARGS_INVALID_COLOR,
142 PARSEARGS_INVALID_FLOAT,
143 };
144
145 int ParseArgs(CResult *pResult, const char *pFormat);
146
147 /*
148 this function will set pFormat to the next parameter (i,s,r,v,?) it contains and
149 return the parameter; descriptions in brackets like [file] will be skipped;
150 returns '\0' if there is no next parameter; expects pFormat to point at a
151 parameter
152 */
153 char NextParam(const char *&pFormat);
154
155 class CExecutionQueueEntry
156 {
157 public:
158 CCommand *m_pCommand;
159 CResult m_Result;
160 CExecutionQueueEntry(CCommand *pCommand, const CResult &Result) :
161 m_pCommand(pCommand),
162 m_Result(Result) {}
163 };
164 std::vector<CExecutionQueueEntry> m_vExecutionQueue;
165
166 void AddCommandSorted(CCommand *pCommand);
167 CCommand *FindCommand(const char *pName, int FlagMask);
168
169 bool m_Cheated;
170
171public:
172 CConsole(int FlagMask);
173 ~CConsole() override;
174
175 void Init() override;
176 const ICommandInfo *FirstCommandInfo(int ClientId, int FlagMask) const override;
177 const ICommandInfo *NextCommandInfo(const IConsole::ICommandInfo *pInfo, int ClientId, int FlagMask) const override;
178 const ICommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp) override;
179 int PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) override;
180
181 void ParseArguments(int NumArgs, const char **ppArguments) override;
182 void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) override;
183 void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) override;
184 void DeregisterTemp(const char *pName) override;
185 void DeregisterTempAll() override;
186 void Chain(const char *pName, FChainCommandCallback pfnChainFunc, void *pUser) override;
187 void StoreCommands(bool Store) override;
188
189 bool LineIsValid(const char *pStr) override;
190 void ExecuteLine(const char *pStr, int ClientId = IConsole::CLIENT_ID_UNSPECIFIED, bool InterpretSemicolons = true) override;
191 void ExecuteLineFlag(const char *pStr, int FlagMask, int ClientId = IConsole::CLIENT_ID_UNSPECIFIED, bool InterpretSemicolons = true) override;
192 bool ExecuteFile(const char *pFilename, int ClientId = IConsole::CLIENT_ID_UNSPECIFIED, bool LogFailure = false, int StorageType = IStorage::TYPE_ALL) override;
193
194 void Print(int Level, const char *pFrom, const char *pStr, ColorRGBA PrintColor = CONSOLE_DEFAULT_COLOR) const override;
195 void SetTeeHistorianCommandCallback(FTeeHistorianCommandCallback pfnCallback, void *pUser) override;
196 void SetUnknownCommandCallback(FUnknownCommandCallback pfnCallback, void *pUser) override;
197 void SetCanUseCommandCallback(FCanUseCommandCallback pfnCallback, void *pUser) override;
198 void InitChecksum(CChecksumData *pData) const override;
199
200 /**
201 * Converts access level string to access level enum.
202 *
203 * @param pAccessLevel should be either "admin", "mod", "moderator", "helper" or "user".
204 * @return `std::nullopt` on error otherwise one of the auth enums such as `EAccessLevel::ADMIN`.
205 */
206 static std::optional<EAccessLevel> AccessLevelToEnum(const char *pAccessLevel);
207
208 /**
209 * Converts access level enum to access level string.
210 *
211 * @param AccessLevel should be one of these: `EAccessLevel::ADMIN`, `EAccessLevel::MODERATOR`, `EAccessLevel::HELPER` or `EAccessLevel::USER`.
212 * @return `nullptr` on error or access level string like "admin".
213 */
214 static const char *AccessLevelToString(EAccessLevel AccessLevel);
215
216 static std::optional<ColorHSLA> ColorParse(const char *pStr, float DarkestLighting);
217
218 // DDRace
219
220 static void ConUserCommandStatus(IConsole::IResult *pResult, void *pUser);
221
222 bool Cheated() const override { return m_Cheated; }
223
224 int FlagMask() const override { return m_FlagMask; }
225 void SetFlagMask(int FlagMask) override { m_FlagMask = FlagMask; }
226};
227
228#endif
229