Releases: LCrew/S2-CSRoll
Release list
v1.37.3
Wallhack fix.
FEAT
- Wallhack works. Glow outlines render through walls for the holder alone, mimicking the real player via the bone-merged relay chain, alongside radar spotting. Configurable under a new
Xrayconfig section:RadarSpotting,GlowProps,GlowRealPawn,ClearIdentityFlagBit2. - New admin command
!rolltestall [seconds]. Walks every registered modifier, applying each to the calling admin alone for a moment and announcing both the on and the off to console and chat, so a misbehaving modifier is named by the last "turning ON" line. Run again to stop. !rolldebug's roll listing is broadcast to every player rather than routed throughPrintToAdminsOnly, which filtered onPermission.PlayerHasPermissionand so reached nobody on a server with no registered admins — exactly where it is needed.- Every roll is written to the console as a
ROLLEDline regardless of!rolldebug, and every activation, slot change and deactivation is bracketed withACTIVATING/ACTIVATED,ADDING SLOTS/ADDED SLOTSandDEACTIVATING/DEACTIVATEDbreadcrumbs. A console ending in an unmatchedACTIVATINGnames the modifier the server was inside when it died.
BUGFIXES
- Wallhack hard-crashed the server on activation, nine times over, always with no managed exception and no stack. Root cause: the parent
GlowUpdated()notifier.CCSPlayerPawndoes not replicatem_Glowas a unit —CGlowPropertycarries a notifier per member — so that call marked a field path the encoder had no entry for, corrupted the entity's dirty-field bookkeeping, and returned cleanly. The fault then surfaced in whatever engine call next walked that state, which is why it appeared to move betweenTeleportandAcceptInputas the surrounding code was reordered while the real culprit never moved. Replaced with per-field notifiers, includingGlowTypeUpdated, which had never once been called. - Glow props were spawned with an empty
CEntityKeyValues, and the engine said so on every spawn (prop_dynamic at (0.000, 0.000, 0.000) has no model name!). Model and origin now go through the spawn keyvalues. - The glow prop rendered as a solid opaque model. Its render colour was
new(1, 255, 255, 255), which againstColor(r, g, b, a)is opaque cyan, where the intent was alpha 1 so only the outline draws. Alpha is also ignored outside a translucent mode, so the prop is nowkRenderTransAlpha. RemoveXrayFromSlotdespawned whatever entity occupied a remembered index with no identity check. CS2 recycles entity indices, so a stale one meant despawning a live pawn, weapon or the bomb. Despawns verify the designer name first, and transmit blocks are lifted before the entity goes.- Deferred prop construction could outlive a deactivation, building props nothing owned or tracked. Construction is driven from the tick loop now, with no long-lived entity references held across frames.
!rolltoggle Wallhackproduced nothing while!memodifier Wallhackworked: a global toggle leavesAssignedSlotsempty,IsAssignedToreads that as "everyone", and skipping holders at build time therefore skipped every target. Props are built for every target; who receives one is decided per viewer and per target.- A second player rolling Wallhack got nothing at all.
SetupXrayruns fromOnEnabled, which by design does not re-run when a slot joins an already-active modifier.OnSlotsAdded/OnSlotsRemovedare implemented, which also covers Mimic and ButterflyEffect handing it out or taking it away mid-round. - Swept
.IsValidacross every native handle in the plugin, then hardened it further.IsValidalone only reports that a wrapper has an address, and an unresolved schema field still has one — all ones — so it returns true and the next read faults at0xFFFFFFFFFFFFFFFF.CSRollUtils.IsUsableHandlechecksIsValidand rejects0and-1. 69 pattern sites across 28 files, plus the unconditional dereferences the sweep could not reach:TeleportPlayerandGameModifierRecallwrotepawn.Collisionwith no check,GameModifierMasterZeusindexedServerControlPointsat hardcoded 0–3 with neither validity nor bounds checking, andTryGetItemDefinitionIndexreadAttributeManager.Itembehind atry/catchthat could only ever have caught a managed exception. - Removed the spin-tick sound logging and the
debugModeparameter carrying it. That sound fires once per spin frame, so it buried the console whenever!rolldebugwas on.
v1.38.0-beta.1 — Custom HUD (test build)
Pre-release from the feature/custom-hud branch, for testing the CS2 Custom HUD. Not a stable release — v1.38.0 proper will be cut when this merges to main.
Requirements
This plugin alone will not show a HUD. All three are needed:
- SwiftlyS2 >= 1.4.6 on the server —
CCSCustomHudLayoutdoes not exist before it - The Panorama Workshop addon delivered to clients — see
tools/HUD_SETUP.md CustomHud.Enabled: trueinconfig.jsonc— it defaults tofalse
With CustomHud.Enabled: false (the default), behaviour is identical to 1.37.1.
FEAT
- CS2 Custom HUD (Panorama) surface built on
CCSCustomHudLayout, off by default - Spin reel + reveal card for rolls, animated client-side via CSS rather than pushed frame-by-frame
- Per-player active-modifier tracker with glyph badges, accent colours and live countdown bars
GetHudTimerhook onGameModifierBase, implemented for Vanish, Recall and Flankerresources/hud/modifiers.jsonc— per-modifier glyph + accent, editable without a rebuild!hudstatus(admin) — reports entity state and draws a test bar, the only way to tell "server side
works" from "clients actually have the addon"tools/validate_hud_contract.py— diffs panel ids and CSS classes against the layout in both
directions, and enforces the Panorama rules resourcecompiler does not check
Install
Extract so CSRoll/ lands in addons/swiftlys2/plugins/, then add the CustomHud block to
config.jsonc. Full setup: tools/HUD_SETUP.md.
v1.37.1
v1.37.0
FEAT
- New modifier — Recall: press Inspect to rewind a few seconds, dragged back along the exact path you walked.
- New modifier — Butterfly Effect: randomizes a modifier that re-rolls every 20s.
- New modifier — Mimic: killing or assisting on an enemy copies one of their modifiers, replacing whatever you took last.
- Weapon Roulette HUD condensed from 4 lines to 2: the "Rolling" label is gone (the flickering name already shows a roll is running) and the countdown now sits in a fixed-width field so it no longer drifts as names change length.
- SwapOnDeath and SuicideBomber added to
RequiresMultiplePlayersPerTeam, so neither is rolled in a 1v1 where they cannot function.
BUGFIXES
- Center-HTML is a single shared surface, so two HUD-drawing modifiers on the same player overwrote each other several times a second instead of stacking → modifiers now publish HUD fragments to a central composer in
ModifierRuntime, which joins every fragment for a player into one panel. - Conditional Invisibility started its fade-out only once the sound cooldown had already expired, and reported INVISIBLE at that same instant — a full fade duration before the player had actually disappeared → the fade is offset to start early so alpha reaches zero exactly as the timer ends, and the gauge is now driven by the live alpha ramp (VISIBLE / FADING / INVISIBLE) instead of predicting from elapsed silence.
- Gauge bars turned green at 50%, reading as "ready" while an ability was still unusable → green now starts at 75%, yellow below (affects Recall, Vanish, Conditional Invisibility, Jetpack fuel).
GetSpawnLocationtook everyinfo_player_terrorist/info_player_counterterroristentity on the map, ignoringSpawnPoint.m_bEnabled— so on maps shipping several mode-specific spawn sets (Wingman alongside the full competitive set) a teleport could land on a competitive-only spawn nowhere near where Wingman plays → spawns are now filtered to the set the current mode has enabled, with a fallback to the unfiltered list. Fixes Teleport On Hit, Teleport On Reload and Revive.
v1.36.0
BUGFIXES
- Fixed random rounds never rolling again after a map change (e.g. Bo3 map switches) until the plugin was reloaded
- Fixed WeaponRoulette never re-rolling weapons after a map change
- Fixed modifier HUDs staying hidden after a map change
- Fixed MasterZeus killing players who were not being aimed at
CHANGED
- MasterZeus now uses a straight hitscan ray instead of an aim cone, so it only hits what you actually aim at
- Removed
MasterZeus.AimConeCosine- no longer used
v1.35.1
FEAT
- Modifier descriptions shown in the reveal popup with a text scramble reveal
- Spectators can also view modifier descriptions
- New modifier Vanish - Inspect Weapon to go invisible and drop all weapons briefly, on a cooldown
- MasterZeus fires a visible lightning bolt from muzzle to impact
- Modifier HUDs no longer fight the reveal popup for the center screen
- Re-roll now plays the spin animation
- Reveal timing fits a 15s freeze time
BUGFIXES
- Fixed Speedhack losing its speed bonus on every jump
- Fixed colour tokens printing literally in chat
- Fixed players occasionally staying permanently invisible after death
- Fixed dead/spectating players never seeing the roll reveal
- Fixed player names injecting HTML into the spectator HUD
- Fixed MasterZeus zapping during the weapon deploy animation
- Fixed
!rolltoggleduring a spin double-activating a modifier - Fixed
!memodifierbypassing Flanker's cooldown - Fixed a crash when disabling the last modifier mid-spin
CHANGED
- Internal modifier names now match translations (11 renamed)
- All 44 descriptions shortened to fit two lines
- Removed Gay Smokes and Surf modifiers
⚠️ BREAKING
Renames change what config.jsonc and admin commands match on:
DisabledModifiersentries with old names silently stop matching- Config sections renamed too - a persisted
"LeadBoots": {...}block is ignored !memodifier LeadBoots->!memodifier HeavyBootsFullInvisibilityis nowVanish
Kamikaze->SuicideBomber, LeadBoots->HeavyBoots, Bhop->BunnyHop, DropOnMiss->Butterfingers, DontMiss->BoomerangBullets, IronBody->SteelBody, PoisonSmoke->PoisonousSmoke, DodgyGrenades->ChineseGrenades, GrenadesOnly->WalkingGrenadier, BiggerExplosions->AtomicExplosions, FlankTeleport->Flanker
If your config.jsonc already has a SpinReveal block, the new timings won't apply until you edit it there.
v1.33.2
BUGFIXES
- WeaponRoulette: reverted
OnGameTick's twoGetAssignedPlayers()calls back to the manualGetAllValidPlayers()+IsAssignedToloop they replaced in v1.31.2. That conversion was applied identically to 14 modifiers with no other reports; per an explicit live report, the rolling animation/landing weapon text stopped rendering in this file specifically after that change. Line-by-line comparison shows the two forms are semantically identical, so the actual mechanism isn't understood — this reverts the one change pinpointed by testing since doing so costs nothing, while the v1.33.1 frame-rate fix (150ms floor per spin frame) stays in place as a separate, independently-reasoned fix for the same visible symptom.
v1.33.1
BUGFIXES
- WeaponRoulette: the "Rolling" animation and landing "Active: weapon" text were not visibly rendering at all (weapon-giving itself was unaffected). Root cause: with the shipped defaults (SpinDurationSeconds=2, SpinFrameCount=30), each frame only had ~67ms on screen — faster than the panel could meaningfully render before being replaced. Now enforces a 150ms floor per frame, widening the effective spin duration for a high frame count instead of slicing it too thin.
- Reverted the reveal banner/spin text back to default size — the larger sizing added in v1.32.0 was too big.
!rollmenu's "Enable/Disable Rolling" list now controls registration eligibility, not live active state. It was wired to the same thing!rolltoggledoes; the actual intent was "can this modifier be rolled/added at all" (the same thing!disablemodifierdoes). AddedEnableModifierByNameas the missing undo — previously disabling a modifier had no way back short of a full plugin reload.!rollmenutext could be permanently truncated. Every menu now scrolls long text into view (ScrollLeftFade) instead of hard-cutting it, and labels were shortened throughout.
FEAT
- Re-added
HtmlGradientto WeaponRoulette's "Rolling" text (gold→orange-red) — previously removed after being blamed for the rendering bug above, which was actually the frame-rate issue. !rollmenunow has real color: chrome (footer/nav marker/guide line) themed via the Design API, modifier names in gold.
v1.33.0
FEAT
New !rollmenu admin command — a SwiftlyS2 menu-based configuration UI:
- Random Rounds on/off toggle (routed through
ToggleRandomRoundsso the existing broadcast announcement still fires) - Modifiers per player submenu with Min/Max sliders, clamped against each other so the pair can never be inverted
- Enable / disable modifiers submenu with one toggle per registered modifier, reflecting live active state; a toggle blocked by an incompatibility snaps back and reports why
- Re-roll this round / Remove all active modifiers buttons
This restores runtime control over MinRandomRounds/MaxRandomRounds, which became config-only in v1.31.0. Menu changes are deliberately runtime-only (no write-back to config.jsonc), stated in the menu itself.
Menus are used here and not for the reveal/spin on purpose: a menu renders into the same panel via the same game event and unlocks no extra styling — it only adds input capture, which is right for a settings screen and wrong for a transient banner (it would hijack movement keys mid-round). Menu text also caps at
fontSize-xl(32px) vs the 64px reachable from raw HTML.
v1.32.0
FEAT
- Reveal banner and spin frames are now sized (
fontSize-ltitle,fontSize-xxlname) instead of default size, so a reveal reads as a reveal. Both share the same constants so the spin doesn't resize when it lands. - Gauges render in a real monospace font (
stratum-regular-mono) with distinct filled/empty glyphs (█/░). This retires the workaround of drawing every cell with the same#glyph and expressing fill purely through colour — which existed only because the default proportional font made a mixed-glyph bar change width as it filled. Shape contrast also makes bars readable without relying on lime-vs-grey. - Optional reveal logo via
SpinReveal.RevealImageUrl, off by default. When empty, no<img>is emitted at all — default behaviour is byte-identical to before and no client makes any outbound request. - Optional screen flash on reveal via
SpinReveal.FadeOnReveal(CCSUsrMsg_Fade), off by default.
BUGFIXES
- Bold was never actually applied anywhere. All 24 uses were
class="fontWeight-bold", but Valve'scsgostyles.cssonly definesfontWeight-Bold/Medium/Normal/Light— capitalised — so every "bold" title in every popup silently rendered at normal weight. Verified by downloading Valve's shipped stylesheet. The lowercase form came from SwiftlyS2's own docs. - Corrected the comment claiming CS2 center HTML is parsed as strict XML and that a bare
<br>breaks the parser. It is a lenient HTML parser — Valve's own shipped strings contain hundreds of bare<br>and several unbalanced<b>tags that render fine.<br/>remains valid so no markup changed, but that constraint does not exist.
The reveal image is evidenced by other live plugins making the same call, but is not verified first-hand — hence off by default.
fontStyle-*andCriticalText, both recommended by SwiftlyS2's docs, exist in no CS2 stylesheet and are deliberately unused.