#include "client.h" #include std::map > Client::client_list; Client::p Client::create(Connection::p c, std::string n) { Client::p p(new Client(c, n)); p->start(); return p; } Client::p Client::exists(Message::Login::p login_msg) { if(client_list.count(login_msg->cookie)) { // Obtain shared pointer to existing client. Client::p client = client_list[login_msg->cookie].lock(); // TODO: Check if game still is ongoing? // A client should only be reconnected to if still participating in an active game. // It may however be proven that a client is always destructed if the game has ended, so this test might not be neccessary. return client; } else { // No or invalid existing client found. return Client::p(); } } Client::Client(Connection::p c, std::string n) : connection(c), timer(c->socket.get_io_service()), nick_(n) { } Client::~Client() { client_list.erase(cookie); } void Client::reconnect(Connection::p c) { connection = c; // TODO: Resync client. } void Client::start() { // Create a unique cookie for this client. cookie = uint64_t(this); // TODO: Use a better cookie source. // Store a weak pointer to this client. client_list[cookie] = shared_from_this(); // Logged in to lobby. connection->send(make_shared(Message::LoginResponse::Lobby)); } void Client::handle_login(Message::p msg, boost::function login_callback) { if(msg->type != Message::Types::Login) { return; } Message::Login::p login_msg = dynamic_pointer_cast(msg); // Check if nick is invalid. if(login_msg->nick.size() == 0) { connection->send(make_shared(Message::LoginResponse::Invalid)); connection->recv(boost::bind(&Client::handle_login, shared_from_this(), _1, login_callback)); return; } connection->send(make_shared(Message::LoginResponse::Lobby)); nick_ = login_msg->nick; login_callback(shared_from_this()); } void Client::handle_lobby(Message::p msg, boost::function lobby_callback) { if(msg->type != Message::Types::LobbyAction) { return; } Message::LobbyAction::p lobby_msg = dynamic_pointer_cast(msg); lobby_callback(lobby_msg->index); } void Client::handle_ready(Message::p msg, boost::function ready_callback) { if(msg->type != Message::Types::Ready) { // Wait for another message. connection->recv(boost::bind(&Client::handle_ready, shared_from_this(), _1, ready_callback)); return; } ready_callback(); } void Client::handle_action(Message::p msg, boost::function action_callback, Actions possible_actions) { if(msg->type != Message::Types::RoundAction) { return; } Message::RoundAction::p action_msg = dynamic_pointer_cast(msg); // Check if the action is valid. if(possible_actions.contains(action_msg->action)) { action_callback(action_msg->action); } else { action_callback(possible_actions.back()); } } void Client::lobby_status(const std::vector& game_modes, boost::function callback) { Message::LobbyStatus::p msg = make_shared(); msg->game_modes = game_modes; connection->send(msg); connection->recv(boost::bind(&Client::handle_lobby, shared_from_this(), _1, callback)); } std::string Client::nick() { return nick_; } void Client::game_start(boost::function callback, std::vector players) { if(connection) { Message::GameStart::p msg = make_shared(); msg->players = players; connection->send(msg); connection->recv(boost::bind(&Client::handle_ready, shared_from_this(), _1, callback)); } else { callback(); } } void Client::round_start() { if(connection) { connection->send(make_shared()); } } void Client::round_state(const PlayerState& pl_d, const PlayerState& pl_r, const PlayerState& pl_u, const PlayerState& pl_l, const GameState& g, const Actions& a) { if(connection) { connection->send(make_shared(pl_d, pl_r, pl_u, pl_l, g, a)); } } void Client::round_end(Message::RoundEnd::p msg, boost::function callback) { if(connection) { connection->send(msg); // Check if we're waiting for ready. if(callback) { connection->recv(boost::bind(&Client::handle_ready, shared_from_this(), _1, callback)); } } else { if(callback){callback();} } } void Client::get_action(boost::function callback, Actions expected_actions) { if(connection) { connection->recv(boost::bind(&Client::handle_action, shared_from_this(), _1, callback, expected_actions)); } else { callback(expected_actions.back()); } } void Client::game_end(Message::GameEnd::p msg, boost::function callback) { if(connection) { connection->send(msg); if(callback) { connection->recv(boost::bind(&Client::handle_ready, shared_from_this(), _1, callback)); } } else { callback(); } } unsigned int ClientDumb::id() { return 0; } std::string ClientDumb::nick() { return "CPU"; } void ClientDumb::game_start(boost::function callback, std::vector players) { callback(); } void ClientDumb::round_start() { } void ClientDumb::round_state(const PlayerState& pl_d, const PlayerState& pl_r, const PlayerState& pl_u, const PlayerState& pl_l, const GameState& g, const Actions& a) { } void ClientDumb::round_end(Message::RoundEnd::p msg, boost::function callback) { if(callback) callback(); } void ClientDumb::get_action(boost::function callback, Actions expected_actions) { callback(expected_actions.back()); } void ClientDumb::game_end(Message::GameEnd::p msg, boost::function callback) { callback(); }