Mercurial > malikania
changeset 154:614ac46dac3e
Client: add basic network support
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 13 Dec 2017 13:48:56 +0100 |
parents | 43a26de57fe7 |
children | f67c187bfceb |
files | libclient/CMakeLists.txt libclient/malikania/client/client.cpp libclient/malikania/client/client.hpp libclient/malikania/client/dispatcher.hpp libclient/malikania/client/state/login_state.cpp libclient/malikania/client/state/login_state.hpp server/CMakeLists.txt server/main.cpp |
diffstat | 8 files changed, 195 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/libclient/CMakeLists.txt Wed Dec 13 13:46:51 2017 +0100 +++ b/libclient/CMakeLists.txt Wed Dec 13 13:48:56 2017 +0100 @@ -43,7 +43,6 @@ ${libmlk-client_SOURCE_DIR}/malikania/client/state/map_state.hpp ${libmlk-client_SOURCE_DIR}/malikania/client/state/login_state.hpp ${libmlk-client_SOURCE_DIR}/malikania/client/state/lobby_state.hpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state/splashscreen_state.hpp ${libmlk-client_SOURCE_DIR}/malikania/client/theme.hpp ${libmlk-client_SOURCE_DIR}/malikania/client/unique_layout.hpp ${libmlk-client_SOURCE_DIR}/malikania/client/widget.hpp @@ -69,7 +68,6 @@ ${libmlk-client_SOURCE_DIR}/malikania/client/state/map_state.cpp ${libmlk-client_SOURCE_DIR}/malikania/client/state/login_state.cpp ${libmlk-client_SOURCE_DIR}/malikania/client/state/lobby_state.cpp - ${libmlk-client_SOURCE_DIR}/malikania/client/state/splashscreen_state.cpp ${libmlk-client_SOURCE_DIR}/malikania/client/theme.cpp ${libmlk-client_SOURCE_DIR}/malikania/client/unique_layout.cpp ${libmlk-client_SOURCE_DIR}/malikania/client/widget.cpp
--- a/libclient/malikania/client/client.cpp Wed Dec 13 13:46:51 2017 +0100 +++ b/libclient/malikania/client/client.cpp Wed Dec 13 13:48:56 2017 +0100 @@ -17,6 +17,7 @@ */ #include <iostream> +#include <thread> #include "client.hpp" #include "connection.hpp" @@ -27,18 +28,52 @@ namespace client { -client::client(boost::asio::io_service&, +client::client(boost::asio::io_service& service, mlk::client::connection& connection, mlk::client::window& window) noexcept - : connection_(connection) + : service_(service) + , connection_(connection) , window_(window) { } client::~client() noexcept = default; -void client::connect(std::string, std::uint16_t) +void client::recv() +{ + // Network thread space. + connection_.recv([this] (auto code, auto message) { + if (!code) + recv(); + + std::lock_guard<std::mutex> lock(nmutex_); + + nqueue_.push_back(std::bind(&client::handle_message, this, code, message)); + }); +} + +void client::connect(std::string host, std::uint16_t port) { + service_.post([this, host, port] () { + connection_.connect(host, port, [this] (auto code) { + // Start receiveing on success. + if (!code) + recv(); + + // Push the result to the main loop queue. + std::lock_guard<std::mutex> lock(nmutex_); + + nqueue_.push_back(std::bind(&client::handle_connect, this, code)); + }); + }); +} + +void client::send(nlohmann::json message) +{ + service_.post([this, message] () { + // TODO: error checking. + connection_.send(std::move(message), nullptr); + }); } void client::set_state(std::unique_ptr<state> state) @@ -46,6 +81,18 @@ state_next_ = std::move(state); } +void client::handle_connect(const boost::system::error_code& code) +{ + if (state_) + state_->handle_connect(code); +} + +void client::handle_message(const boost::system::error_code& code, const nlohmann::json& msg) +{ + if (state_) + state_->handle_message(code, msg); +} + void client::handle_key_down(const key_event& ev) { window_.handle_key_down(ev); @@ -97,25 +144,43 @@ void client::handle_quit() { window_.handle_quit(); + service_.stop(); } void client::run() { - while (window_.is_open()) - run_one(); -} + std::thread t([this] () { + // TODO: change to an atomic member variable. + while (window_.is_open()) { + service_.reset(); + service_.run(); + } + }); + + while (window_.is_open()) { + // Network events. + { + std::lock_guard<std::mutex> lock(nmutex_); + + for (auto& ev : nqueue_) + ev(); -void client::run_one() -{ - if (state_next_) - state_ = std::move(state_next_); + nqueue_.clear(); + } + + // State and input events. + if (state_next_) + state_ = std::move(state_next_); - window_.poll(*this); + window_.poll(*this); - if (state_) { - state_->update(*this); - state_->draw(*this); + if (state_) { + state_->update(*this); + state_->draw(*this); + } } + + t.join(); } } // !client
--- a/libclient/malikania/client/client.hpp Wed Dec 13 13:46:51 2017 +0100 +++ b/libclient/malikania/client/client.hpp Wed Dec 13 13:48:56 2017 +0100 @@ -24,7 +24,10 @@ * \brief Main client game class. */ +#include <functional> #include <memory> +#include <mutex> +#include <vector> #include <boost/asio.hpp> @@ -45,10 +48,17 @@ */ class client : public dispatcher { private: + boost::asio::io_service& service_; + mlk::client::connection& connection_; mlk::client::window& window_; + std::unique_ptr<state> state_; std::unique_ptr<state> state_next_; + std::mutex nmutex_; + std::vector<std::function<void ()>> nqueue_; + + void recv(); public: /** @@ -67,6 +77,8 @@ */ virtual ~client() noexcept; +#if 0 + /** * Get the connection object. * @@ -86,6 +98,7 @@ { return connection_; } +#endif /** * Get the window. @@ -118,6 +131,13 @@ void connect(std::string host, std::uint16_t port); /** + * Send a message. + * + * \param message the message + */ + void send(nlohmann::json message); + + /** * Set the client state. * * \param state the state @@ -130,9 +150,14 @@ void run(); /** - * Same as run except that it does not block. + * \copydoc dispatcher::handle_connect */ - void run_one(); + void handle_connect(const boost::system::error_code& code) override; + + /** + * \copydoc dispatcher::handle_message + */ + void handle_message(const boost::system::error_code& code, const nlohmann::json& msg) override; /** * \copydoc dispatcher::handle_key_down
--- a/libclient/malikania/client/dispatcher.hpp Wed Dec 13 13:46:51 2017 +0100 +++ b/libclient/malikania/client/dispatcher.hpp Wed Dec 13 13:48:56 2017 +0100 @@ -24,6 +24,10 @@ * \brief Client event dispatcher. */ +#include <boost/system/error_code.hpp> + +#include <json.hpp> + #include "mouse.hpp" #include "key.hpp" #include "point.hpp" @@ -91,6 +95,28 @@ virtual ~dispatcher() noexcept = default; /** + * Connection event. + * + * \param code the result code + */ + virtual void handle_connect(const boost::system::error_code& code) + { + (void)code; + } + + /** + * Message event. + * + * \param code the result code + * \param msg the network message + */ + virtual void handle_message(const boost::system::error_code& code, const nlohmann::json& msg) + { + (void)code; + (void)msg; + } + + /** * Key down event. * * \param ev the event
--- a/libclient/malikania/client/state/login_state.cpp Wed Dec 13 13:46:51 2017 +0100 +++ b/libclient/malikania/client/state/login_state.cpp Wed Dec 13 13:48:56 2017 +0100 @@ -28,6 +28,24 @@ namespace client { +void login_state::do_connect() +{ + state_ = state_t::connecting; + status_ = "Connecting..."; + client_.connect("localhost", 3320); +} + +void login_state::do_auth() +{ + status_ = "Authenticating"; + state_ = state_t::authenticating; + client_.send({ + { "command", "auth" }, + { "login", unicode::to_utf8(login_) }, + { "password", unicode::to_utf8(password_) } + }); +} + login_state::login_state(client& clt) : client_(clt) { @@ -46,6 +64,22 @@ { } +void login_state::handle_connect(const boost::system::error_code& code) +{ + if (code) + status_ = code.message(); + else + do_auth(); +} + +void login_state::handle_message(const boost::system::error_code& code, const nlohmann::json& msg) +{ + if (code) + status_ = code.message(); + else + status_ = msg["error"]; +} + void login_state::handle_key_down(const key_event& ev) { switch (ev.key) { @@ -62,8 +96,8 @@ password_.pop_back(); break; case key::enter: - if (index_ == 1) - client_.set_state(std::make_unique<lobby_state>(client_)); + if (index_ == 1 && state_ == state_t::disconnected) + do_connect(); break; default: break; @@ -86,6 +120,8 @@ win.draw_text(unicode::to_utf8(login_), font, {70, 50}); if (!password_.empty()) win.draw_text(std::string(password_.length(), '*'), font, {70, 70}); + if (!status_.empty()) + win.draw_text(status_, font, {70, 90}); win.present(); }
--- a/libclient/malikania/client/state/login_state.hpp Wed Dec 13 13:46:51 2017 +0100 +++ b/libclient/malikania/client/state/login_state.hpp Wed Dec 13 13:48:56 2017 +0100 @@ -24,7 +24,7 @@ * \brief Login state. */ -#include "state.hpp" +#include <malikania/client/state.hpp> namespace mlk { @@ -35,16 +35,29 @@ */ class login_state : public state { private: + enum class state_t { + disconnected, + connecting, + authenticating + }; + client& client_; + state_t state_{state_t::disconnected}; std::size_t index_{0}; std::u32string login_; std::u32string password_; + std::string status_; + + void do_connect(); + void do_auth(); public: login_state(client& clt); void update(client&) override; void draw(client& clt) override; + void handle_connect(const boost::system::error_code& code) override; + void handle_message(const boost::system::error_code& code, const nlohmann::json& msg) override; void handle_key_down(const key_event& ev) override; void handle_text(const text_event& ev) override; };
--- a/server/CMakeLists.txt Wed Dec 13 13:46:51 2017 +0100 +++ b/server/CMakeLists.txt Wed Dec 13 13:48:56 2017 +0100 @@ -24,4 +24,5 @@ ${mlk-server_SOURCE_DIR}/main.cpp LIBRARIES libmlk-server + libmlk-db-sqlite )
--- a/server/main.cpp Wed Dec 13 13:46:51 2017 +0100 +++ b/server/main.cpp Wed Dec 13 13:48:56 2017 +0100 @@ -16,35 +16,22 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <iostream> +#include <cstdio> -#include <malikania/server/db/dynlib_database.hpp> +#include <malikania/server/db/sqlite_database.hpp> + #include <malikania/server/server.hpp> int main() { -#if 0 - mlk::server::settings sv_params{ - 3320, - "/home/markand/null/server.crt", - "/home/markand/null/server.key", - }; + std::remove("server.db"); - mlk::server::dynlib_database db({ - { "type", "sqlite" }, - { "path", "/home/markand/kingdom.db" } - }); + boost::asio::io_service io; - boost::asio::io_service service; - - try { - mlk::server::server server(service, db, sv_params); + mlk::server::sqlite_database db("server.db"); + mlk::server::settings settings(3320U, "server.crt", "server.key"); + mlk::server::server server(io, db, settings); - for (;;) { - service.run(); - } - } catch (const std::exception& ex) { - std::cerr << "fatal: " << ex.what() << std::endl; - } -#endif + for (;;) + io.run(); }