VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
ConVar.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <concepts>
9#include <cstdint>
10#include <string>
11#include <string_view>
12#include <utility>
13
14namespace VoltMod
15{
16
17/** Convar change whose string views remain valid only during the handler. */
19{
20 std::string_view Name;
21 std::string_view OldValue;
22 std::string_view NewValue;
23};
24
25/** The value types a @ref ConVar handle supports. Naming one the engine does not store this way
26 * fails at the `Find` call rather than at link time. */
27template <class T>
28concept ConVarValue =
29 std::same_as<T, bool> || std::same_as<T, int> || std::same_as<T, float> || std::same_as<T, std::string>;
30
31/** A @ref ConVarValue whose storage can be written behind the engine's back: everything but a
32 * string, which has no fixed-width slot to poke. @ref ConVar::RawScope and the raw writes it
33 * depends on are limited to these. */
34template <class T>
35concept RawConVarValue = ConVarValue<T> && !std::same_as<T, std::string>;
36
37template <class T>
38class ConVar;
39
40/** Temporary raw convar value restored on destruction. The handle must outlive the scope. */
41template <class T>
43{
44public:
45 /** Set now and restore the current value on destruction. */
46 ConVarRawScope(ConVar<T>& cvar, const T& value)
47 requires RawConVarValue<T>;
49
53 : _cvar(std::exchange(other._cvar, nullptr)), _previous(std::move(other._previous))
54 {}
56
57private:
58 ConVar<T>* _cvar = nullptr;
59 T _previous{};
60};
61
62class ConVars;
63
64/**
65 * Typed convar handle resolved once by name. Supported types are `bool`, `int`, `float`, and
66 * `std::string`.
67 * Handles remain valid across map changes. Unresolved handles read as `T{}` and
68 * reject writes.
69 */
70template <class T>
71class ConVar
72{
73public:
74 ConVar() = default;
75
76 /** Current server value, or `T{}` when unresolved. */
77 T Get() const;
78
79 /** Set through the server console. Success means queued; Error::NotReady means unavailable. */
80 Status Set(const T& value);
81
82 /**
83 * Override one client's replicated view without changing the server value. Connect and map
84 * snapshots replace the override, so resend it after spawn when persistence is required.
85 */
86 void SetFor(int slot, const T& value) const;
87
88 /** Set without callbacks or networking until the returned scope is destroyed. */
90 requires RawConVarValue<T>
91 {
92 return ConVarRawScope<T>(*this, value);
93 }
94
95 std::string_view Name() const { return _name; }
96
97 explicit operator bool() const noexcept { return _storage != nullptr; }
98
99private:
100 friend class ConVarRawScope<T>;
101 friend class ConVars;
102
103 void SetRaw(const T& value)
104 requires RawConVarValue<T>;
105
106 ConVars* _service = nullptr;
107 std::string _name;
108 CVValue_t* _storage = nullptr;
109 EConVarType _type{}; ///< so Get reads the declared width
110};
111
112/** Convar lookup, console commands, client overrides, and global change events. */
114{
115public:
116 /** @p interfaces must outlive this service. */
117 explicit ConVars(Interfaces& interfaces);
118 ~ConVars();
119 ConVars(const ConVars&) = delete;
120 ConVars& operator=(const ConVars&) = delete;
121
122 /** NotReady when ICvar is unavailable. */
123 Status Available() const;
124
125 /** Resolve by name. Returns NotFound when absent and Invalid on a type mismatch. */
126 template <ConVarValue T>
127 Result<ConVar<T>> Find(std::string_view name);
128
129 /** Queue a server console line. A line with an embedded newline is refused and logged. */
130 void ExecuteServerCommand(std::string_view command);
131
132 /** Queue each line of a cfg file, skipping blanks and `//` comments; `exec` reads only csgo/cfg. */
133 Status ExecuteFile(std::string_view path);
134
135 /**
136 * @brief Assign a convar over the console, quoting the value.
137 *
138 * The one place the `name value` console line is built, so the quoting rule is not
139 * rediscovered per call site: a space would truncate the value and a `;` would start a
140 * second command. A replicated payload sent straight to a client stays unquoted.
141 */
142 void SetByConsole(std::string_view name, std::string_view value);
143
144 /** All engine convar changes. The global callback exists only while this event has subscribers. */
146
147private:
148 template <class U>
149 friend class ConVar;
150
151 bool SendToClient(int slot, std::string_view name, std::string_view value);
152
153 INetworkMessageInternal* SetConVarMessage();
154
155 bool RouteChanges();
156 void StopRoutingChanges();
157
158 Interfaces& _interfaces;
159 bool _routingChanges = false;
160 INetworkMessageInternal* _setConVarMsg = nullptr;
161};
162
163/** Console and network text for a supported convar value. Bools use `1` and `0` for clients. */
164template <class T>
165std::string ConVarText(const T& value);
166
167template <>
168std::string ConVarText<bool>(const bool& value);
169template <>
170std::string ConVarText<int>(const int& value);
171template <>
172std::string ConVarText<float>(const float& value);
173template <>
174std::string ConVarText<std::string>(const std::string& value);
175
176} // namespace VoltMod
ConVarRawScope(const ConVarRawScope &)=delete
ConVarRawScope & operator=(ConVarRawScope &&)=delete
ConVarRawScope(ConVarRawScope &&other) noexcept
Definition ConVar.hpp:52
ConVarRawScope & operator=(const ConVarRawScope &)=delete
T Get() const
Definition ConVar.cpp:69
ConVarRawScope< T > RawScope(const T &value)
Definition ConVar.hpp:89
std::string_view Name() const
Definition ConVar.hpp:95
friend class ConVarRawScope< T >
Definition ConVar.hpp:100
Status Set(const T &value)
Definition ConVar.cpp:107
void SetFor(int slot, const T &value) const
Definition ConVar.cpp:156
ConVar()=default
void SetByConsole(std::string_view name, std::string_view value)
Assign a convar over the console, quoting the value.
Definition ConVars.cpp:112
Result< ConVar< T > > Find(std::string_view name)
Definition ConVar.cpp:33
Status ExecuteFile(std::string_view path)
Definition ConVars.cpp:88
ConVars(const ConVars &)=delete
Event< const ConVarChange & > Changed
Definition ConVar.hpp:145
ConVars & operator=(const ConVars &)=delete
void ExecuteServerCommand(std::string_view command)
Definition ConVars.cpp:62
Status Available() const
Definition ConVars.cpp:53
A multicast signal with a fixed handler signature: the one way to subscribe in VoltMod.
Definition Event.hpp:54
std::string ConVarText< std::string >(const std::string &value)
std::string ConVarText(const T &value)
std::string ConVarText< int >(const int &value)
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
std::expected< void, Error > Status
Definition Result.hpp:67
std::string ConVarText< float >(const float &value)
std::expected< T, Error > Result
Definition Result.hpp:64
std::string ConVarText< bool >(const bool &value)
std::string_view Name
Definition ConVar.hpp:20
std::string_view OldValue
Definition ConVar.hpp:21
std::string_view NewValue
Definition ConVar.hpp:22
Centralized holder for all HL2SDK interface pointers.