YappersHQ.ReservedSlots.Shared
1.0.1
dotnet add package YappersHQ.ReservedSlots.Shared --version 1.0.1
NuGet\Install-Package YappersHQ.ReservedSlots.Shared -Version 1.0.1
<PackageReference Include="YappersHQ.ReservedSlots.Shared" Version="1.0.1" />
<PackageVersion Include="YappersHQ.ReservedSlots.Shared" Version="1.0.1" />
<PackageReference Include="YappersHQ.ReservedSlots.Shared" />
paket add YappersHQ.ReservedSlots.Shared --version 1.0.1
#r "nuget: YappersHQ.ReservedSlots.Shared, 1.0.1"
#:package YappersHQ.ReservedSlots.Shared@1.0.1
#addin nuget:?package=YappersHQ.ReservedSlots.Shared&version=1.0.1
#tool nuget:?package=YappersHQ.ReservedSlots.Shared&version=1.0.1
<div align="center"> <h1><strong>ReservedSlots</strong></h1> <p>Reserved slots for CS2 / ModSharp — keep seats free for your VIPs and admins on a full server.</p> </div>
<p align="center"> <a href="https://github.com/Kxnrl/modsharp-public"><img src="https://img.shields.io/badge/framework-ModSharp-5865F2?logo=github" alt="ModSharp"></a> <img src="https://img.shields.io/badge/game-CS2-orange" alt="CS2"> <img src="https://img.shields.io/badge/license-MIT-green" alt="MIT"> <img src="https://img.shields.io/gitlab/stars/cs2-server-plugins/cs2-reservedslots?gitlab_url=https%3A%2F%2Fgitlab.com" alt="Stars"> </p>
ReservedSlots keeps a configurable number of slots reserved for privileged players. When the public quota is full, ordinary players are rejected at connection time while VIPs and admins are still let in. It can optionally kick a non-privileged player when the server fills completely, so a seat is always free for the next VIP/admin. VIP membership is supplied by other plugins through a small shared interface (IReservedSlotsShared); admin/VIP flags come from ModSharp's AdminManager.
🚀 Install
Copy the build output into your ModSharp install (<sharp> = your sharp directory):
| From | To |
|---|---|
.build/modules/ReservedSlots.Core/ |
<sharp>/modules/ReservedSlots.Core/ |
.build/shared/ReservedSlots.Shared/ |
<sharp>/shared/ReservedSlots.Shared/ |
.build/configs/cs2-reservedslots.json |
<sharp>/configs/cs2-reservedslots.json |
Restart the server (or change map) to load. The config is written with defaults on first run if it doesn't exist. AdminManager (ships with ModSharp) is used for admin/VIP flags — without it, flag-based access is skipped (a warning is logged) and only the shared-interface VIP source applies.
⚙️ Configuration
configs/cs2-reservedslots.json (auto-generated on first run):
| Setting | Default | Meaning |
|---|---|---|
TotalReservedSlots |
3 |
Total reserved slots. Public limit = MaxClients - TotalReservedSlots. Set 0 to disable the gate entirely. |
VipSlots |
2 |
How many of the reserved slots VIPs (and the VipFlag) may fill. |
AdminSlots |
1 |
Admin-only reserved slots (the depth between VipSlots and TotalReservedSlots). |
AdminFlag |
@reservedslots/admin |
Admin permission that grants admin-level reserved access. |
VipFlag |
@reservedslots/vip |
Admin permission that grants VIP-level reserved access. |
KickType |
None |
None = join-gating only (nobody already connected is touched). Kick = when the server is completely full, kick a non-privileged player to keep a slot free. Legacy Spectate is treated as Kick. |
AllowAdminsToFillVipSlots |
true |
If true, admins may also occupy VIP slots, not just admin-only slots. |
Both @reservedslots/admin and @reservedslots/vip are registered with AdminManager on load, so they can be assigned to admin groups.
🔧 How it works
Reservation is enforced at the connection hook (ConnectClient), not the admin check — OnClientPreAdminCheck can't reject a connection. The connecting player is counted as +1; if that pushes the human count past the public limit (MaxClients - TotalReservedSlots), the player must hold reserved access or they're rejected with RejectServerFull. Reserved access is tiered: VIPs and the VIP flag fill the first VipSlots of depth, admins fill the remaining admin-only depth (and the VIP depth too when AllowAdminsToFillVipSlots is set). Players who just disconnected get a 180-second reconnect grace so changelevel / reconnect storms never bump someone who was already in the match.
With KickType: Kick, a completely full server instead kicks one non-privileged player after a new join — spectators first, then the most recently connected (long-time players keep their seat) — deferred to the end of the frame to avoid racing the engine's snapshot send path.
CS2 has no
maxplayersconvar — the gate reads the engine's liveMaxClients. If that's unavailable the gate is inert (fails open). The live slot math is logged at every map start.
🧩 Public API
VIP membership is not stored here — other plugins declare who is a VIP through IReservedSlotsShared. Resolve it in OnAllModulesLoaded and subscribe a predicate:
var rs = sharpModuleManager
.GetOptionalSharpModuleInterface<IReservedSlotsShared>(IReservedSlotsShared.Identity)?.Instance;
rs!.IsVipFor += client => /* is this IGameClient a VIP? */;
rs!.IsVipForSteamId += steamId => /* is this SteamID a VIP? */;
IsVipBySteamId(ulong) is also exposed for direct queries. If no subscriber claims a player, they're treated as non-VIP.
📦 Build
dotnet build -c Release
Outputs the module to .build/modules/ReservedSlots.Core/ReservedSlots.dll, the shared contract to .build/shared/ReservedSlots.Shared/ReservedSlots.Shared.dll, and the default config to .build/configs/cs2-reservedslots.json.
<div align="center"> <p>Made with ❤️ by <a href="https://gitlab.com/cs2-server-plugins">cs2-server-plugins</a></p> <p>⭐ Star this repo if you find it useful!</p> </div>
| Product | Versions 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. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.