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