VoteManagerApi 1.2.0

dotnet add package VoteManagerApi --version 1.2.0
                    
NuGet\Install-Package VoteManagerApi -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="VoteManagerApi" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="VoteManagerApi" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="VoteManagerApi" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add VoteManagerApi --version 1.2.0
                    
#r "nuget: VoteManagerApi, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package VoteManagerApi@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=VoteManagerApi&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=VoteManagerApi&version=1.2.0
                    
Install as a Cake Tool

VoteManagerApi

Shared API for the VoteManager CounterStrikeSharp plugin. Reference this package to start and observe votes from your own plugin. VoteManagerCore runs them and draws them on a Panorama HUD, and only one vote runs at a time, server-wide.

The server must have VoteManagerCore installed (addons/counterstrikesharp/plugins/VoteManagerCore/) plus VoteManagerApi.dll in addons/counterstrikesharp/shared/VoteManagerApi/; both ship in the release zip. Clients need the Vote Manager HUD workshop item mounted on the server, or the vote runs with nothing drawn.

Install

dotnet add package VoteManagerApi

CounterStrikeSharp loads VoteManagerApi.dll from shared/, so your plugin must not ship its own copy:

<PackageReference Include="VoteManagerApi" Version="1.0.*" ExcludeAssets="runtime" Private="false" />

Usage

Resolve the plugin capability once all plugins are loaded, then start a vote:

using VoteManagerApi;
using VoteManagerApi.Enums;
using VoteManagerApi.Votes;

private IVoteManagerApi? _voteManager;

public override void OnAllPluginsLoaded(bool hotReload)
{
    _voteManager = IVoteManagerApi.PluginCapability.Get();
}

private void StartMapVote()
{
    var players = Utilities.GetPlayers().Where(p => p.IsValid && !p.IsBot).ToList();

    var vote = new YesNoVoteInfo(
        title: "Change map to de_dust2?",
        duration: 20,
        potentialClients: players,
        thresholdType: VoteThresholdType.Percentage,
        voteThreshold: 0.6f);

    var state = _voteManager?.InitiateVote(vote,
        onVoteFinish: (info, _, selected) =>
        {
            if (info is YesNoVoteInfo yesNo && yesNo.IsVoteSuccessful())
                Server.ExecuteCommand("changelevel de_dust2");
        },
        onFailure: (_, failed) => Server.PrintToChatAll($"Vote failed: {failed}"));

    if (state != VoteState.InitializeAccepted)
        Server.PrintToChatAll("A vote is already running.");
}

A multi-option vote is decided by plurality, no threshold involved:

var vote = new MultiOptionsVote(
    title: "Next map?",
    options: [new("de_dust2", "Dust II"), new("de_mirage", "Mirage")],
    duration: 20,
    potentialClients: players);

_voteManager?.InitiateVote(vote, onVoteFinish: (_, _, selected) =>
{
    if (selected is not null)
        Server.ExecuteCommand($"changelevel {selected.Identifier}");
});

Input mode and layout

All are init properties on any VoteInfo:

var vote = new MultiOptionsVote("Next map?", options, 20, players)
{
    InputMode   = VoteInputMode.Keys,   // Cursor, Keys, or Both (default)
    AllowRevote = false,                // default true
    Layout      = new VoteLayout("panorama/layout/custom_game/my_vote.vxml_c", "MyVoteRoot", OptionSlots: 8),
};
Property Default Meaning
InputMode Both Cursor takes the mouse while the card is up so options can be clicked. Keys leaves the mouse alone; players run css_1..css_6 for the option on their current page (1 = Yes, 2 = No on a yes/no vote), css_7 for the previous page and css_8 for the next. Both does both
AllowRevote true Whether a player can change their vote after casting. When false the first cast is final; later clicks, keys and css_revote are ignored for that player
Layout null The Panorama layout that draws the vote. null is the built-in design. A custom layout must follow the built-in id contract; see the repository README, "Custom vote layouts", and the skills/vote-manager-layout agent skill

The HUD shows live counts, share bars, a threshold marker on yes/no votes, a countdown, the viewer's own vote, the current leader, and the result for a few seconds after the vote ends. More options than a layout has rows paginate, per viewer.

API

Member Purpose
IVoteManagerApi.PluginCapability PluginCapability<IVoteManagerApi?> for "votemanager:api"
InitiateVote(vote, finishOnAllVote, onVoteFinish, onFailure, onVoteCast) Starts a vote; returns InitializeAccepted on success
CancelVote() Cancels the running vote
IsVoteInProgress / GetCurrentVoteState() Whether a vote is running, and its VoteState
GetCurrentVote() The running VoteInfo, or null

finishOnAllVote (default true) ends the vote as soon as every potential client has voted, instead of waiting out the full duration. Players can change their vote until it ends unless AllowRevote is false.

Callbacks

Delegate Signature
VoteFinishHandler (VoteInfo vote, VoteState state, VoteOption? selectedOption)
VoteFailureHandler (VoteInfo vote, VoteState state)
VoteCastHandler (VoteInfo vote, CCSPlayerController? player, VoteOption option)

Exceptions thrown by a callback are logged by VoteManagerCore and do not stop the vote from completing.

Vote types

Type Constructor Result
YesNoVoteInfo (title, duration, potentialClients, thresholdType, voteThreshold) IsVoteSuccessful(): yes-votes / total votes vs. the threshold
MultiOptionsVote (title, options, duration, potentialClients) GetSelectedOption(): the option with the most votes

VoteThresholdType.Percentage takes voteThreshold in 0.0..1.0 (out-of-range falls back to 0.5). VoteThresholdType.AbsoluteValue ignores voteThreshold, so use Percentage for YesNoVoteInfo.

Subclass VoteInfo for anything else: override GetSelectedOption() / IsVoteFinished() to change how a winner is picked, and use GetVotes(identifier) / GetTotalVotes() for the tallies. Any other VoteInfo subclass is drawn with the multi-option layout.

License

Apache-2.0

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 96 9/5/2026
1.1.0 100 9/5/2026
1.0.2 109 8/11/2026
1.0.1 94 8/11/2026
1.0.0 94 8/11/2026