summaryrefslogtreecommitdiff
path: root/src/client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/client.cpp')
-rw-r--r--src/client.cpp213
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();
+}