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 trailing 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
137 void UpdateEntryTextAttributes(CBacklogEntry *pEntry) const;
138
139 bool IsInputHidden() const;
140 void UpdateCompletionSuggestions();
141
142 private:
143 void SetSearching(bool Searching);
144 void ClearSearch();
145 void UpdateSearch();
146
147 friend class CGameConsole;
148 };
149
150 class IConsole *m_pConsole;
151 CConsoleLogger *m_pConsoleLogger = nullptr;
152
153 CInstance m_LocalConsole;
154 CInstance m_RemoteConsole;
155
156 CInstance *ConsoleForType(int ConsoleType);
157 CInstance *CurrentConsole();
158
159 int m_ConsoleType;
160 int m_ConsoleState;
161 float m_StateChangeEnd;
162 float m_StateChangeDuration;
163
164 bool m_WantsSelectionCopy = false;
165 CUi::CTouchState m_TouchState;
166
167 static constexpr ColorRGBA ms_SearchHighlightColor = ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f);
168 static constexpr ColorRGBA ms_SearchSelectedColor = ColorRGBA(1.0f, 1.0f, 0.0f, 1.0f);
169
170 int PossibleMaps(const char *pStr, IConsole::FPossibleCallback pfnCallback = IConsole::EmptyPossibleCommandCallback, void *pUser = nullptr);
171
172 static void PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser);
173 static void ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData);
174 static void ConToggleRemoteConsole(IConsole::IResult *pResult, void *pUserData);
175 static void ConClearLocalConsole(IConsole::IResult *pResult, void *pUserData);
176 static void ConClearRemoteConsole(IConsole::IResult *pResult, void *pUserData);
177 static void ConDumpLocalConsole(IConsole::IResult *pResult, void *pUserData);
178 static void ConDumpRemoteConsole(IConsole::IResult *pResult, void *pUserData);
179 static void ConConsolePageUp(IConsole::IResult *pResult, void *pUserData);
180 static void ConConsolePageDown(IConsole::IResult *pResult, void *pUserData);
181 static void ConConsolePageTop(IConsole::IResult *pResult, void *pUserData);
182 static void ConConsolePageBottom(IConsole::IResult *pResult, void *pUserData);
183 static void ConchainConsoleOutputLevel(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
184
185public:
186 enum
187 {
188 CONSOLETYPE_LOCAL = 0,
189 CONSOLETYPE_REMOTE,
190 NUM_CONSOLETYPES
191 };
192
193 CGameConsole();
194 ~CGameConsole() override;
195 int Sizeof() const override { return sizeof(*this); }
196
197 void PrintLine(int Type, const char *pLine);
198 void RequireUsername(bool UsernameReq);
199
200 void OnStateChange(int NewState, int OldState) override;
201 void OnConsoleInit() override;
202 void OnInit() override;
203 void OnReset() override;
204 void OnRender() override;
205 void OnMessage(int MsgType, void *pRawMsg) override;
206 bool OnInput(const IInput::CEvent &Event) override;
207 void Prompt(char (&aPrompt)[32]);
208
209 void Toggle(int Type);
210 bool IsActive() const { return m_ConsoleState != CONSOLE_CLOSED; }
211
212 void ForceUpdateRemoteCompletionSuggestions();
213};
214#endif
215