VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
Vote.hpp
Go to the documentation of this file.
1#pragma once
2
13#include <array>
14#include <functional>
15#include <optional>
16#include <string>
17#include <string_view>
18
19namespace VoltMod
20{
21
22/** Why a vote stopped taking ballots. */
23enum class VoteEndReason
24{
25 AllVoted, ///< every eligible player cast a ballot
26 TimeUp,
27 Cancelled, ///< an admin (or a peer feature) called it off
28};
29
30/** The tally handed to @ref VoteRequest::Passed. */
32{
33 int Eligible = 0; ///< players who could vote
34 int Yes = 0;
35 int No = 0;
36
37 int Cast() const { return Yes + No; }
38};
39
40/** A yes/no vote for @ref Vote::Start. */
42{
43 /** A `#SFUI_vote...` or `#Panorama_vote...` token the client already has; other text does not render. */
44 std::string Title;
45 /** The token's detail string, often a map or player name. */
46 std::string Detail;
47 /** How long before the vote closes itself. */
48 int DurationMs = 30000;
49 /** Whose name the panel credits; -1 for the server. */
50 int Caller = -1;
51 /** Decides whether the vote passed. Called once when voting ends, never for a cancelled vote. */
52 std::function<bool(const VoteTally&)> Passed;
53 /** Called after the pass/fail panel is sent, with what @ref Passed decided. */
54 std::function<void(bool passed, VoteEndReason reason)> Finished;
55};
56
57/**
58 * @brief The game's yes/no vote panel (F1/F2), with the ballots counted here.
59 *
60 * One vote at a time, open to every connected human; bots get no panel and no ballot. Callbacks
61 * run on the game thread.
62 *
63 * @code
64 * runtime.Vote.Start({.Title = "#SFUI_vote_changelevel", .Detail = map, .DurationMs = 20000,
65 * .Passed = [](const VoltMod::VoteTally& tally) { return tally.Yes > tally.No; }});
66 * @endcode
67 */
68class Vote
69{
70public:
71 /** All five must outlive this service; the Runtime declares them above it. */
74 Vote(const Vote&) = delete;
75 Vote& operator=(const Vote&) = delete;
76
77 /** Open @p request's vote. False when one is already running, it has no @ref VoteRequest::Passed,
78 * or no human is connected. */
80
81 /** End the running vote early. No-op when none is running. */
83
84 bool InProgress() const { return _running.has_value(); }
85
86 /** @internal Called by the framework for every `vote <option>` console command, as the
87 * panel's F1/F2 keys send it. True while a vote is running: the engine must not see it. */
88 bool TryCastBallot(int slot, std::string_view option);
89
90private:
91 struct Ballot
92 {
93 VoteRequest Request;
94 VoteTally Tally;
95 /** Eligible players who have not voted yet. */
96 std::array<bool, MaxPlayers> Waiting{};
97 /** The timeout, and the deferred close once every ballot is in. Owned here, so ending the
98 * vote cancels both. */
99 Subscription Timeout;
100 Subscription Close;
101 };
102
103 /** The map's vote controller, or an empty handle. Never stored: a map change frees it. */
104 Schema::CVoteController Controller();
105 void Finish(VoteEndReason reason);
106 /** Stop waiting on @p slot, whose player left before voting. */
107 void DropVoter(int slot);
108 void CloseIfAllVoted();
109 void SendStart(const Ballot& ballot);
110 void SendOutcome(const VoteRequest& request, bool passed);
111 void PublishBallot(int slot, int option);
112 void PublishCounts(const VoteTally& tally);
113 /** Every connected human - who a vote panel is sent to. */
114 MultiRecipientFilter Recipients() const;
115
116 Interfaces& _interfaces;
117 EntitySystem& _entities;
118 PlayerManager& _players;
119 GameEvents& _events;
120 Scheduler& _scheduler;
121
122 /** Resolved message types, cached on first send; they are stable for the process. */
123 INetworkMessageInternal* _voteStartInternal = nullptr;
124 INetworkMessageInternal* _votePassInternal = nullptr;
125 INetworkMessageInternal* _voteFailedInternal = nullptr;
126 std::optional<Ballot> _running;
127 /** Declared last so it unregisters before the ballot its handler edits. */
128 Subscription _leaving;
129};
130
131} // namespace VoltMod
runtime.Entities: finds and creates entities. Everything it returns is valid for this frame only; see...
Creates, fires and listens to game events.
The roster: every connected player, and the signals for the connection lifecycle.
One-shot delays and repeating timers, run on the game thread.
Definition Scheduler.hpp:18
The game's yes/no vote panel (F1/F2), with the ballots counted here.
Definition Vote.hpp:69
Vote(const Vote &)=delete
Vote & operator=(const Vote &)=delete
bool TryCastBallot(int slot, std::string_view option)
Definition Vote.cpp:146
bool Start(VoteRequest request)
Definition Vote.cpp:109
void End(VoteEndReason reason)
Definition Vote.cpp:205
bool InProgress() const
Definition Vote.hpp:84
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
VoteEndReason
Definition Vote.hpp:24
@ Cancelled
an admin (or a peer feature) called it off
@ AllVoted
every eligible player cast a ballot
Who invoked the command, and how to answer them.
Centralized holder for all HL2SDK interface pointers.
std::function< bool(const VoteTally &)> Passed
Definition Vote.hpp:52
std::function< void(bool passed, VoteEndReason reason)> Finished
Definition Vote.hpp:54
std::string Detail
Definition Vote.hpp:46
std::string Title
Definition Vote.hpp:44
int Eligible
players who could vote
Definition Vote.hpp:33
int Cast() const
Definition Vote.hpp:37