NativeVoteManagerMS.Shared 0.0.5

dotnet add package NativeVoteManagerMS.Shared --version 0.0.5
                    
NuGet\Install-Package NativeVoteManagerMS.Shared -Version 0.0.5
                    
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="NativeVoteManagerMS.Shared" Version="0.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NativeVoteManagerMS.Shared" Version="0.0.5" />
                    
Directory.Packages.props
<PackageReference Include="NativeVoteManagerMS.Shared" />
                    
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 NativeVoteManagerMS.Shared --version 0.0.5
                    
#r "nuget: NativeVoteManagerMS.Shared, 0.0.5"
                    
#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 NativeVoteManagerMS.Shared@0.0.5
                    
#: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=NativeVoteManagerMS.Shared&version=0.0.5
                    
Install as a Cake Addin
#tool nuget:?package=NativeVoteManagerMS.Shared&version=0.0.5
                    
Install as a Cake Tool

NativeVoteManagerMS

A ModSharp module for Counter-Strike 2 that provides a native vote management system. Supports both YesNo votes (using CS2's built-in vote UI) and MultiChoice votes (using a pluggable menu system).

Features

  • YesNo Vote - Uses CS2's native vote UI (CCSUsrMsg_VoteStart / CCSUsrMsg_VotePass / CCSUsrMsg_VoteFailed)
  • MultiChoice Vote - Menu-based voting with configurable options
  • Pluggable Architecture - Menu system and permission system are abstracted via IMenuCompat / IPermissionCompat
  • Localization - Supports per-client localized messages via LocalizerManager
  • Commands - !cancelvote (with permission check), !revote (reopen MultiChoice menu)
  • Automatic Cleanup - Vote state is cleaned up on map change

Project Structure

Project Description
NativeVoteManagerMS Core module - vote lifecycle, commands, localization
NativeVoteManagerMS.Shared Public API - INativeVoteManager, types, compat interfaces
NvmFPMCompat FPM connector - implements IMenuCompat and IPermissionCompat using FPM's MenuManager and AdminManager
NativeVoteExample Example module demonstrating how to use the API

Dependencies

  • ModSharp.Sharp.Shared >= 2.1.118
  • ModSharp.Sharp.Modules.LocalizerManager.Shared >= 2.1.118
  • ModSharp.Sharp.Modules.AdminManager.Shared >= 2.1.118 (NvmFPMCompat only)
  • ModSharp.Sharp.Modules.MenuManager.Shared >= 2.1.118 (NvmFPMCompat only)

Installation

Grab the latest release zip from Releases (or build from source), then:

  1. Deploy NativeVoteManagerMS.dll and NativeVoteManagerMS.Shared.dll to your ModSharp modules directory
  2. Deploy NvmFPMCompat.dll (or your own compat implementation)
  3. Copy locales/nativevotemanager.json to {sharp}/locales/

For Plugin Developers (consuming the API)

If you're writing a plugin that uses INativeVoteManager, add the Shared package from NuGet:

<ItemGroup>
  <PackageReference Include="NativeVoteManagerMS.Shared" Version="*" ExcludeAssets="runtime" />
</ItemGroup>

Or via CLI:

dotnet add package NativeVoteManagerMS.Shared

ExcludeAssets="runtime" is important — the Shared DLL is already shipped by the server-side module, so you must not bundle it with your plugin.

Check NuGet.org for the latest version.

Usage

Getting the API

public void OnAllModulesLoaded()
{
    var voteManager = _sharedSystem.GetSharpModuleManager()
        .GetRequiredSharpModuleInterface<INativeVoteManager>(INativeVoteManager.ModSharpModuleIdentity)
        .Instance!;
}

YesNo Vote

YesNo votes use CS2's native vote UI, which only accepts SFUI translation keys (strings starting with #). The game engine performs client-side translation — the plugin's LocalizerManager is not applied to Title / Description.

  • Title — SFUI key for the vote question (e.g. #SFUI_vote_kick_player). Defaults to #SFUI_Vote_None.
  • Description — argument substituted into the Title template (%s1%). Leave empty for templates that take no argument.
var options = new YesNoVoteOptions
{
    Title = "#SFUI_vote_kick_player",  // SFUI key — engine translates per client
    Description = targetPlayer.Name,   // %s1% substitution in the SFUI template
    Participants = null, // null = all players
    PassCondition = result => result.Choices[0].Voters.Count > result.Choices[1].Voters.Count,
    VoteDuration = 10.0F,
    VoteHandler = new YesNoVoteHandler(sharedSystem),
    VoteInitiator = executor.Slot
};

var result = voteManager.InitiateYesNoVote(options);
if (result != VoteInitiateResult.Success)
{
    // Handle error
}
YesNo Vote Handler
public class YesNoVoteHandler(ISharedSystem sharedSystem) : IYesNoVoteHandler
{
    public void OnVoteInitiated() { }

    public void OnChoice(IGameClient chooser, bool isYes, YesNoVoteState state)
    {
        // Called each time a player votes
    }

    public void OnVotePassed(VoteResult result) { }
    public void OnVoteFailed(VoteResult result) { }
    public void OnVoteCancelled() { }
}

MultiChoice Vote

var voteContents = new List<VoteContent>
{
    new() { Index = 0, InternalName = "map_dust2", VisibleName = LocalizedString.From(_ => "Dust 2") },
    new() { Index = 1, InternalName = "map_mirage", VisibleName = LocalizedString.From(_ => "Mirage") },
    new() { Index = 2, InternalName = "map_inferno", VisibleName = LocalizedString.From(_ => "Inferno") },
};

var options = new MultiChoiceVoteOptions
{
    Title = LocalizedString.From(_ => "Next Map?"),
    Description = LocalizedString.From(_ => "Choose the next map"),
    Participants = null,
    VoteDuration = 15.0F,
    VoteHandler = new MultiChoiceVoteHandler(sharedSystem),
    VoteContents = voteContents,
    RandomShuffle = true
};

voteManager.InitiateMultiChoiceVote(options);
MultiChoice Vote Handler
public class MultiChoiceVoteHandler(ISharedSystem sharedSystem) : IMultiChoiceVoteHandler
{
    public void OnVoteInitiated() { }

    public void OnChoice(IGameClient chooser, VoteContent content, MultiChoiceVoteState state)
    {
        // Called each time a player selects an option
    }

    public void OnVotePassed(VoteResult result)
    {
        // result.Winner contains the most voted VoteContent
    }

    public void OnVoteFailed(VoteResult result) { }
    public void OnVoteCancelled() { }
}

Return Values

All vote operations return result enums instead of throwing exceptions:

// Initiate
VoteInitiateResult.Success
VoteInitiateResult.VoteAlreadyInProgress
VoteInitiateResult.NoMenuCompatSet

// Cancel
VoteCancelResult.Success
VoteCancelResult.NoVoteInProgress

// End
VoteEndResult.Success
VoteEndResult.NoVoteInProgress

Custom Compat Implementation

NativeVoteManagerMS uses a pluggable architecture. If you don't use FPM modules, you can implement your own compat layer.

IMenuCompat

Required for MultiChoice votes. See NvmFPMCompat/FpmMenuCompat.cs for a reference implementation.

public interface IMenuCompat
{
    void OpenMenu(IGameClient target);
    void CloseMenu(IGameClient target);
    void SetVoteOptions(MultiChoiceVoteOptions options);
    void Cleanup();
    Action<IGameClient, VoteContent> OnChoice { get; set; }
}

IPermissionCompat

Required for permission-gated commands (!cancelvote). See NvmFPMCompat/FPMPermissionCompat.cs for a reference implementation.

public interface IPermissionCompat
{
    bool HasPermission(IGameClient client, string permission);
}

Registering Compat

public void OnAllModulesLoaded()
{
    var voteManager = _sharedSystem.GetSharpModuleManager()
        .GetRequiredSharpModuleInterface<INativeVoteManager>(INativeVoteManager.ModSharpModuleIdentity)
        .Instance!;

    voteManager.SetDefaultMenuCompat(new YourMenuCompat());
    voteManager.SetDefaultPermissionCompat(new YourPermissionCompat());
}

Permissions

Permission Description
nvm.vote.cancel Allow player to use !cancelvote

License

Copyright (c) 2025-2026 faketuna

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
0.0.5 96 4/28/2026
0.0.4 96 4/22/2026
0.0.3 109 4/17/2026
0.0.2 108 4/17/2026 0.0.2 is deprecated.
0.0.1 112 4/17/2026 0.0.1 is deprecated.