VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
Messages.cpp
Go to the documentation of this file.
3
4#include <igameevents.h>
5
15#include <engine/igameeventsystem.h>
16#include <networksystem/inetworkmessages.h>
17#include <networksystem/netmessage.h>
18#include <shareddefs.h>
19#include <usermessages.pb.h>
20
21namespace VoltMod
22{
23
24// Prepend a space to preserve a leading color, or Default to prevent color carryover.
25static std::string EnsureColorPrefix(std::string_view message)
26{
27 std::string_view prefix =
28 (!message.empty() && static_cast<unsigned char>(message.front()) <= 0x10) // 0x01-0x10: color escape bytes
29 ? " "
31
32 std::string out;
33 out.reserve(prefix.size() + message.size());
34 out.append(prefix);
35 out.append(message);
36 return out;
37}
38
39static std::string Render(std::string_view message, MessageKind kind)
40{
41 return kind == MessageKind::Chat ? EnsureColorPrefix(message) : std::string(message);
42}
43
45{
46 switch (kind)
47 {
49 return HUD_PRINTCENTER;
51 return HUD_PRINTALERT;
52 default:
53 return HUD_PRINTTALK;
54 }
55}
56
60
62{
63 if (!_interfaces.GameEventSystem)
64 {
65 return std::unexpected(Error::NotReady("IGameEventSystem not available"));
66 }
67
68 if (!_interfaces.NetworkMessages)
69 {
70 return std::unexpected(Error::NotReady("INetworkMessages not available"));
71 }
72 return {};
73}
74
75void Messages::SendCenterHtml(int slot, const std::string& html)
76{
77 auto* gameEventManager = _interfaces.GameEventManager;
79 {
80 return;
81 }
82
84 if (!pEvent)
85 {
86 return;
87 }
88
89 pEvent->SetString("loc_token", html.c_str());
90 pEvent->SetInt("userid", slot);
91 pEvent->SetInt("duration", 5);
92
93 // Use the client's listener when available; otherwise the event broadcasts to every client.
94 if (IGameEventListener2* listener = _events.GetClientLegacyListener(slot))
95 {
96 listener->FireGameEvent(pEvent);
97 gameEventManager->FreeEvent(pEvent);
98 return;
99 }
100
101 gameEventManager->FireEvent(pEvent);
102}
103
104void Messages::Send(int slot, std::string_view message, MessageKind kind)
105{
107 {
108 SendCenterHtml(slot, std::string(message));
109 return;
110 }
111
112 SendTextMsg(slot, HudDestination(kind), Render(message, kind));
113}
114
116{
117 auto rendered = Render(message, kind);
118
120 {
121 // Each panel write targets one client's listener; null means the slot is empty.
122 for (int slot = 0; slot < MaxPlayers; ++slot)
123 {
124 if (_events.GetClientLegacyListener(slot))
125 {
127 }
128 }
129 return;
130 }
131
132 // One event lets the engine remove empty slots from recipient bits without a roster scan.
134 for (int slot = 0; slot < MaxPlayers; ++slot)
135 {
137 }
138
139 PostTextMsg(filter, HudDestination(kind), rendered);
140}
141
142void Messages::SendKey(int slot, std::string_view key, const Tokens& tokens, MessageKind kind)
143{
144 Send(slot, _translations.Get(key, slot, tokens), kind);
145}
146
148{
149 for (int slot = 0; slot < MaxPlayers; ++slot)
150 {
151 if (_events.GetClientLegacyListener(slot))
152 {
154 }
155 }
156}
157
158void Messages::SendTextMsg(int slot, int destination, const std::string& message)
159{
160 if (!IsValidSlot(slot))
161 {
162 return;
163 }
164
165 SingleRecipientFilter filter(slot);
166 PostTextMsg(filter, destination, message);
167}
168
169void Messages::PostTextMsg(IRecipientFilter& filter, int destination, const std::string& message)
170{
171 // Server chat uses TextMsg with HUD_PRINTTALK; SayText2 requires a connected source player.
172 PostUserMessage(_interfaces, _textMsgInternal, "TextMsg", filter, [&](CNetMessage* raw) {
173 auto* textMsg = raw->ToPB<CUserMessageTextMsg>();
174 if (!textMsg)
175 {
176 return false;
177 }
178 textMsg->set_dest(destination);
179 textMsg->add_param(message.c_str());
180 return true;
181 });
182}
183
184void Messages::Shake(int slot, float durationSec, float frequency, float amplitude)
185{
187 PostUserMessage(_interfaces, _shakeInternal, "Shake", filter, [&](CNetMessage* raw) {
188 auto* shake = raw->ToPB<CUserMessageShake>();
189 if (!shake)
190 {
191 return false;
192 }
193 shake->set_duration(durationSec);
194 shake->set_frequency(frequency);
195 shake->set_amplitude(amplitude);
196 shake->set_command(0); // SHAKE_START
197 return true;
198 });
199}
200
202{
203 SendCenterHtml(slot, " ");
204}
205
206} // namespace VoltMod
Creates, fires and listens to game events.
IGameEvent * CreateEvent(std::string_view name)
IGameEventListener2 * GetClientLegacyListener(int slot) const
void BroadcastKey(std::string_view key, const Tokens &tokens={}, MessageKind kind=MessageKind::Chat)
Definition Messages.cpp:147
Status Available() const
Definition Messages.cpp:61
void ClearCenterHtml(int slot)
Definition Messages.cpp:201
void SendCenterHtml(int slot, const std::string &html)
Definition Messages.cpp:75
void Send(int slot, std::string_view message, MessageKind kind=MessageKind::Chat)
Definition Messages.cpp:104
void Broadcast(std::string_view message, MessageKind kind=MessageKind::Chat)
Definition Messages.cpp:115
Messages(Interfaces &interfaces, GameEvents &events, Translations &translations)
Definition Messages.cpp:57
void SendKey(int slot, std::string_view key, const Tokens &tokens={}, MessageKind kind=MessageKind::Chat)
Definition Messages.cpp:142
void Shake(int slot, float durationSec, float frequency, float amplitude)
Definition Messages.cpp:184
Routes a user message or filtered sound to a chosen set of player slots. Starts empty; callers add ea...
Routes a user message to a single player slot.
Localization system. Loads one JSON file per language; nested objects flatten into dotted keys (categ...
std::string Get(std::string_view key) const
constexpr std::string_view Default
@ Center
Plain center-screen print.
@ Chat
Chat box line (color escapes honored).
@ CenterHtml
Center HTML panel (same channel the menu system renders into).
@ Alert
Top-center alert bar.
static std::string EnsureColorPrefix(std::string_view message)
Definition Messages.cpp:25
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
constexpr bool IsValidSlot(int slot)
Definition Slot.hpp:13
static std::string Render(std::string_view message, MessageKind kind)
Definition Messages.cpp:39
std::expected< void, Error > Status
Definition Result.hpp:67
static int HudDestination(MessageKind kind)
Definition Messages.cpp:44
std::map< std::string, std::string > Tokens
Definition Strings.hpp:14
constexpr int MaxPlayers
Definition Slot.hpp:7
bool PostUserMessage(Interfaces &interfaces, INetworkMessageInternal *&cached, std::string_view partialName, IRecipientFilter &filter, const std::function< bool(CNetMessage *)> &fill)
@ Send
point the client at AddonDecision::Id and wait for its reconnect
static Error NotReady(std::string detail)
Definition Result.hpp:50
Centralized holder for all HL2SDK interface pointers.
IGameEventSystem * GameEventSystem
INetworkMessages * NetworkMessages
IGameEventManager2 * GameEventManager
static constexpr std::string_view EventName