]> git.localhorst.tv Git - blank.git/blob - src/shared/cli.cpp
impersonate command
[blank.git] / src / shared / cli.cpp
1 #include "CLI.hpp"
2 #include "CLIContext.hpp"
3 #include "commands.hpp"
4
5 #include "../io/TokenStreamReader.hpp"
6 #include "../world/Entity.hpp"
7 #include "../world/Player.hpp"
8 #include "../world/World.hpp"
9
10 #include <iostream>
11 #include <sstream>
12 #include <glm/gtx/io.hpp>
13
14 using namespace std;
15
16
17 namespace blank {
18
19 CLI::CLI(World &world)
20 : world(world)
21 , commands() {
22         AddCommand("as", new ImpersonateCommand);
23         AddCommand("tp", new TeleportCommand);
24 }
25
26 CLI::~CLI() {
27         for (auto &entry : commands) {
28                 delete entry.second;
29         }
30 }
31
32 void CLI::AddCommand(const string &name, Command *cmd) {
33         commands[name] = cmd;
34 }
35
36 void CLI::Execute(CLIContext &ctx, const string &line) {
37         stringstream s(line);
38         TokenStreamReader args(s);
39         if (!args.HasMore()) {
40                 // ignore empty command line
41                 return;
42         }
43         if (args.Peek().type != Token::IDENTIFIER) {
44                 ctx.Error("I don't understand");
45                 return;
46         }
47         string name;
48         args.ReadIdentifier(name);
49         auto entry = commands.find(name);
50         if (entry == commands.end()) {
51                 ctx.Error(name + ": command not found");
52                 return;
53         }
54         try {
55                 entry->second->Execute(*this, ctx, args);
56         } catch (exception &e) {
57                 ctx.Error(name + ": " + e.what());
58         } catch (...) {
59                 ctx.Error(name + ": unknown execution error");
60         }
61 }
62
63 CLI::Command::~Command() {
64
65 }
66
67
68 CLIContext::CLIContext(Player *p, Entity *e)
69 : original_player(p)
70 , effective_player(p)
71 , original_entity(e)
72 , effective_entity(e) {
73         if (!e && p) {
74                 original_entity = effective_entity = &p->GetEntity();
75         }
76 }
77
78 std::string CLIContext::Name() const {
79         if (HasPlayer()) return GetPlayer().Name();
80         if (HasEntity()) return GetEntity().Name();
81         return "anonymous";
82 }
83
84
85 void ImpersonateCommand::Execute(CLI &cli, CLIContext &ctx, TokenStreamReader &args) {
86         if (!args.HasMore()) {
87                 // no argument => reset
88                 ctx.Reset();
89                 ctx.Broadcast(ctx.Name() + " returned to their own self");
90                 return;
91         }
92         // TODO: broadcast who (real player name) impersonates who
93         string old_name = ctx.Name();
94         string name(args.GetString());
95
96         Player *p = cli.GetWorld().FindPlayer(name);
97         if (p) {
98                 ctx.SetPlayer(*p);
99                 ctx.SetEntity(p->GetEntity());
100                 ctx.Broadcast(old_name + " now impersonating " + p->Name());
101                 return;
102         }
103
104         // not a player, try an entity
105         Entity *e = cli.GetWorld().FindEntity(name);
106         if (e) {
107                 ctx.SetEntity(*e);
108                 ctx.Broadcast(old_name + " now impersonating " + e->Name());
109                 return;
110         }
111
112         ctx.Error("no player or entity with name " + name);
113 }
114
115
116 void TeleportCommand::Execute(CLI &, CLIContext &ctx, TokenStreamReader &args) {
117         if (!ctx.HasEntity()) {
118                 ctx.Error("teleport needs entity to operate on");
119                 return;
120         }
121
122         glm::vec3 pos(args.GetFloat(), args.GetFloat(), args.GetFloat());
123         EntityState state = ctx.GetEntity().GetState();
124         state.pos = ExactLocation(pos).Sanitize();
125         ctx.GetEntity().SetState(state);
126
127         stringstream msg;
128         msg << ctx.GetEntity().Name() << " teleported to " << pos;
129         ctx.Broadcast(msg.str());
130 }
131
132 }