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