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