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_COMPONENTS_CONSOLE_H
4#define GAME_CLIENT_COMPONENTS_CONSOLE_H
5
6#include <base/lock.h>
7
8#include <engine/console.h>
9#include <engine/shared/ringbuffer.h>
10
11#include <game/client/component.h>
12#include <game/client/lineinput.h>
13#include <game/client/ui.h>
14
15enum
16{
17 CONSOLE_CLOSED,
18 CONSOLE_OPENING,
19 CONSOLE_OPEN,
20 CONSOLE_CLOSING,
21};
22
23class CConsoleLogger;
24
25class CGameConsole : public CComponent
26{
27 friend class CConsoleLogger;
28 class CInstance
29 {
30 public:
31 struct CBacklogEntry
32 {
33 float m_YOffset;
34 int m_LineCount;
35 ColorRGBA m_PrintColor;
36 size_t m_Length;
37 char m_aText[1];
38 };
39 CStaticRingBuffer<CBacklogEntry, 1024 * 1024, CRingBufferBase::FLAG_RECYCLE> m_Backlog;
40 CLock m_BacklogPendingLock;
41 CStaticRingBuffer<CBacklogEntry, 1024 * 1024, CRingBufferBase::FLAG_RECYCLE> m_BacklogPending GUARDED_BY(m_BacklogPendingLock);
42 CStaticRingBuffer<char, 64 * 1024, CRingBufferBase::FLAG_RECYCLE> m_History;
43 char *m_pHistoryEntry;
44
45 CLineInputBuffered<IConsole::CMDLINE_LENGTH> m_Input;
46 const char *m_pName;
47 int m_Type;
48 int m_BacklogCurLine;
49 int m_BacklogLastActiveLine = -1;
50 int m_LinesRendered;
51
52 STextBoundingBox m_BoundingBox = {.m_X: 0.0f, .m_Y: 0.0f, .m_W: 0.0f, .m_H: 0.0f};
53 float m_LastInputHeight = 0.0f;
54
55 bool m_MouseIsPress = false;
56 vec2 m_MousePress = vec2(0.0f, 0.0f);
57 vec2 m_MouseRelease = vec2(0.0f, 0.0f);
58 int m_CurSelStart = 0;
59 int m_CurSelEnd = 0;
60 bool m_HasSelection = false;
61 int m_NewLineCounter = 0;
62
63 CGameConsole *m_pGameConsole;
64
65 char m_aCompletionBuffer[IConsole::CMDLINE_LENGTH];
66 int m_CompletionChosen;
67 char m_aCompletionBufferArgument[IConsole::CMDLINE_LENGTH];
68 int m_CompletionChosenArgument;
69 int m_CompletionFlagmask;
70 float m_CompletionRenderOffset;
71 float m_CompletionRenderOffsetChange;
72 int m_CompletionArgumentPosition;
73 int m_CompletionCommandStart = 0;
74 int m_CompletionCommandEnd = 0;
75
76 char m_aUser[64];
77 bool m_UserGot;
78 bool m_UsernameReq;
79
80 bool m_IsCommand;
81 const char *m_pCommandName;
82 const char *m_pCommandHelp;
83 const char *m_pCommandParams;
84
85 bool m_CompletionDirty;
86 bool m_QueueResetAnimation;
87 std::vector<const char *> m_vpCommandSuggestions;
88 std::vector<const char *> m_vpArgumentSuggestions;
89
90 bool m_Searching = false;
91 struct SSearchMatch
92 {
93 int m_Pos;
94 int m_StartLine;
95 int m_EndLine;
96 int m_EntryLine;
97
98 SSearchMatch(int Pos, int StartLine, int EndLine, int EntryLine) :
99 m_Pos(Pos), m_StartLine(StartLine), m_EndLine(EndLine), m_EntryLine(EntryLine) {}
100 };
101 int m_CurrentMatchIndex;
102 char m_aCurrentSearchString[IConsole::CMDLINE_LENGTH];
103 std::vector<SSearchMatch> m_vSearchMatches;
104
105 CInstance(int t);
106 void Init(CGameConsole *pGameConsole);
107
108 void ClearBacklog() REQUIRES(!m_BacklogPendingLock);
109 void UpdateBacklogTextAttributes();
110 void PumpBacklogPending() REQUIRES(!m_BacklogPendingLock);
111 void ClearHistory();
112 void Reset();
113
114 void ExecuteLine(const char *pLine);
115
116 bool OnInput(const IInput::CEvent &Event);
117 void PrintLine(const char *pLine, int Len, ColorRGBA PrintColor) REQUIRES(!m_BacklogPendingLock);
118 int GetLinesToScroll(int Direction, int LinesToScroll);
119 void ScrollToCenter(int StartLine, int EndLine);
120 void Dump() REQUIRES(!m_BacklogPendingLock);
121
122 const char *GetString() const { return m_Input.GetString(); }
123 /**
124 * Gets the command at the current cursor including surrounding spaces.
125 * Commands are split by semicolons.
126 *
127 * So if the current console input is for example "hello; world ;foo"
128 * ^
129 * and the cursor is here -------------/
130 * The result would be " world "
131 *
132 * @param pInput the console input line
133 * @param aCmd the command the cursor is at
134 */
135 void GetCommand(const char *pInput, char (&aCmd)[IConsole::CMDLINE_LENGTH]);
136 static void PossibleCommandsCompleteCallback(int Index, const char *pStr, void *pUser);
137 static void PossibleArgumentsCompleteCallback(int Index, const char *pStr, void *pUser);
138
139 void UpdateEntryTextAttributes(CBacklogEntry *pEntry) const;
140
141 bool IsInputHidden() const;
142 void UpdateCompletionSuggestions();
143
144 private:
145 void SetSearching(bool Searching);
146 void ClearSearch();
147 void UpdateSearch();
148
149 friend class CGameConsole;
150 };
151
152 class IConsole *m_pConsole;
153 CConsoleLogger *m_pConsoleLogger = nullptr;
154
155 CInstance m_LocalConsole;
156 CInstance m_RemoteConsole;
157
158 CInstance *ConsoleForType(int ConsoleType);
159 CInstance *CurrentConsole();
160
161 int m_ConsoleType;
162 int m_ConsoleState;
163 float m_StateChangeEnd;
164 float m_StateChangeDuration;
165
166 bool m_WantsSelectionCopy = false;
167 CUi::CTouchState m_TouchState;
168
169 static constexpr ColorRGBA ms_SearchHighlightColor = ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f);
170 static constexpr ColorRGBA ms_SearchSelectedColor = ColorRGBA(1.0f, 1.0f, 0.0f, 1.0f);
171
172 int PossibleMaps(const char *pStr, IConsole::FPossibleCallback pfnCallback = IConsole::EmptyPossibleCommandCallback, void *pUser = nullptr);
173
174 static void PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser);
175 static void ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData);
176 static void ConToggleRemoteConsole(IConsole::IResult *pResult, void *pUserData);
177 static void ConClearLocalConsole(IConsole::IResult *pResult, void *pUserData);
178 static void ConClearRemoteConsole(IConsole::IResult *pResult, void *pUserData);
179 static void ConDumpLocalConsole(IConsole::IResult *pResult, void *pUserData);
180 static void ConDumpRemoteConsole(IConsole::IResult *pResult, void *pUserData);
181 static void ConConsolePageUp(IConsole::IResult *pResult, void *pUserData);
182 static void ConConsolePageDown(IConsole::IResult *pResult, void *pUserData);
183 static void ConConsolePageTop(IConsole::IResult *pResult, void *pUserData);
184 static void ConConsolePageBottom(IConsole::IResult *pResult, void *pUserData);
185 static void ConchainConsoleOutputLevel(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
186
187public:
188 enum
189 {
190 CONSOLETYPE_LOCAL = 0,
191 CONSOLETYPE_REMOTE,
192 NUM_CONSOLETYPES
193 };
194
195 CGameConsole();
196 ~CGameConsole() override;
197 int Sizeof() const override { return sizeof(*this); }
198
199 void PrintLine(int Type, const char *pLine);
200 void RequireUsername(bool UsernameReq);
201
202 void OnStateChange(int NewState, int OldState) override;
203 void OnConsoleInit() override;
204 void OnInit() override;
205 void OnReset() override;
206 void OnRender() override;
207 void OnMessage(int MsgType, void *pRawMsg) override;
208 bool OnInput(const IInput::CEvent &Event) override;
209 void Prompt(char (&aPrompt)[32]);
210
211 void Toggle(int Type);
212 bool IsActive() const { return m_ConsoleState != CONSOLE_CLOSED; }
213
214 void ForceUpdateRemoteCompletionSuggestions();
215};
216#endif
217