VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
CommandManager.cpp
Go to the documentation of this file.
3
8#include <convar.h>
9#include <memory>
10#include <unordered_map>
11#include <utility>
12
13namespace VoltMod
14{
15
26
28
29CommandBuilder CommandManager::Add(std::string_view name)
30{
31 return CommandBuilder(
32 [this](CommandDefinition def) {
33 const CommandDefinition* added = _router->Add(std::move(def));
34 if (added && added->Access != CommandAccess::Players)
35 {
36 InstallConsoleCommand(*added);
37 }
38 },
39 name);
40}
41
43{
44 _consoleCommands.clear();
45 _router->Clear();
46}
47
48void CommandManager::InstallConsoleCommand(const CommandDefinition& def)
49{
50 const std::string name = Strings::ToLower(def.Name);
51 const std::string help = def.Description.empty() ? _router->Usage(def, -1, Origin::Console) : def.Description;
52
53 ServerCommand::Handler run = [this, name](const CCommand& args, int slot) {
54 // Shutdown can unregister the command before the engine drops it.
55 const CommandDefinition* current = _router->Find(name);
56 if (!current)
57 {
58 return;
59 }
60
61 std::vector<std::string> tokens;
62 tokens.reserve(static_cast<size_t>(args.ArgC()));
63 for (int i = 1; i < args.ArgC(); ++i)
64 {
65 tokens.emplace_back(args.Arg(i));
66 }
67
68 if (slot >= 0)
69 {
70 if (Player* player = _players.Get(slot))
71 {
72 _router->Dispatch(*current, player, tokens, Origin::Console, *_binder,
73 [this, slot](const std::string& line) { ReplyToPlayer(slot, line); });
74 }
75 return;
76 }
77
78 _router->Dispatch(*current, nullptr, tokens, Origin::Console, *_binder,
79 [](const std::string& line) { Log::Info("{}", line); });
80 };
81
82 const bool playersCanRun = def.Access == CommandAccess::Anywhere;
83 _consoleCommands.try_emplace(name, name, help, std::move(run), playersCanRun);
84}
85
86void CommandManager::ReplyToPlayer(int slot, const std::string& line)
87{
88 if (_policy.Reply)
89 {
90 _policy.Reply(slot, line);
91 }
92 else
93 {
94 _messages.Send(slot, line);
95 }
96}
97
99{
100 if (!caller)
101 {
102 return false;
103 }
104
106 if (!body)
107 {
108 return false;
109 }
110
111 std::vector<std::string> parts = CommandSyntax::Tokenize(*body);
112 if (parts.empty())
113 {
114 return false;
115 }
116
117 const CommandDefinition* def = _router->Find(parts.front());
118 if (!def || def->Access == CommandAccess::ServerOnly)
119 {
120 return false;
121 }
122
123 const std::span<const std::string> tokens{parts.begin() + 1, parts.end()};
124 const int slot = caller->Slot();
125 _router->Dispatch(*def, caller, tokens, Origin::Chat, *_binder,
126 [this, slot](const std::string& line) { ReplyToPlayer(slot, line); });
127
128 return true;
129}
130
131bool CommandManager::IsForeign(std::string_view message) const
132{
134 if (!body)
135 {
136 return false;
137 }
138
139 std::vector<std::string> parts = CommandSyntax::Tokenize(*body);
140 return !parts.empty() && _router->IsForeign(parts.front());
141}
142
144{
145 return _router->Count();
146}
147
148} // namespace VoltMod
How a chat line is spelled: the prefix, and splitting one into tokens.
Fluent command registration, returned by CommandManager::Add.
CommandManager(Policy &policy, Translations &translations, PlayerManager &players, EntitySystem &entities, Messages &messages, IPluginContext &host)
bool HandleChatMessage(Player *caller, std::string_view message)
CommandBuilder Add(std::string_view name)
bool IsForeign(std::string_view message) const
The registered commands, their usage lines, and the dispatch that runs one.
runtime.Entities: finds and creates entities. Everything it returns is valid for this frame only; see...
Send chat, center print, center HTML, and alert messages.
Definition Messages.hpp:30
void Send(int slot, std::string_view message, MessageKind kind=MessageKind::Chat)
Definition Messages.cpp:104
The roster: every connected player, and the signals for the connection lifecycle.
Player * Get(int slot)
One connected player, owned by PlayerManager for the length of the connection.
Definition Player.hpp:23
The one permission and targeting gate, plus the plugin's reply callback.
Definition Policy.hpp:41
std::function< void(int slot, std::string_view message)> Reply
Definition Policy.hpp:63
std::function< void(const CCommand &args, int slot)> Handler
static std::string ToLower(std::string_view str)
Definition Strings.cpp:100
Localization system. Loads one JSON file per language; nested objects flatten into dotted keys (categ...
std::optional< std::string_view > StripPrefix(std::string_view message)
std::vector< std::string > Tokenize(std::string_view text)
void Info(std::format_string< Args... > fmt, Args &&... args)
Definition Log.hpp:79
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
One command as the builder assembled it.