1#ifndef GAME_SERVER_SCOREWORKER_H
2#define GAME_SERVER_SCOREWORKER_H
3
4#include <memory>
5#include <optional>
6#include <string>
7#include <utility>
8#include <vector>
9
10#include <engine/map.h>
11#include <engine/server/databases/connection_pool.h>
12#include <engine/shared/protocol.h>
13#include <engine/shared/uuid_manager.h>
14#include <game/server/save.h>
15#include <game/voting.h>
16
17class IDbConnection;
18class IGameController;
19
20enum
21{
22 NUM_CHECKPOINTS = MAX_CHECKPOINTS,
23 TIMESTAMP_STR_LENGTH = 20, // 2019-04-02 19:38:36
24};
25
26struct CScorePlayerResult : ISqlResult
27{
28 CScorePlayerResult();
29
30 enum
31 {
32 MAX_MESSAGES = 10,
33 };
34
35 enum Variant
36 {
37 DIRECT,
38 ALL,
39 BROADCAST,
40 MAP_VOTE,
41 PLAYER_INFO,
42 PLAYER_TIMECP,
43 } m_MessageKind;
44 union
45 {
46 char m_aaMessages[MAX_MESSAGES][512];
47 char m_aBroadcast[1024];
48 struct
49 {
50 std::optional<float> m_Time;
51 float m_aTimeCp[NUM_CHECKPOINTS];
52 int m_Birthday; // 0 indicates no birthday
53 char m_aRequestedPlayer[MAX_NAME_LENGTH];
54 } m_Info = {};
55 struct
56 {
57 char m_aReason[VOTE_REASON_LENGTH];
58 char m_aServer[32 + 1];
59 char m_aMap[MAX_MAP_LENGTH + 1];
60 } m_MapVote;
61 } m_Data = {}; // PLAYER_INFO
62
63 void SetVariant(Variant v);
64};
65
66struct CScoreLoadBestTimeResult : ISqlResult
67{
68 CScoreLoadBestTimeResult() :
69 m_CurrentRecord(0)
70 {
71 }
72 float m_CurrentRecord;
73};
74
75struct CSqlLoadBestTimeData : ISqlData
76{
77 CSqlLoadBestTimeData(std::shared_ptr<CScoreLoadBestTimeResult> pResult) :
78 ISqlData(std::move(pResult))
79 {
80 }
81
82 // current map
83 char m_aMap[MAX_MAP_LENGTH];
84};
85
86struct CSqlPlayerRequest : ISqlData
87{
88 CSqlPlayerRequest(std::shared_ptr<CScorePlayerResult> pResult) :
89 ISqlData(std::move(pResult))
90 {
91 }
92
93 // object being requested, either map (128 bytes) or player (16 bytes)
94 char m_aName[MAX_MAP_LENGTH];
95 // current map
96 char m_aMap[MAX_MAP_LENGTH];
97 char m_aRequestingPlayer[MAX_NAME_LENGTH];
98 // relevant for /top5 kind of requests
99 int m_Offset;
100 char m_aServer[5];
101};
102
103struct CScoreRandomMapResult : ISqlResult
104{
105 CScoreRandomMapResult(int ClientId) :
106 m_ClientId(ClientId)
107 {
108 m_aMap[0] = '\0';
109 m_aMessage[0] = '\0';
110 }
111 int m_ClientId;
112 char m_aMap[MAX_MAP_LENGTH];
113 char m_aMessage[512];
114};
115
116struct CSqlRandomMapRequest : ISqlData
117{
118 CSqlRandomMapRequest(std::shared_ptr<CScoreRandomMapResult> pResult) :
119 ISqlData(std::move(pResult))
120 {
121 }
122
123 char m_aServerType[32];
124 char m_aCurrentMap[MAX_MAP_LENGTH];
125 char m_aRequestingPlayer[MAX_NAME_LENGTH];
126 int m_Stars;
127};
128
129struct CSqlScoreData : ISqlData
130{
131 CSqlScoreData(std::shared_ptr<CScorePlayerResult> pResult) :
132 ISqlData(std::move(pResult))
133 {
134 }
135
136 virtual ~CSqlScoreData(){};
137
138 char m_aMap[MAX_MAP_LENGTH];
139 char m_aGameUuid[UUID_MAXSTRSIZE];
140 char m_aName[MAX_MAP_LENGTH];
141
142 int m_ClientId;
143 float m_Time;
144 char m_aTimestamp[TIMESTAMP_STR_LENGTH];
145 float m_aCurrentTimeCp[NUM_CHECKPOINTS];
146 int m_Num;
147 bool m_Search;
148 char m_aRequestingPlayer[MAX_NAME_LENGTH];
149};
150
151struct CScoreSaveResult : ISqlResult
152{
153 CScoreSaveResult(int PlayerId) :
154 m_Status(SAVE_FAILED),
155 m_RequestingPlayer(PlayerId)
156 {
157 m_aMessage[0] = '\0';
158 m_aBroadcast[0] = '\0';
159 }
160 enum
161 {
162 SAVE_SUCCESS,
163 // load team in the following two cases
164 SAVE_FAILED,
165 LOAD_SUCCESS,
166 LOAD_FAILED,
167 } m_Status;
168 char m_aMessage[512];
169 char m_aBroadcast[512];
170 CSaveTeam m_SavedTeam;
171 int m_RequestingPlayer;
172 CUuid m_SaveId;
173};
174
175struct CSqlTeamScoreData : ISqlData
176{
177 CSqlTeamScoreData() :
178 ISqlData(nullptr)
179 {
180 }
181
182 char m_aGameUuid[UUID_MAXSTRSIZE];
183 char m_aMap[MAX_MAP_LENGTH];
184 float m_Time;
185 char m_aTimestamp[TIMESTAMP_STR_LENGTH];
186 unsigned int m_Size;
187 char m_aaNames[MAX_CLIENTS][MAX_NAME_LENGTH];
188 CUuid m_TeamrankUuid;
189};
190
191struct CSqlTeamSave : ISqlData
192{
193 CSqlTeamSave(std::shared_ptr<CScoreSaveResult> pResult) :
194 ISqlData(std::move(pResult))
195 {
196 }
197 virtual ~CSqlTeamSave(){};
198
199 char m_aClientName[MAX_NAME_LENGTH];
200 char m_aMap[MAX_MAP_LENGTH];
201 char m_aCode[128];
202 char m_aGeneratedCode[128];
203 char m_aServer[5];
204};
205
206struct CSqlTeamLoad : ISqlData
207{
208 CSqlTeamLoad(std::shared_ptr<CScoreSaveResult> pResult) :
209 ISqlData(std::move(pResult))
210 {
211 }
212 virtual ~CSqlTeamLoad(){};
213
214 char m_aCode[128];
215 char m_aMap[MAX_MAP_LENGTH];
216 char m_aRequestingPlayer[MAX_NAME_LENGTH];
217 int m_ClientId;
218 // struct holding all player names in the team or an empty string
219 char m_aClientNames[MAX_CLIENTS][MAX_NAME_LENGTH];
220 int m_aClientId[MAX_CLIENTS];
221 int m_NumPlayer;
222};
223
224class CPlayerData
225{
226public:
227 CPlayerData()
228 {
229 Reset();
230 }
231 ~CPlayerData() {}
232
233 void Reset()
234 {
235 m_BestTime = 0;
236 for(float &BestTimeCp : m_aBestTimeCp)
237 BestTimeCp = 0;
238
239 m_RecordStopTick = -1;
240 }
241
242 void Set(float Time, const float aTimeCp[NUM_CHECKPOINTS])
243 {
244 m_BestTime = Time;
245 for(int i = 0; i < NUM_CHECKPOINTS; i++)
246 m_aBestTimeCp[i] = aTimeCp[i];
247 }
248
249 void SetBestTimeCp(const float aTimeCp[NUM_CHECKPOINTS])
250 {
251 for(int i = 0; i < NUM_CHECKPOINTS; i++)
252 m_aBestTimeCp[i] = aTimeCp[i];
253 }
254
255 float m_BestTime;
256 float m_aBestTimeCp[NUM_CHECKPOINTS];
257
258 int m_RecordStopTick;
259 float m_RecordFinishTime;
260};
261
262struct CTeamrank
263{
264 CUuid m_TeamId;
265 char m_aaNames[MAX_CLIENTS][MAX_NAME_LENGTH];
266 unsigned int m_NumNames;
267 CTeamrank();
268
269 // Assumes that a database query equivalent to
270 //
271 // SELECT TeamId, Name [, ...] -- the order is important
272 // FROM record_teamrace
273 // ORDER BY TeamId, Name
274 //
275 // was executed and that the result line of the first team member is already selected.
276 // Afterwards the team member of the next team is selected.
277 //
278 // Returns true on SQL failure
279 //
280 // if another team can be extracted
281 bool NextSqlResult(IDbConnection *pSqlServer, bool *pEnd, char *pError, int ErrorSize);
282
283 bool SamePlayers(const std::vector<std::string> *pvSortedNames);
284};
285
286struct CScoreWorker
287{
288 static bool LoadBestTime(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
289
290 static bool RandomMap(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
291 static bool RandomUnfinishedMap(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
292 static bool MapVote(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
293
294 static bool LoadPlayerData(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
295 static bool LoadPlayerTimeCp(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
296 static bool MapInfo(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
297 static bool ShowRank(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
298 static bool ShowTeamRank(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
299 static bool ShowTop(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
300 static bool ShowTeamTop5(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
301 static bool ShowPlayerTeamTop5(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
302 static bool ShowTimes(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
303 static bool ShowPoints(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
304 static bool ShowTopPoints(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
305 static bool GetSaves(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
306
307 static bool SaveTeam(IDbConnection *pSqlServer, const ISqlData *pGameData, Write w, char *pError, int ErrorSize);
308 static bool LoadTeam(IDbConnection *pSqlServer, const ISqlData *pGameData, Write w, char *pError, int ErrorSize);
309
310 static bool SaveScore(IDbConnection *pSqlServer, const ISqlData *pGameData, Write w, char *pError, int ErrorSize);
311 static bool SaveTeamScore(IDbConnection *pSqlServer, const ISqlData *pGameData, Write w, char *pError, int ErrorSize);
312};
313
314#endif // GAME_SERVER_SCOREWORKER_H
315