VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
CommandRouter.hpp
Go to the documentation of this file.
1#pragma once
2
4
9#include <cstdint>
10#include <functional>
11#include <span>
12#include <string>
13#include <string_view>
14#include <unordered_map>
15#include <vector>
16
17namespace VoltMod
18{
19
20/** Which surface an invocation arrived on. The usage line's prefix and whether a permission is
21 * checked at all both follow from it. */
22enum class Origin : uint8_t
23{
24 Chat,
25 Console,
26};
27
28/**
29 * @brief The registered commands, their usage lines, and the dispatch that runs one.
30 *
31 * Engine-free by construction: it holds a @ref Policy and a @ref Translations, both of which are
32 * plain logic, and reaches the server only through the @ref ArgBinder handed to @ref Dispatch.
33 * Chat syntax lives in @ref CommandSyntax and argument binding in @ref BindArgs; neither needs the
34 * registry, so neither is here.
35 */
37{
38public:
39 CommandRouter(const Policy& policy, Translations& translations) : _policy(policy), _translations(translations) {}
40
41 /** Attach to @p host, which owns the process-wide command names. Null leaves registration
42 * as it is without a host: names are the plugin's own business. */
43 void Attach(IPluginContext* host) { _host = host; }
44
45 /** Register @p def under its lowercased name plus its aliases. With a host attached, each of
46 * those names is registered there first, so two plugins cannot answer the same command.
47 * @return the stored definition, or null when the name or the registration was refused
48 * (already logged). Valid until @ref Clear. */
50
51 /** Drop every registration. The router is emptied as a whole or not at all: a command
52 * lives exactly as long as the manager that owns it. */
53 void Clear();
54
55 /** Look @p name up as a command name, then as an alias. */
56 const CommandDefinition* Find(std::string_view name) const;
57
58 /** True when @p name is not this router's but the host has it registered for someone else. */
59 bool IsForeign(std::string_view name) const;
60
61 size_t Count() const { return _commands.size(); }
62
63 /** The usage line for @p def, in @p slot's language. */
64 std::string Usage(const CommandDefinition& def, int slot, Origin origin) const;
65
66 /**
67 * Authorize, bind and run @p def, sending every line to @p say.
68 *
69 * @p caller is null for @ref Origin::Console, which is the server itself: no permission is
70 * checked and caller-relative selectors match nobody.
71 */
72 void Dispatch(const CommandDefinition& def, Player* caller, std::span<const std::string> tokens, Origin origin,
73 ArgBinder& binder, const std::function<void(const std::string&)>& say) const;
74
75private:
76 /** How many leading arguments @p def requires. */
77 static size_t RequiredArgs(const CommandDefinition& def);
78 /** Whether @p def's last argument swallows the remainder of the line. */
79 static bool HasRest(const CommandDefinition& def);
80 /** The `{prefix}`, `{command}`, `{args}` and assembled `{usage}` tokens for @p def. */
81 Tokens UsageTokens(const CommandDefinition& def, int slot, Origin origin) const;
82
83 const Policy& _policy;
84 Translations& _translations;
85 /** The host that arbitrates command names, or null when no host is attached. It outlives
86 * the plugin. */
87 IPluginContext* _host = nullptr;
88
89 std::unordered_map<std::string, CommandDefinition> _commands;
90 /** Lowercased alias -> the lowercased command name that owns it. */
91 std::unordered_map<std::string, std::string> _aliases;
92};
93
94} // namespace VoltMod
The one thing command dispatch needs a running server for.
The registered commands, their usage lines, and the dispatch that runs one.
CommandRouter(const Policy &policy, Translations &translations)
void Dispatch(const CommandDefinition &def, Player *caller, std::span< const std::string > tokens, Origin origin, ArgBinder &binder, const std::function< void(const std::string &)> &say) const
const CommandDefinition * Find(std::string_view name) const
const CommandDefinition * Add(CommandDefinition def)
std::string Usage(const CommandDefinition &def, int slot, Origin origin) const
bool IsForeign(std::string_view name) const
void Attach(IPluginContext *host)
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
Localization system. Loads one JSON file per language; nested objects flatten into dotted keys (categ...
@ Chat
Chat box line (color escapes honored).
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
std::map< std::string, std::string > Tokens
Definition Strings.hpp:14
One command as the builder assembled it.