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_CLIENT_H
4#define ENGINE_CLIENT_H
5#include "graphics.h"
6#include "kernel.h"
7#include "message.h"
8
9#include <base/hash.h>
10
11#include <engine/client/enums.h>
12#include <engine/friends.h>
13#include <engine/shared/translation_context.h>
14
15#include <generated/protocol.h>
16#include <generated/protocol7.h>
17
18#include <functional>
19#include <optional>
20
21#define CONNECTLINK_DOUBLE_SLASH "ddnet://"
22#define CONNECTLINK_NO_SLASH "ddnet:"
23
24struct SWarning;
25
26enum
27{
28 RECORDER_MANUAL = 0,
29 RECORDER_AUTO = 1,
30 RECORDER_RACE = 2,
31 RECORDER_REPLAYS = 3,
32 RECORDER_MAX = 4,
33};
34
35typedef bool (*CLIENTFUNC_FILTER)(const void *pData, int DataSize, void *pUser);
36struct CChecksumData;
37
38class IClient : public IInterface
39{
40 MACRO_INTERFACE("client")
41public:
42 /* Constants: Client States
43 STATE_OFFLINE - The client is offline.
44 STATE_CONNECTING - The client is trying to connect to a server.
45 STATE_LOADING - The client has connected to a server and is loading resources.
46 STATE_ONLINE - The client is connected to a server and running the game.
47 STATE_DEMOPLAYBACK - The client is playing a demo
48 STATE_QUITTING - The client is quitting.
49 */
50
51 enum EClientState
52 {
53 STATE_OFFLINE = 0,
54 STATE_CONNECTING,
55 STATE_LOADING,
56 STATE_ONLINE,
57 STATE_DEMOPLAYBACK,
58 STATE_QUITTING,
59 STATE_RESTARTING,
60 };
61
62 /**
63 * More precise state for @see STATE_LOADING
64 * Sets what is actually happening in the client right now
65 */
66 enum ELoadingStateDetail
67 {
68 LOADING_STATE_DETAIL_INITIAL,
69 LOADING_STATE_DETAIL_LOADING_MAP,
70 LOADING_STATE_DETAIL_LOADING_DEMO,
71 LOADING_STATE_DETAIL_SENDING_READY,
72 LOADING_STATE_DETAIL_GETTING_READY,
73 };
74
75 enum ELoadingCallbackDetail
76 {
77 LOADING_CALLBACK_DETAIL_MAP,
78 LOADING_CALLBACK_DETAIL_DEMO,
79 };
80 typedef std::function<void(ELoadingCallbackDetail Detail)> TLoadingCallback;
81 CTranslationContext m_TranslationContext;
82
83protected:
84 // quick access to state of the client
85 EClientState m_State = IClient::STATE_OFFLINE;
86 ELoadingStateDetail m_LoadingStateDetail = LOADING_STATE_DETAIL_INITIAL;
87 int64_t m_StateStartTime;
88
89 // quick access to time variables
90 int m_aPrevGameTick[NUM_DUMMIES] = {0, 0};
91 int m_aCurGameTick[NUM_DUMMIES] = {0, 0};
92 float m_aGameIntraTick[NUM_DUMMIES] = {0.0f, 0.0f};
93 float m_aGameTickTime[NUM_DUMMIES] = {0.0f, 0.0f};
94 float m_aGameIntraTickSincePrev[NUM_DUMMIES] = {0.0f, 0.0f};
95
96 int m_aPredTick[NUM_DUMMIES] = {0, 0};
97 float m_aPredIntraTick[NUM_DUMMIES] = {0.0f, 0.0f};
98
99 float m_LocalTime = 0.0f;
100 float m_GlobalTime = 0.0f;
101 float m_RenderFrameTime = 0.0001f;
102 float m_FrameTimeAverage = 0.0001f;
103
104 TLoadingCallback m_LoadingCallback = nullptr;
105
106 char m_aNews[3000] = "";
107 int m_Points = -1;
108 int64_t m_ReconnectTime = 0;
109
110public:
111 class CSnapItem
112 {
113 public:
114 int m_Type;
115 int m_Id;
116 const void *m_pData;
117 int m_DataSize;
118 };
119
120 enum
121 {
122 CONN_MAIN = 0,
123 CONN_DUMMY,
124 CONN_CONTACT,
125 NUM_CONNS,
126 };
127
128 enum
129 {
130 CONNECTIVITY_UNKNOWN,
131 CONNECTIVITY_CHECKING,
132 CONNECTIVITY_UNREACHABLE,
133 CONNECTIVITY_REACHABLE,
134 // Different global IP address has been detected for UDP and
135 // TCP connections.
136 CONNECTIVITY_DIFFERING_UDP_TCP_IP_ADDRESSES,
137 };
138
139 //
140 EClientState State() const { return m_State; }
141 ELoadingStateDetail LoadingStateDetail() const { return m_LoadingStateDetail; }
142 int64_t StateStartTime() const { return m_StateStartTime; }
143 void SetLoadingStateDetail(ELoadingStateDetail LoadingStateDetail) { m_LoadingStateDetail = LoadingStateDetail; }
144
145 void SetLoadingCallback(TLoadingCallback &&Func) { m_LoadingCallback = std::move(Func); }
146
147 // tick time access
148 int PrevGameTick(int Conn) const { return m_aPrevGameTick[Conn]; }
149 int GameTick(int Conn) const { return m_aCurGameTick[Conn]; }
150 int PredGameTick(int Conn) const { return m_aPredTick[Conn]; }
151 float IntraGameTick(int Conn) const { return m_aGameIntraTick[Conn]; }
152 float PredIntraGameTick(int Conn) const { return m_aPredIntraTick[Conn]; }
153 float IntraGameTickSincePrev(int Conn) const { return m_aGameIntraTickSincePrev[Conn]; }
154 float GameTickTime(int Conn) const { return m_aGameTickTime[Conn]; }
155 int GameTickSpeed() const { return SERVER_TICK_SPEED; }
156
157 // other time access
158 float RenderFrameTime() const { return m_RenderFrameTime; }
159 float LocalTime() const { return m_LocalTime; }
160 float GlobalTime() const { return m_GlobalTime; }
161 float FrameTimeAverage() const { return m_FrameTimeAverage; }
162
163 // actions
164 virtual void Connect(const char *pAddress, const char *pPassword = nullptr) = 0;
165 virtual void Disconnect() = 0;
166
167 // dummy
168 virtual void DummyDisconnect(const char *pReason) = 0;
169 virtual void DummyConnect() = 0;
170 virtual bool DummyConnected() const = 0;
171 virtual bool DummyConnecting() const = 0;
172 virtual bool DummyConnectingDelayed() const = 0;
173 virtual bool DummyAllowed() const = 0;
174
175 virtual void Restart() = 0;
176 virtual void Quit() = 0;
177 virtual const char *DemoPlayer_Play(const char *pFilename, int StorageType) = 0;
178#if defined(CONF_VIDEORECORDER)
179 virtual const char *DemoPlayer_Render(const char *pFilename, int StorageType, const char *pVideoName, int SpeedIndex, bool StartPaused = false) = 0;
180#endif
181 virtual void DemoRecorder_Start(const char *pFilename, bool WithTimestamp, int Recorder, bool Verbose = false) = 0;
182 virtual void DemoRecorder_HandleAutoStart() = 0;
183 virtual void DemoRecorder_UpdateReplayRecorder() = 0;
184 virtual class IDemoRecorder *DemoRecorder(int Recorder) = 0;
185 virtual void AutoScreenshot_Start() = 0;
186 virtual void AutoStatScreenshot_Start() = 0;
187 virtual void AutoCSV_Start() = 0;
188 virtual void ServerBrowserUpdate() = 0;
189
190 // gfx
191 virtual void Notify(const char *pTitle, const char *pMessage) = 0;
192 virtual void OnWindowResize() = 0;
193
194 virtual void UpdateAndSwap() = 0;
195
196 // networking
197 virtual void EnterGame(int Conn) = 0;
198
199 //
200 virtual const NETADDR &ServerAddress() const = 0;
201 virtual int ConnectNetTypes() const = 0;
202 virtual const char *ConnectAddressString() const = 0;
203 virtual const char *MapDownloadName() const = 0;
204 virtual int MapDownloadAmount() const = 0;
205 virtual int MapDownloadTotalsize() const = 0;
206
207 // input
208 virtual int *GetInput(int Tick, int IsDummy = 0) const = 0;
209
210 // remote console
211 virtual void RconAuth(const char *pUsername, const char *pPassword, bool Dummy) = 0;
212 virtual bool RconAuthed() const = 0;
213 virtual bool UseTempRconCommands() const = 0;
214 virtual void Rcon(const char *pLine) = 0;
215 virtual bool ReceivingRconCommands() const = 0;
216 virtual float GotRconCommandsPercentage() const = 0;
217 virtual bool ReceivingMaplist() const = 0;
218 virtual float GotMaplistPercentage() const = 0;
219 virtual const std::vector<std::string> &MaplistEntries() const = 0;
220
221 // server info
222 virtual void GetServerInfo(class CServerInfo *pServerInfo) const = 0;
223 virtual bool ServerCapAnyPlayerFlag() const = 0;
224
225 virtual int GetPredictionTime() = 0;
226 virtual int GetPredictionTick() = 0;
227
228 // snapshot interface
229
230 enum
231 {
232 SNAP_CURRENT = 0,
233 SNAP_PREV = 1,
234 NUM_SNAPSHOT_TYPES = 2,
235 };
236
237 // TODO: Refactor: should redo this a bit i think, too many virtual calls
238 virtual int SnapNumItems(int SnapId) const = 0;
239 virtual const void *SnapFindItem(int SnapId, int Type, int Id) const = 0;
240 virtual CSnapItem SnapGetItem(int SnapId, int Index) const = 0;
241
242 virtual void SnapSetStaticsize(int ItemType, int Size) = 0;
243 virtual void SnapSetStaticsize7(int ItemType, int Size) = 0;
244
245 virtual int SendMsg(int Conn, CMsgPacker *pMsg, int Flags) = 0;
246 virtual int SendMsgActive(CMsgPacker *pMsg, int Flags) = 0;
247
248 template<class T>
249 int SendPackMsgActive(T *pMsg, int Flags, bool NoTranslate = false)
250 {
251 CMsgPacker Packer(T::ms_MsgId, false, NoTranslate);
252 if(pMsg->Pack(&Packer))
253 return -1;
254 return SendMsgActive(pMsg: &Packer, Flags);
255 }
256
257 template<class T>
258 int SendPackMsg(int Conn, T *pMsg, int Flags, bool NoTranslate = false)
259 {
260 CMsgPacker Packer(T::ms_MsgId, false, NoTranslate);
261 if(pMsg->Pack(&Packer))
262 return -1;
263 return SendMsg(Conn, pMsg: &Packer, Flags);
264 }
265
266 //
267 virtual const char *PlayerName() const = 0;
268 virtual const char *DummyName() = 0;
269 virtual const char *ErrorString() const = 0;
270 virtual const char *LatestVersion() const = 0;
271 virtual bool ConnectionProblems() const = 0;
272
273 virtual IGraphics::CTextureHandle GetDebugFont() const = 0; // TODO: remove this function
274
275 // DDRace
276
277 virtual const char *GetCurrentMap() const = 0;
278 virtual const char *GetCurrentMapPath() const = 0;
279 virtual SHA256_DIGEST GetCurrentMapSha256() const = 0;
280 virtual unsigned GetCurrentMapCrc() const = 0;
281
282 const char *News() const { return m_aNews; }
283 int Points() const { return m_Points; }
284 int64_t ReconnectTime() const { return m_ReconnectTime; }
285 void SetReconnectTime(int64_t ReconnectTime) { m_ReconnectTime = ReconnectTime; }
286
287 virtual bool IsSixup() const = 0;
288
289 virtual void RaceRecord_Start(const char *pFilename) = 0;
290 virtual void RaceRecord_Stop() = 0;
291 virtual bool RaceRecord_IsRecording() = 0;
292
293 virtual void DemoSliceBegin() = 0;
294 virtual void DemoSliceEnd() = 0;
295 virtual void DemoSlice(const char *pDstPath, CLIENTFUNC_FILTER pfnFilter, void *pUser) = 0;
296
297 enum class EInfoState
298 {
299 LOADING,
300 SUCCESS,
301 ERROR,
302 };
303 virtual EInfoState InfoState() const = 0;
304 virtual void RequestDDNetInfo() = 0;
305 virtual bool EditorHasUnsavedData() const = 0;
306
307 virtual void GenerateTimeoutSeed() = 0;
308
309 virtual IFriends *Foes() = 0;
310
311 virtual void GetSmoothTick(int *pSmoothTick, float *pSmoothIntraTick, float MixAmount) = 0;
312
313 virtual void AddWarning(const SWarning &Warning) = 0;
314 virtual std::optional<SWarning> CurrentWarning() = 0;
315
316 virtual CChecksumData *ChecksumData() = 0;
317 virtual int UdpConnectivity(int NetType) = 0;
318
319 /**
320 * Opens a link in the browser.
321 *
322 * @param pLink The link to open in a browser.
323 *
324 * @return `true` on success, `false` on failure.
325 *
326 * @remark This may not be called with untrusted input or it'll result in arbitrary code execution, especially on Windows.
327 */
328 virtual bool ViewLink(const char *pLink) = 0;
329 /**
330 * Opens a file or directory with the default program.
331 *
332 * @param pFilename The file or folder to open with the default program.
333 *
334 * @return `true` on success, `false` on failure.
335 *
336 * @remark This may not be called with untrusted input or it'll result in arbitrary code execution, especially on Windows.
337 */
338 virtual bool ViewFile(const char *pFilename) = 0;
339
340#if defined(CONF_FAMILY_WINDOWS)
341 virtual void ShellRegister() = 0;
342 virtual void ShellUnregister() = 0;
343#endif
344
345 virtual std::optional<int> ShowMessageBox(const IGraphics::CMessageBox &MessageBox) = 0;
346 virtual void GetGpuInfoString(char (&aGpuInfo)[512]) = 0;
347};
348
349class IGameClient : public IInterface
350{
351 MACRO_INTERFACE("gameclient")
352protected:
353public:
354 virtual void OnConsoleInit() = 0;
355
356 virtual void OnRconType(bool UsernameReq) = 0;
357 virtual void OnRconLine(const char *pLine) = 0;
358 virtual void OnInit() = 0;
359 virtual void InvalidateSnapshot() = 0;
360 virtual void OnNewSnapshot() = 0;
361 virtual void OnEnterGame() = 0;
362 virtual void OnShutdown() = 0;
363 virtual void OnRender() = 0;
364 virtual void OnUpdate() = 0;
365 virtual void OnStateChange(int NewState, int OldState) = 0;
366 virtual void OnConnected() = 0;
367 virtual void OnMessage(int MsgId, CUnpacker *pUnpacker, int Conn, bool Dummy) = 0;
368 virtual void OnPredict() = 0;
369 virtual void OnActivateEditor() = 0;
370 virtual void OnWindowResize() = 0;
371
372 virtual int OnSnapInput(int *pData, bool Dummy, bool Force) = 0;
373 virtual void OnDummySwap() = 0;
374 virtual void SendDummyInfo(bool Start) = 0;
375
376 virtual const char *GetItemName(int Type) const = 0;
377 virtual const char *Version() const = 0;
378 virtual const char *NetVersion() const = 0;
379 virtual const char *NetVersion7() const = 0;
380 virtual int DDNetVersion() const = 0;
381 virtual const char *DDNetVersionStr() const = 0;
382
383 virtual void OnDummyDisconnect() = 0;
384 virtual void DummyResetInput() = 0;
385 virtual void Echo(const char *pString) = 0;
386
387 virtual bool CanDisplayWarning() const = 0;
388 virtual void RenderShutdownMessage() = 0;
389
390 virtual CNetObjHandler *GetNetObjHandler() = 0;
391 virtual protocol7::CNetObjHandler *GetNetObjHandler7() = 0;
392
393 virtual int ClientVersion7() const = 0;
394
395 virtual void ApplySkin7InfoFromSnapObj(const protocol7::CNetObj_De_ClientInfo *pObj, int ClientId) = 0;
396 virtual int OnDemoRecSnap7(class CSnapshot *pFrom, class CSnapshot *pTo, int Conn) = 0;
397 virtual int TranslateSnap(class CSnapshot *pSnapDstSix, class CSnapshot *pSnapSrcSeven, int Conn, bool Dummy) = 0;
398 virtual void ProcessDemoSnapshot(class CSnapshot *pSnap) = 0;
399
400 virtual void InitializeLanguage() = 0;
401
402 virtual void ForceUpdateConsoleRemoteCompletionSuggestions() = 0;
403};
404
405extern IGameClient *CreateGameClient();
406#endif
407