diff options
Diffstat (limited to 'src/client.cpp')
-rw-r--r-- | src/client.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/client.cpp b/src/client.cpp new file mode 100644 index 0000000..afec605 --- /dev/null +++ b/src/client.cpp @@ -0,0 +1,213 @@ +#include "client.h" + +#include <boost/bind.hpp> + +std::map<uint64_t, boost::weak_ptr<Client> > 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>(Message::LoginResponse::Lobby)); +} + +void Client::handle_login(Message::p msg, boost::function<void (Client::p)> login_callback) { + if(msg->type != Message::Types::Login) { + return; + } + + Message::Login::p login_msg = dynamic_pointer_cast<Message::Login>(msg); + + // Check if nick is invalid. + if(login_msg->nick.size() == 0) { + connection->send(make_shared<Message::LoginResponse>(Message::LoginResponse::Invalid)); + connection->recv(boost::bind(&Client::handle_login, shared_from_this(), _1, login_callback)); + return; + } + + connection->send(make_shared<Message::LoginResponse>(Message::LoginResponse::Lobby)); + + nick_ = login_msg->nick; + + login_callback(shared_from_this()); +} + +void Client::handle_lobby(Message::p msg, boost::function<void (int)> lobby_callback) { + if(msg->type != Message::Types::LobbyAction) { + return; + } + + Message::LobbyAction::p lobby_msg = dynamic_pointer_cast<Message::LobbyAction>(msg); + + lobby_callback(lobby_msg->index); +} + +void Client::handle_ready(Message::p msg, boost::function<void ()> 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<void (Action)> action_callback, Actions possible_actions) { + if(msg->type != Message::Types::RoundAction) { + return; + } + + Message::RoundAction::p action_msg = dynamic_pointer_cast<Message::RoundAction>(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<std::string>& game_modes, boost::function<void (int)> callback) { + Message::LobbyStatus::p msg = make_shared<Message::LobbyStatus>(); + + 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<void ()> callback, std::vector<std::string> players) { + if(connection) { + Message::GameStart::p msg = make_shared<Message::GameStart>(); + + 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<Message::RoundStart>()); + } +} + +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<Message::RoundState>(pl_d, pl_r, pl_u, pl_l, g, a)); + } +} + +void Client::round_end(Message::RoundEnd::p msg, boost::function<void ()> 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<void (Action)> 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<void ()> 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<void ()> callback, std::vector<std::string> 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<void ()> callback) { + if(callback) callback(); +} + +void ClientDumb::get_action(boost::function<void (Action)> callback, Actions expected_actions) { + callback(expected_actions.back()); +} + +void ClientDumb::game_end(Message::GameEnd::p msg, boost::function<void ()> callback) { + callback(); +} |