From fa3c4a14546d73ddc2671cd5cc58208839bf7173 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 23 Nov 2015 14:47:30 +0100 Subject: [PATCH] make command output visible to player(s) --- doc/todo | 1 - src/server/ClientConnection.hpp | 7 ++ src/server/NetworkCLIFeedback.hpp | 31 +++++++ src/server/Server.hpp | 3 +- src/server/net.cpp | 40 +++++++- src/shared/CLI.hpp | 9 +- src/shared/CLIContext.hpp | 38 ++++++++ src/shared/cli.cpp | 33 +++---- src/shared/commands.hpp | 2 +- src/standalone/DirectCLIFeedback.hpp | 31 +++++++ src/standalone/MasterState.hpp | 2 + src/standalone/PreloadState.cpp | 32 ------- src/standalone/UnloadState.cpp | 54 ----------- .../{MasterState.cpp => standalone.cpp} | 91 ++++++++++++++++++- 14 files changed, 255 insertions(+), 119 deletions(-) create mode 100644 src/server/NetworkCLIFeedback.hpp create mode 100644 src/shared/CLIContext.hpp create mode 100644 src/standalone/DirectCLIFeedback.hpp delete mode 100644 src/standalone/PreloadState.cpp delete mode 100644 src/standalone/UnloadState.cpp rename src/standalone/{MasterState.cpp => standalone.cpp} (75%) diff --git a/doc/todo b/doc/todo index bbf432c..9df0ec4 100644 --- a/doc/todo +++ b/doc/todo @@ -20,7 +20,6 @@ font rendering command line more commands pls - and show me their output persistence diff --git a/src/server/ClientConnection.hpp b/src/server/ClientConnection.hpp index 57a34e4..3ab0453 100644 --- a/src/server/ClientConnection.hpp +++ b/src/server/ClientConnection.hpp @@ -2,6 +2,7 @@ #define BLANK_SERVER_CLIENTCONNECTION_HPP_ #include "ChunkTransmitter.hpp" +#include "NetworkCLIFeedback.hpp" #include "Server.hpp" #include "../app/IntervalTimer.hpp" #include "../ui/DirectInput.hpp" @@ -10,6 +11,7 @@ #include "../world/EntityState.hpp" #include "../world/Player.hpp" +#include #include #include #include @@ -39,6 +41,8 @@ public: Connection &GetConnection() noexcept { return conn; } bool Disconnected() const noexcept { return conn.Closed(); } + Server &GetServer() noexcept { return server; } + /// prepare a packet of given type template Type Prepare() const noexcept { @@ -63,6 +67,8 @@ public: bool ChunkInRange(const glm::ivec3 &) const noexcept; + std::uint16_t SendMessage(std::uint8_t type, std::uint32_t from, const std::string &msg); + private: struct SpawnStatus { // the entity in question @@ -105,6 +111,7 @@ private: Server &server; Connection conn; std::unique_ptr input; + std::unique_ptr cli_ctx; const Model *player_model; std::list spawns; unsigned int confirm_wait; diff --git a/src/server/NetworkCLIFeedback.hpp b/src/server/NetworkCLIFeedback.hpp new file mode 100644 index 0000000..25a8781 --- /dev/null +++ b/src/server/NetworkCLIFeedback.hpp @@ -0,0 +1,31 @@ +#ifndef BLANK_SERVER_NETWORKCLIFEEDBACK_HPP_ +#define BLANK_SERVER_NETWORKCLIFEEDBACK_HPP_ + +#include "../shared/CLIContext.hpp" + + +namespace blank { + +namespace server { + +class ClientConnection; + +class NetworkCLIFeedback +: public CLIContext { + +public: + NetworkCLIFeedback(Player &, ClientConnection &); + + void Error(const std::string &) override; + void Message(const std::string &) override; + void Broadcast(const std::string &) override; + +private: + ClientConnection &conn; + +}; + +} +} + +#endif diff --git a/src/server/Server.hpp b/src/server/Server.hpp index 40905c8..9b89ab1 100644 --- a/src/server/Server.hpp +++ b/src/server/Server.hpp @@ -14,6 +14,7 @@ namespace blank { class ChunkIndex; +class CLIContext; class Model; class Player; class WorldSave; @@ -52,7 +53,7 @@ public: void SetBlock(Chunk &, int, const Block &) override; /// for use by client connections when they receive a line from the player - void DispatchMessage(Player &, const std::string &); + void DispatchMessage(CLIContext &, const std::string &); /// send message to all connected clients void DistributeMessage(std::uint8_t type, std::uint32_t ref, const std::string &msg); diff --git a/src/server/net.cpp b/src/server/net.cpp index d160889..e8325da 100644 --- a/src/server/net.cpp +++ b/src/server/net.cpp @@ -439,6 +439,8 @@ void ClientConnection::AttachPlayer(Player &player) { input.reset(new DirectInput(server.GetWorld(), player, server)); PlayerEntity().Ref(); + cli_ctx.reset(new NetworkCLIFeedback(player, *this)); + old_base = PlayerChunks().Base(); ExactLocation::Coarse begin = PlayerChunks().CoordsBegin(); ExactLocation::Coarse end = PlayerChunks().CoordsEnd(); @@ -469,6 +471,7 @@ void ClientConnection::DetachPlayer() { server.GetWorldSave().Write(input->GetPlayer()); PlayerEntity().Kill(); PlayerEntity().UnRef(); + cli_ctx.reset(); input.reset(); transmitter.Abort(); chunk_queue.clear(); @@ -629,11 +632,38 @@ void ClientConnection::On(const Packet::Message &pack) { pack.ReadReferral(ref); pack.ReadMessage(msg); - if (type == 1 && HasPlayer()) { - server.DispatchMessage(input->GetPlayer(), msg); + if (type == 1 && cli_ctx) { + server.DispatchMessage(*cli_ctx, msg); } } +uint16_t ClientConnection::SendMessage(uint8_t type, uint32_t from, const string &msg) { + auto pack = Prepare(); + pack.WriteType(type); + pack.WriteReferral(from); + pack.WriteMessage(msg); + return Send(Packet::Message::GetSize(msg)); +} + + +NetworkCLIFeedback::NetworkCLIFeedback(Player &p, ClientConnection &c) +: CLIContext(p) +, conn(c) { + +} + +void NetworkCLIFeedback::Error(const string &msg) { + conn.SendMessage(0, 0, msg); +} + +void NetworkCLIFeedback::Message(const string &msg) { + conn.SendMessage(0, 0, msg); +} + +void NetworkCLIFeedback::Broadcast(const string &msg) { + conn.GetServer().DistributeMessage(0, GetPlayer().GetEntity().ID(), msg); +} + Server::Server( const Config::Network &conf, @@ -788,14 +818,14 @@ void Server::SetBlock(Chunk &chunk, int index, const Block &block) { } } -void Server::DispatchMessage(Player &player, const string &msg) { +void Server::DispatchMessage(CLIContext &ctx, const string &msg) { if (msg.empty()) { return; } if (msg[0] == '/' && msg.size() > 1 && msg[1] != '/') { - cli.Execute(player, msg.substr(1)); + cli.Execute(ctx, msg.substr(1)); } else { - DistributeMessage(1, player.GetEntity().ID(), msg); + DistributeMessage(1, ctx.GetPlayer().GetEntity().ID(), msg); } } diff --git a/src/shared/CLI.hpp b/src/shared/CLI.hpp index b601e57..ab1e3ee 100644 --- a/src/shared/CLI.hpp +++ b/src/shared/CLI.hpp @@ -7,7 +7,7 @@ namespace blank { -class Player; +class CLIContext; class TokenStreamReader; class World; @@ -16,7 +16,7 @@ class CLI { public: struct Command { virtual ~Command(); - virtual void Execute(CLI &, Player &, TokenStreamReader &) = 0; + virtual void Execute(CLI &, CLIContext &, TokenStreamReader &) = 0; }; public: @@ -25,10 +25,7 @@ public: void AddCommand(const std::string &name, Command *); - void Execute(Player &, const std::string &); - - void Message(const std::string &msg); - void Error(const std::string &msg); + void Execute(CLIContext &, const std::string &); private: World &world; diff --git a/src/shared/CLIContext.hpp b/src/shared/CLIContext.hpp new file mode 100644 index 0000000..8de432b --- /dev/null +++ b/src/shared/CLIContext.hpp @@ -0,0 +1,38 @@ +#ifndef BLANK_SHARED_CLICONTEXT_HPP_ +#define BLANK_SHARED_CLICONTEXT_HPP_ + +#include + + +namespace blank { + +class Player; + +class CLIContext { + +public: + explicit CLIContext(Player &p) + : player(p) { } + + /// get the player responsible for all this + Player &GetPlayer() { return player; } + + /// an error has happened and the player should be notified + virtual void Error(const std::string &) = 0; + + /// return to sender + /// use this for output concerning the originator of a command + virtual void Message(const std::string &) = 0; + + /// send a status message to all players + /// use this to announce stuff which may be interesting to anyone + virtual void Broadcast(const std::string &) = 0; + +private: + Player &player; + +}; + +} + +#endif diff --git a/src/shared/cli.cpp b/src/shared/cli.cpp index 6942f78..d4cf525 100644 --- a/src/shared/cli.cpp +++ b/src/shared/cli.cpp @@ -1,4 +1,5 @@ #include "CLI.hpp" +#include "CLIContext.hpp" #include "commands.hpp" #include "../io/TokenStreamReader.hpp" @@ -7,6 +8,7 @@ #include #include +#include using namespace std; @@ -29,7 +31,7 @@ void CLI::AddCommand(const string &name, Command *cmd) { commands[name] = cmd; } -void CLI::Execute(Player &player, const string &line) { +void CLI::Execute(CLIContext &ctx, const string &line) { stringstream s(line); TokenStreamReader args(s); if (!args.HasMore()) { @@ -37,44 +39,39 @@ void CLI::Execute(Player &player, const string &line) { return; } if (args.Peek().type != Token::IDENTIFIER) { - Error("I don't understand"); + ctx.Error("I don't understand"); return; } string name; args.ReadIdentifier(name); auto entry = commands.find(name); if (entry == commands.end()) { - Error(name + ": command not found"); + ctx.Error(name + ": command not found"); return; } try { - entry->second->Execute(*this, player, args); + entry->second->Execute(*this, ctx, args); } catch (exception &e) { - Error(name + ": " + e.what()); + ctx.Error(name + ": " + e.what()); } catch (...) { - Error(name + ": unknown execution error"); + ctx.Error(name + ": unknown execution error"); } } -void CLI::Message(const string &msg) { - // TODO: display message to player - cout << msg << endl; -} - -void CLI::Error(const string &msg) { - Message("CLI error: " + msg); -} - CLI::Command::~Command() { } -void TeleportCommand::Execute(CLI &cli, Player &player, TokenStreamReader &args) { +void TeleportCommand::Execute(CLI &cli, CLIContext &ctx, TokenStreamReader &args) { glm::vec3 pos(args.GetFloat(), args.GetFloat(), args.GetFloat()); - EntityState state = player.GetEntity().GetState(); + EntityState state = ctx.GetPlayer().GetEntity().GetState(); state.pos = ExactLocation(pos).Sanitize(); - player.GetEntity().SetState(state); + ctx.GetPlayer().GetEntity().SetState(state); + + stringstream msg; + msg << ctx.GetPlayer().Name() << " teleported to " << pos; + ctx.Broadcast(msg.str()); } } diff --git a/src/shared/commands.hpp b/src/shared/commands.hpp index 53ab697..1c00241 100644 --- a/src/shared/commands.hpp +++ b/src/shared/commands.hpp @@ -9,7 +9,7 @@ namespace blank { class TeleportCommand : public CLI::Command { - void Execute(CLI &, Player &, TokenStreamReader &) override; + void Execute(CLI &, CLIContext &, TokenStreamReader &) override; }; diff --git a/src/standalone/DirectCLIFeedback.hpp b/src/standalone/DirectCLIFeedback.hpp new file mode 100644 index 0000000..06f2038 --- /dev/null +++ b/src/standalone/DirectCLIFeedback.hpp @@ -0,0 +1,31 @@ +#ifndef BLANK_STANDALONE_DIRECTCLIFEEDBACK_HPP_ +#define BLANK_STANDALONE_DIRECTCLIFEEDBACK_HPP_ + +#include "../shared/CLIContext.hpp" + + +namespace blank { + +class HUD; + +namespace standalone { + +class DirectCLIFeedback +: public CLIContext { + +public: + DirectCLIFeedback(Player &, HUD &); + + void Error(const std::string &) override; + void Message(const std::string &) override; + void Broadcast(const std::string &) override; + +private: + HUD &hud; + +}; + +} +} + +#endif diff --git a/src/standalone/MasterState.hpp b/src/standalone/MasterState.hpp index 610f13a..04234e5 100644 --- a/src/standalone/MasterState.hpp +++ b/src/standalone/MasterState.hpp @@ -4,6 +4,7 @@ #include "../app/State.hpp" #include "../ui/ClientController.hpp" +#include "DirectCLIFeedback.hpp" #include "PreloadState.hpp" #include "UnloadState.hpp" #include "../ai/Spawner.hpp" @@ -90,6 +91,7 @@ private: SkyBox sky; CLI cli; + DirectCLIFeedback cli_ctx; PreloadState preload; UnloadState unload; diff --git a/src/standalone/PreloadState.cpp b/src/standalone/PreloadState.cpp deleted file mode 100644 index 554a458..0000000 --- a/src/standalone/PreloadState.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "PreloadState.hpp" - -#include "../app/Environment.hpp" -#include "../world/ChunkLoader.hpp" -#include "../world/ChunkRenderer.hpp" - - -namespace blank { -namespace standalone { - -PreloadState::PreloadState(Environment &env, ChunkLoader &loader, ChunkRenderer &render) -: ProgressState(env, "Preloading chunks: %d/%d (%d%%)") -, env(env) -, loader(loader) -, render(render) -, total(loader.ToLoad()) -, per_update(64) { - -} - -void PreloadState::Update(int dt) { - loader.LoadN(per_update); - if (loader.ToLoad() <= 0) { - env.state.Pop(); - render.Update(render.MissingChunks()); - } else { - SetProgress(total - loader.ToLoad(), total); - } -} - -} -} diff --git a/src/standalone/UnloadState.cpp b/src/standalone/UnloadState.cpp deleted file mode 100644 index 0b48904..0000000 --- a/src/standalone/UnloadState.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "UnloadState.hpp" - -#include "../app/Environment.hpp" -#include "../io/WorldSave.hpp" -#include "../world/ChunkLoader.hpp" - - -namespace blank { -namespace standalone { - -UnloadState::UnloadState( - Environment &env, - ChunkStore &chunks, - const WorldSave &save) -: ProgressState(env, "Unloading chunks: %d/%d (%d%%)") -, env(env) -, chunks(chunks) -, save(save) -, cur(chunks.begin()) -, end(chunks.end()) -, done(0) -, total(chunks.NumLoaded()) -, per_update(64) { - -} - - -void UnloadState::OnResume() { - cur = chunks.begin(); - end = chunks.end(); - done = 0; - total = chunks.NumLoaded(); -} - - -void UnloadState::Handle(const SDL_Event &) { - // ignore everything -} - -void UnloadState::Update(int dt) { - for (std::size_t i = 0; i < per_update && cur != end; ++i, ++cur, ++done) { - if (cur->ShouldUpdateSave()) { - save.Write(*cur); - } - } - if (cur == end) { - env.state.Pop(); - } else { - SetProgress(done, total); - } -} - -} -} diff --git a/src/standalone/MasterState.cpp b/src/standalone/standalone.cpp similarity index 75% rename from src/standalone/MasterState.cpp rename to src/standalone/standalone.cpp index 6d45738..ad6450d 100644 --- a/src/standalone/MasterState.cpp +++ b/src/standalone/standalone.cpp @@ -1,10 +1,15 @@ +#include "DirectCLIFeedback.hpp" #include "MasterState.hpp" +#include "PreloadState.hpp" +#include "UnloadState.hpp" #include "../app/Config.hpp" #include "../app/Environment.hpp" #include "../app/init.hpp" #include "../geometry/distance.hpp" #include "../io/WorldSave.hpp" +#include "../world/ChunkLoader.hpp" +#include "../world/ChunkRenderer.hpp" #include @@ -12,6 +17,25 @@ namespace blank { namespace standalone { +DirectCLIFeedback::DirectCLIFeedback(Player &p, HUD &h) +: CLIContext(p) +, hud(h) { + +} + +void DirectCLIFeedback::Error(const std::string &msg) { + hud.PostMessage(msg); +} + +void DirectCLIFeedback::Message(const std::string &msg) { + hud.PostMessage(msg); +} + +void DirectCLIFeedback::Broadcast(const std::string &msg) { + hud.PostMessage(msg); +} + + MasterState::MasterState( Environment &env, Config &config, @@ -38,6 +62,7 @@ MasterState::MasterState( , spawner(world, res.models, env.rng) , sky(env.loader.LoadCubeMap("skybox")) , cli(world) +, cli_ctx(player, hud) , preload(env, chunk_loader, chunk_renderer) , unload(env, world.Chunks(), save) , chat(env, *this, *this) { @@ -224,11 +249,75 @@ void MasterState::OnLineSubmit(const std::string &line) { return; } if (line[0] == '/' && line.size() > 1 && line[1] != '/') { - cli.Execute(player, line.substr(1)); + cli.Execute(cli_ctx, line.substr(1)); } else { hud.PostMessage(line); } } + +PreloadState::PreloadState(Environment &env, ChunkLoader &loader, ChunkRenderer &render) +: ProgressState(env, "Preloading chunks: %d/%d (%d%%)") +, env(env) +, loader(loader) +, render(render) +, total(loader.ToLoad()) +, per_update(64) { + +} + +void PreloadState::Update(int dt) { + loader.LoadN(per_update); + if (loader.ToLoad() <= 0) { + env.state.Pop(); + render.Update(render.MissingChunks()); + } else { + SetProgress(total - loader.ToLoad(), total); + } +} + + +UnloadState::UnloadState( + Environment &env, + ChunkStore &chunks, + const WorldSave &save) +: ProgressState(env, "Unloading chunks: %d/%d (%d%%)") +, env(env) +, chunks(chunks) +, save(save) +, cur(chunks.begin()) +, end(chunks.end()) +, done(0) +, total(chunks.NumLoaded()) +, per_update(64) { + +} + + +void UnloadState::OnResume() { + cur = chunks.begin(); + end = chunks.end(); + done = 0; + total = chunks.NumLoaded(); +} + + +void UnloadState::Handle(const SDL_Event &) { + // ignore everything +} + +void UnloadState::Update(int dt) { + for (std::size_t i = 0; i < per_update && cur != end; ++i, ++cur, ++done) { + if (cur->ShouldUpdateSave()) { + save.Write(*cur); + } + } + if (cur == end) { + env.state.Pop(); + } else { + SetProgress(done, total); + } +} + } } -- 2.39.2