BF2MC-Matchmaker
leaderboard_clan.cpp
1 #include <iostream>
2 #include <mysql/mysql.h>
3 
4 #include <settings.h>
5 #include <logger.h>
6 #include <util.h>
7 
8 #include <database.h>
9 
10 bool Database::queryLeaderboardClan(Battlefield::RankClans& rank_clans, uint32_t limit, uint32_t offset)
11 {
12  std::lock_guard<std::mutex> guard(this->_mutex); // database lock
13 
14  std::string query = "";
15  query += "SELECT ";
16  query += " `rank`, `clanid`, `name`, `tag`, `score`, `wins`, `losses`, `draws` ";
17  query += "FROM ";
18  query += " `Leaderboard_clan` ";
19  query += "ORDER BY ";
20  query += " `rank` ASC, ";
21  query += " `score` DESC, ";
22  query += " `wins` DESC, ";
23  query += " `losses` DESC, ";
24  query += " `draws` DESC ";
25  query += "LIMIT ? OFFSET ?;";
26 
27  int output_rank;
28  int output_clanid;
29  char output_name[VARCHAR_LEN(32)];
30  char output_tag[VARCHAR_LEN(3)];
31  uint32_t output_score;
32  uint32_t output_wins;
33  uint32_t output_losses;
34  uint32_t output_draws;
35 
36  // Allocate input binds
37  MYSQL_BIND* input_bind = (MYSQL_BIND *)calloc(2, sizeof(MYSQL_BIND));
38  input_bind[0].buffer_type = MYSQL_TYPE_LONG;
39  input_bind[0].buffer = &limit;
40  input_bind[0].is_unsigned = true;
41  input_bind[1].buffer_type = MYSQL_TYPE_LONG;
42  input_bind[1].buffer = &offset;
43  input_bind[1].is_unsigned = true;
44 
45  // Allocate output binds
46  MYSQL_BIND* output_bind = (MYSQL_BIND *)calloc(8, sizeof(MYSQL_BIND));
47  output_bind[0].buffer_type = MYSQL_TYPE_LONG;
48  output_bind[0].buffer = &output_rank;
49  output_bind[0].is_unsigned = false;
50  output_bind[1].buffer_type = MYSQL_TYPE_LONG;
51  output_bind[1].buffer = &output_clanid;
52  output_bind[1].is_unsigned = false;
53  output_bind[2].buffer_type = MYSQL_TYPE_VAR_STRING;
54  output_bind[2].buffer = &output_name;
55  output_bind[2].buffer_length = VARCHAR_LEN(32);
56  output_bind[3].buffer_type = MYSQL_TYPE_VAR_STRING;
57  output_bind[3].buffer = &output_tag;
58  output_bind[3].buffer_length = VARCHAR_LEN(3);
59  output_bind[4].buffer_type = MYSQL_TYPE_LONG;
60  output_bind[4].buffer = &output_score;
61  output_bind[4].is_unsigned = true;
62  output_bind[5].buffer_type = MYSQL_TYPE_LONG;
63  output_bind[5].buffer = &output_wins;
64  output_bind[5].is_unsigned = true;
65  output_bind[6].buffer_type = MYSQL_TYPE_LONG;
66  output_bind[6].buffer = &output_losses;
67  output_bind[6].is_unsigned = true;
68  output_bind[7].buffer_type = MYSQL_TYPE_LONG;
69  output_bind[7].buffer = &output_draws;
70  output_bind[7].is_unsigned = true;
71 
72  // Prepare and execute with binds
73  MYSQL_STMT* statement;
74 
75  if(
76  !this->_init(&statement) ||
77  !this->_prepare(statement, query, input_bind) ||
78  !this->_execute(statement, output_bind)
79  )
80  {
81  // Cleanup
82  free(input_bind);
83  free(output_bind);
84 
85  return false;
86  }
87 
88  // Fetch and process rows
89  while (true)
90  {
91  int status = mysql_stmt_fetch(statement);
92 
93  if (status == 1 || status == MYSQL_NO_DATA)
94  break;
95 
96  Battlefield::Clan clan;
97 
98  clan.SetClanId(output_clanid);
99  clan.SetName(output_name);
100  clan.SetTag(output_tag);
101  clan.SetScore(output_score);
102  clan.SetWins(output_wins);
103  clan.SetLosses(output_losses);
104  clan.SetDraws(output_draws);
105 
106  rank_clans.insert(std::make_pair(output_rank, clan));
107  }
108 
109  // Cleanup
110  mysql_stmt_free_result(statement);
111  mysql_stmt_close(statement);
112  free(input_bind);
113  free(output_bind);
114 
115  return true;
116 }
117 
118 bool Database::queryLeaderboardClanByClanId(Battlefield::RankClans& rank_clans, const Battlefield::Clan& clan)
119 {
120  std::lock_guard<std::mutex> guard(this->_mutex); // database lock
121 
122  std::string query = "";
123  query += "SELECT `rp`.* ";
124  query += "FROM ";
125  query += " `Leaderboard_clan` AS `rp` ";
126  query += "JOIN ( ";
127  query += " SELECT ";
128  query += " `clanid`, ";
129  query += " `rank` AS `start_rank` ";
130  query += " FROM ";
131  query += " `Leaderboard_clan` ";
132  query += " WHERE ";
133  query += " `clanid` = ? ";
134  query += ") AS `start` ON rp.rank >= CASE WHEN start.start_rank <= 4 THEN 1 ELSE start.start_rank - 4 END ";
135  query += "JOIN ( ";
136  query += " SELECT ";
137  query += " `clanid`, ";
138  query += " `rank` AS `end_rank` ";
139  query += " FROM ";
140  query += " `Leaderboard_clan` ";
141  query += " WHERE ";
142  query += " `clanid` = ? ";
143  query += ") AS `end` ON rp.rank <= CASE WHEN end.end_rank <= 4 THEN 10 ELSE end.end_rank + 5 END ";
144  query += "ORDER BY ";
145  query += " `rank` ASC";
146 
147  int input_clanid = clan.GetClanId();
148 
149  int output_rank;
150  int output_clanid;
151  char output_name[VARCHAR_LEN(32)];
152  char output_tag[VARCHAR_LEN(3)];
153  uint32_t output_score;
154  uint32_t output_wins;
155  uint32_t output_losses;
156  uint32_t output_draws;
157 
158  // Allocate input binds
159  MYSQL_BIND* input_bind = (MYSQL_BIND *)calloc(2, sizeof(MYSQL_BIND));
160  input_bind[0].buffer_type = MYSQL_TYPE_LONG;
161  input_bind[0].buffer = &input_clanid;
162  input_bind[0].is_unsigned = false;
163  input_bind[1].buffer_type = MYSQL_TYPE_LONG;
164  input_bind[1].buffer = &input_clanid;
165  input_bind[1].is_unsigned = false;
166 
167  // Allocate output binds
168  MYSQL_BIND* output_bind = (MYSQL_BIND *)calloc(8, sizeof(MYSQL_BIND));
169  output_bind[0].buffer_type = MYSQL_TYPE_LONG;
170  output_bind[0].buffer = &output_rank;
171  output_bind[0].is_unsigned = false;
172  output_bind[1].buffer_type = MYSQL_TYPE_LONG;
173  output_bind[1].buffer = &output_clanid;
174  output_bind[1].is_unsigned = false;
175  output_bind[2].buffer_type = MYSQL_TYPE_VAR_STRING;
176  output_bind[2].buffer = &output_name;
177  output_bind[2].buffer_length = VARCHAR_LEN(32);
178  output_bind[3].buffer_type = MYSQL_TYPE_VAR_STRING;
179  output_bind[3].buffer = &output_tag;
180  output_bind[3].buffer_length = VARCHAR_LEN(3);
181  output_bind[4].buffer_type = MYSQL_TYPE_LONG;
182  output_bind[4].buffer = &output_score;
183  output_bind[4].is_unsigned = true;
184  output_bind[5].buffer_type = MYSQL_TYPE_LONG;
185  output_bind[5].buffer = &output_wins;
186  output_bind[5].is_unsigned = true;
187  output_bind[6].buffer_type = MYSQL_TYPE_LONG;
188  output_bind[6].buffer = &output_losses;
189  output_bind[6].is_unsigned = true;
190  output_bind[7].buffer_type = MYSQL_TYPE_LONG;
191  output_bind[7].buffer = &output_draws;
192  output_bind[7].is_unsigned = true;
193 
194  // Prepare and execute with binds
195  MYSQL_STMT* statement;
196 
197  if(
198  !this->_init(&statement) ||
199  !this->_prepare(statement, query, input_bind) ||
200  !this->_execute(statement, output_bind)
201  )
202  {
203  // Cleanup
204  free(input_bind);
205  free(output_bind);
206 
207  return false;
208  }
209 
210  // Fetch and process rows
211  while (true)
212  {
213  int status = mysql_stmt_fetch(statement);
214 
215  if (status == 1 || status == MYSQL_NO_DATA)
216  break;
217 
218  Battlefield::Clan clan;
219 
220  clan.SetClanId(output_clanid);
221  clan.SetName(output_name);
222  clan.SetTag(output_tag);
223  clan.SetScore(output_score);
224  clan.SetWins(output_wins);
225  clan.SetLosses(output_losses);
226  clan.SetDraws(output_draws);
227 
228  rank_clans.insert(std::make_pair(output_rank, clan));
229  }
230 
231  // Cleanup
232  mysql_stmt_free_result(statement);
233  mysql_stmt_close(statement);
234  free(input_bind);
235  free(output_bind);
236 
237  return true;
238 }
239 
241 {
242  std::lock_guard<std::mutex> guard(this->_mutex); // database lock
243 
244  std::string query = "";
245  query += "CALL CreateLeaderboards()";
246 
247  // Prepare and execute with binds
248  MYSQL_STMT* statement;
249 
250  if(
251  !this->_init(&statement) ||
252  !this->_prepare(statement, query) ||
253  !this->_execute(statement)
254  )
255  {
256  return false;
257  }
258 
259  // Cleanup
260  mysql_stmt_free_result(statement);
261  mysql_stmt_close(statement);
262 
263  return true;
264 }
Represents a clan in the Battlefield game.
Definition: clan.h:54
bool _prepare(MYSQL_STMT *statement, const std::string &query)
Prepares a MySQL statement with a query.
Definition: database.cpp:59
bool _init(MYSQL_STMT **statement)
Initializes a MySQL statement object.
Definition: database.cpp:45
bool queryLeaderboardClan(Battlefield::RankClans &rank_clans, uint32_t limit=10, uint32_t offset=0)
Queries clan leaderboard.
bool _execute(MYSQL_STMT *statement)
Executes a prepared MySQL statement.
Definition: database.cpp:94
bool createLeaderboards()
Creates leaderboard tables with ranked players.
std::mutex _mutex
Mutex for thread-safe access to the database connection.
Definition: database.h:42
bool queryLeaderboardClanByClanId(Battlefield::RankClans &rank_clans, const Battlefield::Clan &clan)
Queries clan leaderboard by clan ID with the clan in the middle.