23 #ifndef JWT_GAME_SERVER_MATCHMAKING_SERVER_HPP
24 #define JWT_GAME_SERVER_MATCHMAKING_SERVER_HPP
26 #include "base_server.hpp"
28 #include <unordered_set>
35 using namespace std::chrono_literals;
38 using std::unordered_set;
45 template<
typename matchmaker,
typename jwt_clock,
typename json_traits,
46 typename server_config,
typename close_reasons = default_close_reasons>
51 typename matchmaker::player_traits,
66 using game = std::tuple<vector<session_id>, session_id, json>;
67 using message = pair<session_id, std::string>;
68 using session_data =
typename matchmaker::session_data;
73 struct connection_update {
74 connection_update(
const combined_id& i) : id(i),
75 disconnection(
true) {}
76 connection_update(
const combined_id& i, json&& d) : id(i),
77 data(std::move(d)), disconnection(
false) {}
92 const jwt::verifier<jwt_clock, json_traits>& v,
93 function<std::string(
const combined_id&,
const json&)> f,
94 std::chrono::milliseconds t
95 ) : m_jwt_server{v, f, t}
97 m_jwt_server.set_open_handler(
99 &matchmaking_server::player_connect,
101 simple_web_game_server::_1,
102 simple_web_game_server::_2
105 m_jwt_server.set_close_handler(
107 &matchmaking_server::player_disconnect,
109 simple_web_game_server::_1
112 m_jwt_server.set_message_handler(
114 &matchmaking_server::process_message,
116 simple_web_game_server::_1,
117 simple_web_game_server::_2
124 const jwt::verifier<jwt_clock, json_traits>& v,
125 function<std::string(
const combined_id&,
const json&)> f
130 m_jwt_server.set_tls_init_handler(f);
134 void run(uint16_t port,
bool unlock_address =
false) {
135 m_jwt_server.run(port, unlock_address);
140 m_jwt_server.process_messages();
146 m_jwt_server.reset();
153 lock_guard<mutex> guard(m_match_lock);
154 m_session_data.clear();
155 m_session_players.clear();
156 m_connection_updates.second.clear();
159 lock_guard<mutex> guard(m_connection_update_list_lock);
160 m_connection_updates.first.clear();
162 m_match_condition.notify_one();
167 return m_jwt_server.get_player_count();
171 return m_jwt_server.is_running();
182 auto time_start = clock::now();
183 pair<vector<session_id>, vector<session_id> > finished_sessions;
185 while(m_jwt_server.is_running()) {
186 unique_lock<mutex> match_lock(m_match_lock);
188 if(!m_matchmaker.can_match(m_session_data)) {
190 unique_lock<mutex> conn_lock(m_connection_update_list_lock);
191 while(m_connection_updates.first.empty()) {
192 m_match_condition.wait(conn_lock);
193 if(!m_jwt_server.is_running()) {
201 std::chrono::duration_cast<std::chrono::milliseconds>(
202 clock::now() - time_start
204 const long dt_count = delta_time.count();
206 if(delta_time < timestep) {
208 std::this_thread::sleep_for(std::min(1us, timestep-delta_time+1us));
210 time_start = clock::now();
212 process_connection_updates(finished_sessions.second);
216 for(
const session_id& sid : finished_sessions.first) {
217 spdlog::trace(
"erasing data for session {}", sid);
218 m_session_data.erase(sid);
219 m_session_players.erase(sid);
221 finished_sessions.first.clear();
222 std::swap(finished_sessions.first, finished_sessions.second);
226 vector<pair<session_id, std::string> > messages;
227 m_matchmaker.match(games, messages, m_session_data, dt_count);
229 for(message& msg : messages) {
230 auto session_players_it = m_session_players.find(msg.first);
231 if(session_players_it != m_session_players.end()) {
232 for(player_id pid : session_players_it->second) {
233 m_jwt_server.send_message(
234 { pid, msg.first }, std::move(msg.second)
241 for(game& g : games) {
242 vector<session_id> sessions;
245 std::tie(sessions, game_sid, game_data) = std::move(g);
247 spdlog::trace(
"matched game: {}", game_data.dump());
249 for(session_id& sid : sessions) {
250 m_jwt_server.complete_session(
251 sid, game_sid, game_data
253 finished_sessions.first.push_back(sid);
261 void process_connection_updates(vector<session_id>& finished_sessions) {
263 unique_lock<mutex> conn_lock(m_connection_update_list_lock);
264 std::swap(m_connection_updates.first, m_connection_updates.second);
267 for(connection_update& update : m_connection_updates.second) {
268 auto it = m_session_data.find(update.id.session);
269 if(update.disconnection) {
270 if(it != m_session_data.end()) {
272 "processing disconnection for session {}", update.id.session
274 m_jwt_server.complete_session(
277 m_matchmaker.get_cancel_data()
279 m_session_data.erase(it);
280 m_session_players.erase(update.id.session);
281 finished_sessions.push_back(update.id.session);
285 "processing connection for session {}", update.id.session
287 if(it == m_session_data.end()) {
288 session_data data{update.data};
290 if(data.is_valid()) {
291 m_session_data.emplace(
292 update.id.session, std::move(data)
294 m_session_players.emplace(
295 update.id.session, set<player_id>{ update.id.player }
298 m_jwt_server.complete_session(
301 m_matchmaker.get_cancel_data()
303 finished_sessions.push_back(update.id.session);
306 m_session_players.at(update.id.session).insert(update.id.player);
310 m_connection_updates.second.clear();
318 void process_message(
const combined_id&
id, std::string&& data) {
320 lock_guard<mutex> guard(m_connection_update_list_lock);
321 m_connection_updates.first.emplace_back(
id);
323 m_match_condition.notify_one();
326 void player_connect(
const combined_id&
id, json&& data) {
328 lock_guard<mutex> guard(m_connection_update_list_lock);
329 m_connection_updates.first.emplace_back(
333 m_match_condition.notify_one();
336 void player_disconnect(
const combined_id&
id) {
338 lock_guard<mutex> guard(m_connection_update_list_lock);
339 m_connection_updates.first.emplace_back(
id);
341 m_match_condition.notify_one();
345 matchmaker m_matchmaker;
347 unordered_map<session_id, session_data, id_hash> m_session_data;
348 unordered_map<session_id, set<player_id>, id_hash> m_session_players;
352 vector<connection_update>,
353 vector<connection_update>
354 > m_connection_updates;
355 mutex m_connection_update_list_lock;
357 condition_variable m_match_condition;
359 jwt_base_server m_jwt_server;
A WebSocket server that performs authentication and manages sessions.
Definition: base_server.hpp:107
std::chrono::high_resolution_clock clock
The type of clock for server time-step management.
Definition: base_server.hpp:131
typename combined_id::player_id player_id
The type of the player component of a client id.
Definition: base_server.hpp:122
typename player_traits::id combined_id
The type of a client id.
Definition: base_server.hpp:120
typename combined_id::session_id session_id
The type of the session component of a client id.
Definition: base_server.hpp:124
websocketpp::lib::shared_ptr< websocketpp::lib::asio::ssl::context > ssl_context_ptr
The type of a pointer to an asio ssl context.
Definition: base_server.hpp:135
typename json_traits::json json
The type of a json object.
Definition: base_server.hpp:129
typename combined_id::hash id_hash
The type of the hash struct for all id types.
Definition: base_server.hpp:126
A matchmaking server built on the base_server class.
Definition: matchmaking_server.hpp:47
void set_tls_init_handler(function< ssl_context_ptr(connection_hdl)> f)
Sets the tls_init_handler for the underlying base_server.
Definition: matchmaking_server.hpp:129
void stop()
Stops the server and clears all data and connections.
Definition: matchmaking_server.hpp:150
void match_players(std::chrono::milliseconds timestep)
Loop to match players.
Definition: matchmaking_server.hpp:181
matchmaking_server(const jwt::verifier< jwt_clock, json_traits > &v, function< std::string(const combined_id &, const json &)> f, std::chrono::milliseconds t)
The constructor for the matchmaking_server class.
Definition: matchmaking_server.hpp:91
void run(uint16_t port, bool unlock_address=false)
Runs the underlying base_server.
Definition: matchmaking_server.hpp:134
matchmaking_server(const jwt::verifier< jwt_clock, json_traits > &v, function< std::string(const combined_id &, const json &)> f)
Constructs the underlying base_server with a default time-step.
Definition: matchmaking_server.hpp:123
std::size_t get_player_count()
Returns the number of verified clients connected.
Definition: matchmaking_server.hpp:166
void reset()
Stops, clears, and resets the server so it may be run again.
Definition: matchmaking_server.hpp:144
void process_messages()
Runs the process_messages loop on the underlying base_server.
Definition: matchmaking_server.hpp:139
Definition: base_server.hpp:52