]> git.localhorst.tv Git - blank.git/commitdiff
added simple command line
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 26 Oct 2015 14:56:35 +0000 (15:56 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 26 Oct 2015 15:15:05 +0000 (16:15 +0100)
12 files changed:
doc/todo
src/app/init.cpp
src/client/client.cpp
src/server/Server.hpp
src/server/net.cpp
src/shared/CLI.hpp [new file with mode: 0644]
src/shared/ChatState.hpp
src/shared/cli.cpp [new file with mode: 0644]
src/shared/commands.hpp [new file with mode: 0644]
src/shared/states.cpp
src/standalone/MasterState.cpp
src/standalone/MasterState.hpp

index 704487ff7209536bc2d1dcae5dd854063a840318..c6a3808160d9b05ce0e95cff091760c58716bc04 100644 (file)
--- a/doc/todo
+++ b/doc/todo
@@ -19,7 +19,8 @@ font rendering
 
 command line
 
-       useful for development and later on world administration
+       more commands pls
+       and show me their output
 
 persistence
 
@@ -30,10 +31,11 @@ persistence
 
 networking
 
-       write tests
-       do some manual testing
-       some more testing
-       a little optimization
+       definitely needs throttling for the internets
+
+       players stats (who's connected, their ping, and game-relevant
+       things) should be sent to clients
+
 
 launcher ui
 
index f4bcd01f45a230c4a1d928f967f60c0ff494ba19..a0ea7b51ba5d614a3df13814c4eee90468d6fe1d 100644 (file)
@@ -91,6 +91,8 @@ InitVideo::InitVideo() {
        if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
                throw SDLError("SDL_InitSubSystem(SDL_INIT_VIDEO)");
        }
+       // SDL seems to start out in text input state
+       SDL_StopTextInput();
 }
 
 InitVideo::~InitVideo() {
index ae1bf7378f59f6ed12494a08de8bd692e3b49aa6..26e0e0df748c64cd70f0807ae00e90b4bb7d1dbf 100644 (file)
@@ -105,6 +105,11 @@ void InteractiveState::Handle(const SDL_Event &event) {
                case SDL_KEYDOWN:
                        // TODO: move to interface
                        if (event.key.keysym.sym == SDLK_RETURN) {
+                               chat.Clear();
+                               master.GetEnv().state.Push(&chat);
+                               hud.KeepMessages(true);
+                       } else if (event.key.keysym.sym == SDLK_SLASH) {
+                               chat.Preset("/");
                                master.GetEnv().state.Push(&chat);
                                hud.KeepMessages(true);
                        } else {
index 683d36254c76523a6ba5afddd84c2607ae204292..3bffafc29d2ada80307be32b5cab2269c49a6a65 100644 (file)
@@ -2,6 +2,7 @@
 #define BLANK_SERVER_SERVER_HPP
 
 #include "../app/Config.hpp"
+#include "../shared/CLI.hpp"
 #include "../world/World.hpp"
 #include "../world/WorldManipulator.hpp"
 
@@ -46,6 +47,9 @@ 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 &);
+
        /// send message to all connected clients
        void DistributeMessage(std::uint8_t type, std::uint32_t ref, const std::string &msg);
 
@@ -66,6 +70,8 @@ private:
        const WorldSave &save;
        const Model *player_model;
 
+       CLI cli;
+
 };
 
 }
index 38224ec9a57e879e2a84357a77456b30253f3f1c..f7c874f665fb1fbc4f38e190e045b5ae4f96a255 100644 (file)
@@ -593,7 +593,7 @@ void ClientConnection::On(const Packet::Message &pack) {
        pack.ReadMessage(msg);
 
        if (type == 1 && HasPlayer()) {
-               server.DistributeMessage(1, PlayerEntity().ID(), msg);
+               server.DispatchMessage(input->GetPlayer(), msg);
        }
 }
 
@@ -609,7 +609,8 @@ Server::Server(
 , world(world)
 , spawn_index(world.Chunks().MakeIndex(wc.spawn, 3))
 , save(save)
-, player_model(nullptr) {
+, player_model(nullptr)
+, cli(world) {
        serv_sock = SDLNet_UDP_Open(conf.port);
        if (!serv_sock) {
                throw NetError("SDLNet_UDP_Open");
@@ -724,6 +725,17 @@ void Server::SetBlock(Chunk &chunk, int index, const Block &block) {
        }
 }
 
+void Server::DispatchMessage(Player &player, const string &msg) {
+       if (msg.empty()) {
+               return;
+       }
+       if (msg[0] == '/' && msg.size() > 1 && msg[1] != '/') {
+               cli.Execute(player, msg.substr(1));
+       } else {
+               DistributeMessage(1, player.GetEntity().ID(), msg);
+       }
+}
+
 void Server::DistributeMessage(uint8_t type, uint32_t ref, const string &msg) {
        auto pack = Packet::Make<Packet::Message>(serv_pack);
        pack.WriteType(type);
diff --git a/src/shared/CLI.hpp b/src/shared/CLI.hpp
new file mode 100644 (file)
index 0000000..b601e57
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef BLANK_SHARED_CLI_HPP_
+#define BLANK_SHARED_CLI_HPP_
+
+#include <map>
+#include <string>
+
+
+namespace blank {
+
+class Player;
+class TokenStreamReader;
+class World;
+
+class CLI {
+
+public:
+       struct Command {
+               virtual ~Command();
+               virtual void Execute(CLI &, Player &, TokenStreamReader &) = 0;
+       };
+
+public:
+       explicit CLI(World &);
+       ~CLI();
+
+       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);
+
+private:
+       World &world;
+       std::map<std::string, Command *> commands;
+
+};
+
+}
+
+#endif
index 7b8a993c6fa0fa782cc6a80387a9b5f7872b75aa..67523d7f822c95f004a716353674cc1e935e9adb 100644 (file)
@@ -23,6 +23,9 @@ public:
 public:
        ChatState(Environment &env, State &parent, Responder &);
 
+       void Preset(const std::string &);
+       void Clear();
+
        void OnResume() override;
        void OnPause() override;
 
@@ -39,6 +42,7 @@ private:
        State &parent;
        Responder &responder;
 
+       std::string preset;
        TextInput input;
 
 };
diff --git a/src/shared/cli.cpp b/src/shared/cli.cpp
new file mode 100644 (file)
index 0000000..aa6629f
--- /dev/null
@@ -0,0 +1,84 @@
+#include "CLI.hpp"
+#include "commands.hpp"
+
+#include "../io/TokenStreamReader.hpp"
+#include "../world/Entity.hpp"
+#include "../world/Player.hpp"
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+
+namespace blank {
+
+CLI::CLI(World &world)
+: world(world)
+, commands() {
+       AddCommand("tp", new TeleportCommand);
+}
+
+CLI::~CLI() {
+       for (auto &entry : commands) {
+               delete entry.second;
+       }
+}
+
+void CLI::AddCommand(const string &name, Command *cmd) {
+       commands[name] = cmd;
+}
+
+void CLI::Execute(Player &player, const string &line) {
+       stringstream s(line);
+       TokenStreamReader args(s);
+       if (!args.HasMore()) {
+               // ignore empty command line
+               return;
+       }
+       if (args.Peek().type != Token::IDENTIFIER) {
+               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");
+               return;
+       }
+       try {
+               entry->second->Execute(*this, player, args);
+       } catch (exception &e) {
+               Error(name + ": " + e.what());
+       } catch (...) {
+               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) {
+       glm::vec3 pos(args.GetFloat(), args.GetFloat(), args.GetFloat());
+       glm::ivec3 chunk(pos);
+       chunk /= Chunk::Extent();
+       pos -= chunk;
+       EntityState state = player.GetEntity().GetState();
+       state.chunk_pos = chunk;
+       state.block_pos = pos;
+       player.GetEntity().SetState(state);
+}
+
+}
diff --git a/src/shared/commands.hpp b/src/shared/commands.hpp
new file mode 100644 (file)
index 0000000..53ab697
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef BLANK_SHARED_COMMANDS_HPP_
+#define BLANK_SHARED_COMMANDS_HPP_
+
+#include "CLI.hpp"
+
+
+namespace blank {
+
+class TeleportCommand
+: public CLI::Command {
+
+       void Execute(CLI &, Player &, TokenStreamReader &) override;
+
+};
+
+}
+
+#endif
index b9a48b09a94ab53840070e13b173628bd223d214..f98382e39d30b587bcce82a3722dbda9350f3394 100644 (file)
@@ -14,6 +14,7 @@ ChatState::ChatState(Environment &env, State &parent, Responder &responder)
 : env(env)
 , parent(parent)
 , responder(responder)
+, preset()
 , input(env.assets.small_ui_font) {
        input.Position(glm::vec3(25.0f, -25.0f, -1.0f), Gravity::SOUTH_WEST, Gravity::SOUTH_WEST);
        input.Width(env.viewport.Width() - 50.0f);
@@ -21,9 +22,20 @@ ChatState::ChatState(Environment &env, State &parent, Responder &responder)
        input.Background(glm::vec4(0.5f));
 }
 
+void ChatState::Preset(const std::string &text) {
+       preset = text;
+}
+
+void ChatState::Clear() {
+       preset.clear();
+}
+
 void ChatState::OnResume() {
        OnResize(env.viewport);
        input.Clear();
+       if (!preset.empty()) {
+               input.Insert(preset.c_str());
+       }
        input.Focus(env.viewport);
 }
 
index 81017f78603cea89bca967d440089e7c26876e05..5ade4f1ed89a3f6009d19e54adb407c2d2c77a1e 100644 (file)
@@ -36,6 +36,7 @@ MasterState::MasterState(
 , chunk_renderer(player.GetChunks())
 , spawner(world, res.models, env.rng)
 , sky(env.loader.LoadCubeMap("skybox"))
+, cli(world)
 , preload(env, chunk_loader, chunk_renderer)
 , unload(env, world.Chunks(), save)
 , chat(env, *this, *this) {
@@ -99,6 +100,11 @@ void MasterState::Handle(const SDL_Event &event) {
                case SDL_KEYDOWN:
                        // TODO: move to interface
                        if (event.key.keysym.sym == SDLK_RETURN) {
+                               chat.Clear();
+                               env.state.Push(&chat);
+                               hud.KeepMessages(true);
+                       } else if (event.key.keysym.sym == SDLK_SLASH) {
+                               chat.Preset("/");
                                env.state.Push(&chat);
                                hud.KeepMessages(true);
                        } else {
@@ -206,7 +212,12 @@ void MasterState::Exit() {
 }
 
 void MasterState::OnLineSubmit(const std::string &line) {
-       if (!line.empty()) {
+       if (line.empty()) {
+               return;
+       }
+       if (line[0] == '/' && line.size() > 1 && line[1] != '/') {
+               cli.Execute(player, line.substr(1));
+       } else {
                hud.PostMessage(line);
        }
 }
index 26fcf26742a62cb4e05ca49208b5a9df5bc9ec63..9cb095ac1eb8d7d048bc12481e25227ca3feb287 100644 (file)
@@ -10,6 +10,7 @@
 #include "../audio/SoundBank.hpp"
 #include "../graphics/SkyBox.hpp"
 #include "../shared/ChatState.hpp"
+#include "../shared/CLI.hpp"
 #include "../shared/WorldResources.hpp"
 #include "../ui/DirectInput.hpp"
 #include "../ui/HUD.hpp"
@@ -87,6 +88,8 @@ private:
 
        SkyBox sky;
 
+       CLI cli;
+
        PreloadState preload;
        UnloadState unload;
        ChatState chat;