1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2001, Sven2
6 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18/* engine handler of league system */
19
20#pragma once
21
22#include <C4Network2Reference.h>
23#include <C4Gui.h>
24
25#include <StdSha1.h>
26
27#define C4League_Name_Valid_Characters "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD9\xDA\xDB\xDC\xDD\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF\x20\x2E\x2D\x5F"
28
29// maximum league count a game can run in
30const int32_t C4NetMaxLeagues = 10;
31
32enum C4LeagueAction
33{
34 C4LA_None, // no action
35
36 C4LA_Start, // [host] Game registration
37 C4LA_Update, // [host] Game status update (heartbeat)
38 C4LA_End, // [host] Final game status
39 C4LA_PlrAuthCheck, // [host] Player authentication check
40
41 C4LA_RefQuery, // [client] Query reference list
42 C4LA_PlrAuth, // [client] Player authentication request
43
44 C4LA_ReportDisconnect, // [both] Sent by host and client when a client is disconnected irregularly
45};
46
47class C4LeagueRequestHead
48{
49public:
50 C4LeagueRequestHead(C4LeagueAction eAction, const char *szCSID = "", const char *szAUID = "")
51 : eAction(eAction), CSID(szCSID), AUID(szAUID) {}
52
53private:
54 C4LeagueAction eAction;
55 StdStrBuf CSID;
56 StdStrBuf AUID;
57 StdStrBuf Checksum;
58
59 // Auth
60 StdStrBuf Account;
61 StdStrBuf Password;
62 StdStrBuf NewAccount;
63 StdStrBuf NewPassword;
64
65public:
66 void SetChecksum(const char *szChecksum) { Checksum = szChecksum; }
67 void SetAuth(const char *szAccount, const char *szPassword);
68 void SetNewAccount(const char *szNewAccount);
69 void SetNewPassword(const char *szNewPassword);
70
71 void CompileFunc(StdCompiler *pComp);
72};
73
74class C4LeagueReportDisconnectHead : public C4LeagueRequestHead
75{
76private:
77 C4LeagueDisconnectReason eReason;
78
79public:
80 C4LeagueReportDisconnectHead(const char *szCSID, C4LeagueDisconnectReason eReason) : eReason(eReason), C4LeagueRequestHead(C4LA_ReportDisconnect, szCSID, nullptr) {}
81
82public:
83 void CompileFunc(StdCompiler *pComp);
84};
85
86class C4LeagueRequestHeadEnd : public C4LeagueRequestHead
87{
88public:
89 C4LeagueRequestHeadEnd(C4LeagueAction eAction, const char *szCSID, const char *szRecordName = nullptr, const uint8_t *pRecordSHA = nullptr)
90 : C4LeagueRequestHead(eAction, szCSID), RecordName(szRecordName)
91 {
92 if (pRecordSHA)
93 memcpy(dest: RecordSHA, src: pRecordSHA, n: StdSha1::DigestLength);
94 }
95
96private:
97 StdStrBuf RecordName;
98 uint8_t RecordSHA[StdSha1::DigestLength];
99
100public:
101 void CompileFunc(StdCompiler *pComp);
102};
103
104class C4LeagueResponseHead
105{
106public:
107 C4LeagueResponseHead() {}
108
109private:
110 StdStrBuf Status;
111 StdStrBuf CSID;
112 StdStrBuf Message;
113
114 // Auth
115 StdStrBuf Account;
116 StdStrBuf AUID;
117 StdStrBuf FBID;
118
119public:
120 const char *getCSID() const { return CSID.getData(); }
121 const char *getMessage() const { return Message.getData(); }
122 bool isSuccess() const { return SEqualNoCase(szStr1: Status.getData(), szStr2: "Success"); }
123 bool isStatusRegister() const { return SEqualNoCase(szStr1: Status.getData(), szStr2: "Register"); }
124 const char *getAccount() const { return Account.getData(); }
125 const char *getAUID() const { return AUID.getData(); }
126 const char *getFBID() const { return FBID.getData(); }
127
128 void CompileFunc(StdCompiler *pComp);
129};
130
131class C4LeagueResponseHeadStart : public C4LeagueResponseHead
132{
133private:
134 StdStrBuf League;
135 StdStrBuf StreamingAddr;
136 int32_t fHaveSeed;
137 int32_t iSeed;
138 int32_t iMaxPlayers;
139
140public:
141 const char *getLeague() const { return League.getData(); }
142 const char *getStreamingAddr() const { return StreamingAddr.getData(); }
143 bool haveSeed() const { return !!fHaveSeed; }
144 int32_t getSeed() const { return iSeed; }
145 int32_t getMaxPlayers() const { return iMaxPlayers; }
146
147 void CompileFunc(StdCompiler *pComp);
148};
149
150class C4LeagueResponseHeadUpdate : public C4LeagueResponseHead
151{
152private:
153 StdStrBuf League;
154 C4ClientPlayerInfos PlrInfos;
155
156public:
157 const char *getLeague() const { return League.getData(); }
158 const C4ClientPlayerInfos &GetPlrInfos() const { return PlrInfos; }
159
160 void CompileFunc(StdCompiler *pComp);
161};
162
163class C4LeagueResponseHeadAuthCheck : public C4LeagueResponseHead
164{
165private:
166 StdStrBuf Leagues[C4NetMaxLeagues];
167 int32_t Scores[C4NetMaxLeagues];
168 int32_t Ranks[C4NetMaxLeagues];
169 int32_t RankSymbols[C4NetMaxLeagues];
170 StdStrBuf ProgressData[C4NetMaxLeagues];
171 StdStrBuf ClanTag;
172
173public:
174 int32_t getScore(const char *szLeague) const;
175 int32_t getRank(const char *szLeague) const;
176 int32_t getRankSymbol(const char *szLeague) const;
177 const char *getProgressData(const char *szLeague) const;
178 const char *getClanTag() const { return ClanTag.getData(); }
179
180 void CompileFunc(StdCompiler *pComp);
181};
182
183// a linked list of all known feedback IDs, associated to player IDs
184class C4LeagueFBIDList
185{
186private:
187 struct FBIDItem
188 {
189 StdStrBuf Account;
190 StdStrBuf FBID;
191 FBIDItem *pNext;
192 } *pFirst;
193
194public:
195 C4LeagueFBIDList() : pFirst(nullptr) {}
196 ~C4LeagueFBIDList() { Clear(); }
197 void Clear();
198 void RemoveFBIDByAccount(const char *szAccount);
199 bool FindFBIDByAccount(const char *szAccount, StdStrBuf *pFBIDOut);
200
201 void AddFBID(const char *szFBID, const char *szAccount);
202};
203
204class C4LeagueClient : public C4Network2RefClient
205{
206private:
207 StdStrBuf CSID;
208 C4LeagueAction eCurrAction;
209 C4LeagueFBIDList FBIDList;
210
211public:
212 C4LeagueClient() : CSID(), eCurrAction(C4LA_None), C4Network2RefClient() {}
213 const char *getCSID() const { return CSID.getData(); }
214 C4LeagueAction getCurrentAction() const { return eCurrAction; }
215 void ResetCurrentAction() { eCurrAction = C4LA_None; }
216
217 // Action "Start"
218 bool Start(const C4Network2Reference &Ref);
219 bool GetStartReply(StdStrBuf *pMessage, StdStrBuf *pLeague, StdStrBuf *pStreamingAddr, int32_t *pSeed, int32_t *pMaxPlayers);
220
221 // Action "Update"
222 bool Update(const C4Network2Reference &Ref);
223 bool GetUpdateReply(StdStrBuf *pMessage, C4ClientPlayerInfos *pPlayerLeagueInfos);
224
225 // Action "End"
226 bool End(const C4Network2Reference &Ref, const char *szRecordName, const uint8_t *pRecordSHA);
227 bool GetEndReply(StdStrBuf *pMessage, class C4RoundResultsPlayers *pRoundResults);
228
229 // Action "Auth"
230 bool Auth(const C4PlayerInfo &PlrInfo, const char *szAccount, const char *szPassword, const char *szNewAccount = nullptr, const char *szNewPassword = nullptr);
231 bool GetAuthReply(StdStrBuf *pMessage, StdStrBuf *pAUID, StdStrBuf *pAccount, bool *pRegister);
232
233 // Action "Join"
234 bool AuthCheck(const C4PlayerInfo &PlrInfo);
235 bool GetAuthCheckReply(StdStrBuf *pMessage, const char *szLeague, class C4PlayerInfo *pPlrInfo);
236
237 // Action "Disconnect" - sent by host and client when one or more clients are disconnected irregularly
238 bool ReportDisconnect(const C4ClientPlayerInfos &rSendPlayerFBIDs, C4LeagueDisconnectReason eReason);
239 bool GetReportDisconnectReply(StdStrBuf *pMessage);
240
241private:
242 void ModifyForChecksum(std::string &data, const char *replace);
243 void ModifyForChecksum(const void *pData, size_t iDataSize, char *pReplace, uint32_t iChecksum, uint32_t iCheckMask);
244};
245
246// dialog shown for each participating player to enter league authentication data
247class C4LeagueSignupDialog : public C4GUI::Dialog
248{
249private:
250 C4GUI::CheckBox *pChkPassword;
251 C4GUI::LabeledEdit *pEdtAccount, *pEdtPass, *pEdtPass2;
252 C4GUI::Button *pBtnOK, *pBtnAbort;
253 int32_t iEdtPassSpace;
254 StdStrBuf strPlayerName;
255
256public:
257 C4LeagueSignupDialog(const char *szPlayerName, const char *szLeagueName, const char *szLeagueServerName, const char *szAccountPref, const char *szPassPref, bool fWarnThirdParty, bool fRegister);
258 ~C4LeagueSignupDialog() {}
259
260 const char *GetAccount();
261 bool HasPass();
262 const char *GetPass();
263
264 // check for errors (overridden)
265 virtual void UserClose(bool fOK) override;
266
267 // show modal league dialog to query password for player; return
268 static bool ShowModal(const char *szPlayerName, const char *szLeagueName, const char *szLeagueServerName, StdStrBuf *psAccount, StdStrBuf *psPass, bool fWarnThirdParty, bool fRegister);
269
270private:
271 void OnChkPassword();
272};
273