One event server, every fun mode deployed — switch Prophunt, MiniHumans & friends live, no redeploys.
Licensed under GPL-3.0.
EventManager is a centralized optional gate for fun-mode plugins on a CS2 event/stream server.
All event plugins stay deployed at once and dormant; operators flip exactly one on with !events
— and back off to a fully vanilla server. The same plugin builds keep running standalone on their
dedicated servers: when the gate isn't installed, they behave exactly as before. This repo also
bundles ChallengeEngine, a full session-based competitive gamemode ("Challenge Night") built as
a reference IEventMode — see the ChallengeEngine section below.
Copy the build output into your ModSharp install (<sharp> = your sharp directory):
| From | To |
|---|---|
.build/modules/EventManager.Core/ |
<sharp>/modules/EventManager/ |
.build/shared/EventManager.Shared/ |
<sharp>/shared/EventManager.Shared/ |
.assets/locales/eventmanager.json |
<sharp>/locales/eventmanager.json |
.assets/configs/eventmanager.pins.jsonc.example (optional — workshop-map convar protection) |
<sharp>/configs/eventmanager.pins.jsonc.example |
.build/modules/EventManager.LowGravity/ (optional demo event) |
<sharp>/modules/EventManager.LowGravity/ |
.build/modules/ChallengeEngine/ (bundled "Challenge Night" event) |
<sharp>/modules/ChallengeEngine/ |
.build/shared/ChallengeEngine.Shared/ |
<sharp>/shared/ChallengeEngine.Shared/ |
.assets/locales/challengeengine.json |
<sharp>/locales/challengeengine.json |
.assets/gamedata/challengeengine.games.jsonc |
<sharp>/gamedata/challengeengine.games.jsonc |
Restart the server (or change map) to load. Rename eventmanager.pins.jsonc.example to
eventmanager.pins.jsonc to activate convar protection — absent, it's a no-op.
Uses the ModSharp first-party modules (ship with ModSharp): CommandCenter (the events
command), AdminManager (permission gate), MenuManager (the !events menu),
LocalizerManager (all user-facing text). All four are optional — the plugin degrades
gracefully, but without CommandCenter there is no way to operate it.
Bundled: Microsoft.Extensions.DependencyInjection (ships inside the module). ChallengeEngine and
the website/API bridge also bundle MySqlConnector + SqlSugarCoreNoDrive for optional persistence
— both stay inert (no-op) if no configs/*.database.jsonc is present.
One command, admin-gated (eventmanager:admin); also available from server console/RCON as events ….
| Command | Description |
|---|---|
!events |
Open the menu: pick/toggle events, edit their settings, stream tools |
!events list |
List registered events (● active, ▶ armed-and-waiting) |
!events on <id> |
Select an event — in the default Warmup start mode this only arms it in a paused warmup lobby; Direct mode activates it immediately |
!events start |
Start the armed event: activates it and ends warmup into round 1 |
!events startmode warmup|direct |
Switch how on <id> behaves (see above) |
!events off |
Disarm the armed event, or deactivate the active one — back to the vanilla warmup lobby |
!events set <id> <key> <value> |
Apply an event's setting (validated by the event itself) |
!events intro on|off |
Intro mode — round can't end while a stream shot is set up |
!events respawnall |
Respawn every dead T/CT |
!events countdown [secs] |
Center-screen countdown → "GO!" |
EventManager publishes IEventManagerShared in PostInit; fun-mode plugins look it up in their
OnAllModulesLoaded. Gate absent → the plugin activates itself (standalone server, unchanged
behaviour). Gate present → it registers an IEventMode and stays dormant until an operator
activates it. The coordinator enforces at most one active event, always boots to a paused
warmup lobby ground state (never mid-round), and events expose their own settings through the
contract — strings at the boundary, no convars. Selecting an event either arms it (default
Warmup start mode: parked in the lobby until !events start) or activates it immediately (Direct
mode); either way the manager captures each event's declared GameConVars and restores the
original values on deactivate/switch, even if the event's own teardown throws. A
ConVarPinsModule separately protects a configurable convar set (sv_cheats, sv_gravity, …)
against hostile workshop-map cfgs/vscripts by blocking point_servercommand writes and
re-asserting pinned values at map/round start — inert unless eventmanager.pins.jsonc exists. An
optional web bridge module lets an external dashboard observe live state and drive the same
!events actions remotely; it's inert without a configs/*.database.jsonc. See
docs/SPEC.md for the design and docs/INTEGRATION.md for the
step-by-step gamemode integration guide.
ChallengeEngine is a satellite gamemode built on top of the gate itself: it registers as the
"Challenge Night" IEventMode and hosts round-based scored challenges over a 30 min–3 h session
with a points ledger, escalation, a grand finale, and a crowned champion. It ships five real
challenges — King of the Hill, Bomb Tag, Gun Game, Territories, and The Purge — plus an internal
smoke-test challenge not shown to players. Session state persists to MySQL (ce_* tables) when a
DB config is present; otherwise the session simply runs in memory. Its own settings (challenge
pick, duration, escalation interval, finale size, autostart) and operator actions (force finale,
extend, inject a modifier, …) are all exposed through the same IEventMode contract, so it's
driven entirely from the !events menu — no separate command set. See
docs/CHALLENGE_ENGINE.md for the full design.
Fun-mode plugins consume IEventManagerShared (resolve in OnAllModulesLoaded):
var gate = sharpModuleManager
.GetOptionalSharpModuleInterface<IEventManagerShared>(IEventManagerShared.Identity)?.Instance;
if (gate is null)
ActivateGameplay(); // dedicated server — run as always
else
_registration = gate.RegisterEvent(mode); // event server — dormant until !eventsEventManager.LowGravity in this repo is a minimal reference implementation (one setting, one
convar); ChallengeEngine is a complete reference for a full session-based event.
dotnet build -c ReleaseOutputs .build/modules/EventManager.Core/EventManager.dll,
.build/shared/EventManager.Shared/EventManager.Shared.dll, the optional
.build/modules/EventManager.LowGravity/ demo event, and the bundled
.build/modules/ChallengeEngine/ChallengeEngine.dll +
.build/shared/ChallengeEngine.Shared/ChallengeEngine.Shared.dll.
Made with ❤️ by yappershq
⭐ Star this repo if you find it useful!