]> git.localhorst.tv Git - blank.git/commitdiff
impersonate command
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 17 Nov 2016 08:41:32 +0000 (09:41 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 17 Nov 2016 08:41:32 +0000 (09:41 +0100)
src/io/TokenStreamReader.hpp
src/io/token.cpp
src/shared/CLI.hpp
src/shared/CLIContext.hpp
src/shared/cli.cpp
src/shared/commands.hpp
src/world/World.hpp
src/world/world.cpp
tst/io/TokenTest.cpp

index f1b73491447c5c662aa37b219b2e42b0d5c283db..ea3a6ccbca1af7d5463d283e8b65329b5da6e889 100644 (file)
@@ -28,6 +28,9 @@ public:
        void ReadNumber(int &);
        void ReadNumber(unsigned long &);
        void ReadString(std::string &);
+       // like ReadString, but does not require the value to be
+       // written as a string literal in source
+       void ReadRelaxedString(std::string &);
 
        void ReadVec(glm::vec2 &);
        void ReadVec(glm::vec3 &);
@@ -42,6 +45,7 @@ public:
        // the Get* functions advance to the next token
        // the As* functions try to cast the current token
        // if the value could not be converted, a std::runtime_error is thrown
+       // conversion to string is always possible
 
        bool GetBool();
        bool AsBool() const;
@@ -51,6 +55,8 @@ public:
        int AsInt() const;
        unsigned long GetULong();
        unsigned long AsULong() const;
+       const std::string &GetString();
+       const std::string &AsString() const;
 
 private:
        void SkipComments();
index a2ad44c918f0a834a409aa94fc36f4c3877eaabe..99b25b6690a168c727c63e623fcff426c62a59ca 100644 (file)
@@ -336,6 +336,10 @@ void TokenStreamReader::ReadString(string &out) {
        out = GetValue();
 }
 
+void TokenStreamReader::ReadRelaxedString(string &out) {
+       out = GetString();
+}
+
 
 void TokenStreamReader::ReadVec(glm::vec2 &v) {
        Skip(Token::BRACKET_OPEN);
@@ -467,4 +471,13 @@ unsigned long TokenStreamReader::AsULong() const {
        return stoul(GetValue());
 }
 
+const string &TokenStreamReader::GetString() {
+       Next();
+       return AsString();
+}
+
+const string &TokenStreamReader::AsString() const {
+       return GetValue();
+}
+
 }
index ab1e3eeaad60deaa701dd34850e674a546aa5c5c..b0731e8a4ce69d0ffd5b40abd643fe4c50fbd29c 100644 (file)
@@ -27,6 +27,8 @@ public:
 
        void Execute(CLIContext &, const std::string &);
 
+       World &GetWorld() noexcept { return world; }
+
 private:
        World &world;
        std::map<std::string, Command *> commands;
index e07571fc331eafbeff45100f712ab6204a648625..1556b8e164628130692cbd1e9d704052cd53311d 100644 (file)
@@ -19,25 +19,30 @@ public:
        /// values when reset.
        explicit CLIContext(Player *p = nullptr, Entity *e = nullptr);
 
+       /// get a best name for this context
+       std::string Name() const;
+
        /// check if this context associates a player
-       bool HasPlayer() { return effective_player; }
+       bool HasPlayer() const noexcept { return effective_player; }
        /// get the player responsible for all this
        /// only valid if HasPlayer() returns true
-       Player &GetPlayer() { return *effective_player; }
+       Player &GetPlayer() noexcept { return *effective_player; }
+       const Player &GetPlayer() const noexcept { return *effective_player; }
        /// change the effective player of this context
        /// note that this will *not* change the effective entity
-       void SetPlayer(Player &p) { effective_player = &p; }
+       void SetPlayer(Player &p) noexcept { effective_player = &p; }
 
        /// check if this context associates an entity
-       bool HasEntity() { return effective_entity; }
+       bool HasEntity() const noexcept { return effective_entity; }
        /// get the entity on which operations should be performed
        /// only valid if HasPlayer() returns true
-       Entity &GetEntity() { return *effective_entity; }
+       Entity &GetEntity() noexcept { return *effective_entity; }
+       const Entity &GetEntity() const noexcept { return *effective_entity; }
        /// change the effective player of this context
-       void SetEntity(Entity &e) { effective_entity = &e; }
+       void SetEntity(Entity &e) noexcept { effective_entity = &e; }
 
        /// reset effective player and entity to their original values
-       void Reset() {
+       void Reset() noexcept {
                effective_player = original_player;
                effective_player = original_player;
        }
index bb4aa6de706e3259f25f374a9fdfe15d57808870..c144d8677830281318f09585705168f0d9d3ca90 100644 (file)
@@ -5,6 +5,7 @@
 #include "../io/TokenStreamReader.hpp"
 #include "../world/Entity.hpp"
 #include "../world/Player.hpp"
+#include "../world/World.hpp"
 
 #include <iostream>
 #include <sstream>
@@ -18,6 +19,7 @@ namespace blank {
 CLI::CLI(World &world)
 : world(world)
 , commands() {
+       AddCommand("as", new ImpersonateCommand);
        AddCommand("tp", new TeleportCommand);
 }
 
@@ -73,6 +75,43 @@ CLIContext::CLIContext(Player *p, Entity *e)
        }
 }
 
+std::string CLIContext::Name() const {
+       if (HasPlayer()) return GetPlayer().Name();
+       if (HasEntity()) return GetEntity().Name();
+       return "anonymous";
+}
+
+
+void ImpersonateCommand::Execute(CLI &cli, CLIContext &ctx, TokenStreamReader &args) {
+       if (!args.HasMore()) {
+               // no argument => reset
+               ctx.Reset();
+               ctx.Broadcast(ctx.Name() + " returned to their own self");
+               return;
+       }
+       // TODO: broadcast who (real player name) impersonates who
+       string old_name = ctx.Name();
+       string name(args.GetString());
+
+       Player *p = cli.GetWorld().FindPlayer(name);
+       if (p) {
+               ctx.SetPlayer(*p);
+               ctx.SetEntity(p->GetEntity());
+               ctx.Broadcast(old_name + " now impersonating " + p->Name());
+               return;
+       }
+
+       // not a player, try an entity
+       Entity *e = cli.GetWorld().FindEntity(name);
+       if (e) {
+               ctx.SetEntity(*e);
+               ctx.Broadcast(old_name + " now impersonating " + e->Name());
+               return;
+       }
+
+       ctx.Error("no player or entity with name " + name);
+}
+
 
 void TeleportCommand::Execute(CLI &, CLIContext &ctx, TokenStreamReader &args) {
        if (!ctx.HasEntity()) {
index 1c00241850350ac80ce5be9b5390e3112483bb65..c151da3c8ecec2885f4ae9f6c4db869d3c75517e 100644 (file)
@@ -6,6 +6,13 @@
 
 namespace blank {
 
+class ImpersonateCommand
+: public CLI::Command {
+
+       void Execute(CLI &, CLIContext &, TokenStreamReader &) override;
+
+};
+
 class TeleportCommand
 : public CLI::Command {
 
index 7785ed6a68c3847a866201e6c8d5c3abfb6d8edd..771bc0c8c4fd072d8dd59c82c642828c66a30441 100644 (file)
@@ -96,6 +96,14 @@ public:
        /// returs an existing entity if ID is already taken
        Entity &ForceAddEntity(std::uint32_t id);
 
+       /// get the player with given name
+       /// returns nullptr if no player bears this name
+       Player *FindPlayer(const std::string &name);
+       /// get an entity with given name
+       /// returns nullptr if name doesn't refer to any entity
+       /// note that unlike players, entity names are not unique
+       Entity *FindEntity(const std::string &name);
+
        std::list<Player> &Players() noexcept { return players; }
        const std::list<Player> &Players() const noexcept { return players; }
        std::list<Entity> &Entities() noexcept { return entities; }
index 2292d15418f6dd30420bb329b9f09fb2fcb2c8f4..033967ad970ffecd32c098f226c1942b8b97dabd 100644 (file)
@@ -764,6 +764,26 @@ Entity &World::ForceAddEntity(std::uint32_t id) {
 }
 
 
+Player *World::FindPlayer(const std::string &name) {
+       for (Player &p : players) {
+               if (p.Name() == name) {
+                       return &p;
+               }
+       }
+       return nullptr;
+}
+
+Entity *World::FindEntity(const std::string &name) {
+       // TODO: this may get inefficient
+       for (Entity &e : entities) {
+               if (e.Name() == name) {
+                       return &e;
+               }
+       }
+       return nullptr;
+}
+
+
 namespace {
 
 struct Candidate {
index e794a7b6386daad2f66e5a331fb786d874fe1af6..16b4f4d8aeddfdc37dabb8300755e4eeca5e5ade 100644 (file)
@@ -202,6 +202,7 @@ void TokenTest::testReader() {
                "0 1 -1 2.5\n"
                // strings
                "\"hello\" \"\" \"\\r\\n\\t\\\"\"\n"
+               "\"world\" foo 12\n"
                // vectors
                "[1,0] [ 0.707, 0.707 ] // vec2\n"
                "[.577,.577 ,0.577] [ 1,-2,3] // vec3\n"
@@ -308,6 +309,21 @@ void TokenTest::testReader() {
                "reading string \"\\r\\n\\t\\\"\"",
                "\r\n\t\"", value_string, in);
 
+       in.ReadRelaxedString(value_string);
+       assert_read<string>(
+               "reading relaxed string \"world\"",
+               "world", value_string, in);
+
+       in.ReadRelaxedString(value_string);
+       assert_read<string>(
+               "reading relaxed string foo",
+               "foo", value_string, in);
+
+       in.ReadRelaxedString(value_string);
+       assert_read<string>(
+               "reading relaxed string 12",
+               "12", value_string, in);
+
        // vectors
 
        glm::vec2 value_vec2;