VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
GameEvents.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <igameevents.h>
4
12#include <cstdint>
13#include <functional>
14#include <map>
15#include <string>
16#include <string_view>
17
18namespace VoltMod
19{
20
21/** @brief Creates, fires and listens to game events. */
22class GameEvents : public IGameEventListener2
23{
24public:
25 /** Reads IGameEventManager2 into @p interfaces. Both must outlive this service. */
27 ~GameEvents() override;
28 GameEvents(const GameEvents&) = delete;
29 GameEvents& operator=(const GameEvents&) = delete;
30
31 /** An error when the event manager did not resolve. */
32 Status Available() const;
33
34 IGameEvent* CreateEvent(std::string_view name);
35 bool FireEvent(IGameEvent* event, bool broadcast = true);
37
38 /** Subscribe to @p TEvent, a struct from `<VoltMod/Events/EventTypes.hpp>`, while the returned
39 * Subscription lives. An event whose `Slot` is invalid never reaches @p handler. */
40 template <class TEvent>
41 [[nodiscard]] Subscription On(std::function<void(const TEvent&)> handler)
42 {
43 return Add(TEvent::EventName, [h = std::move(handler)](IGameEvent* e) {
44 if (!e)
45 {
46 return;
47 }
48 const TEvent event = TEvent::From(*e);
49 if constexpr (requires { event.Slot; })
50 {
51 if (!IsValidSlot(event.Slot))
52 {
53 return;
54 }
55 }
56 h(event);
57 });
58 }
59
60 /** Remove every handler and detach from the engine. */
61 void RemoveAllListeners();
62
63 /** Re-attach every event that still has a handler: map startup resets the engine's listeners. */
64 void OnServerStartup();
65
66 /** @p slot's client listener: an event fired at it reaches that client alone. Null without a
67 * client or when the GetLegacyGameEventListener signature did not bind. */
68 IGameEventListener2* GetClientLegacyListener(int slot) const;
69
70 /** Whether @p slot's client listens to @p eventName; a vanilla client takes only what its HUD
71 * needs, so an extra one can mean injected code. */
72 bool ClientListensTo(int slot, std::string_view eventName) const;
73
74 void FireGameEvent(IGameEvent* event) override;
75
76private:
77 using EventCallback = std::function<void(IGameEvent*)>;
78
79 [[nodiscard]] Subscription Add(std::string_view eventName, EventCallback callback);
80
81 struct EventHandlers
82 {
84 bool Attached = false;
85 };
86
87 using GetLegacyGameEventListenerFn = IGameEventListener2* (*)(CPlayerSlot slot);
88
89 Interfaces& _interfaces;
90 const Bindings& _bindings;
91 /** Never erased: subscriptions point at their entry's registry. */
92 std::map<std::string, EventHandlers, std::less<>> _events;
93 GetLegacyGameEventListenerFn _getLegacyListener = nullptr;
94};
95
96} // namespace VoltMod
Creates, fires and listens to game events.
~GameEvents() override
Status Available() const
GameEvents(const GameEvents &)=delete
Subscription On(std::function< void(const TEvent &)> handler)
void FreeEvent(IGameEvent *event)
bool FireEvent(IGameEvent *event, bool broadcast=true)
IGameEvent * CreateEvent(std::string_view name)
GameEvents & operator=(const GameEvents &)=delete
IGameEventListener2 * GetClientLegacyListener(int slot) const
bool ClientListensTo(int slot, std::string_view eventName) const
void FireGameEvent(IGameEvent *event) override
Owns one registration and releases it on destruction.
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
constexpr bool IsValidSlot(int slot)
Definition Slot.hpp:13
std::expected< void, Error > Status
Definition Result.hpp:67
Centralized holder for all HL2SDK interface pointers.