Skip to content

Releases: LCrew/S2-CSRoll

v1.37.3

Choose a tag to compare

@LCrew LCrew released this 07 Sep 17:06

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 Xray config 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 through PrintToAdminsOnly, which filtered on Permission.PlayerHasPermission and so reached nobody on a server with no registered admins — exactly where it is needed.
  • Every roll is written to the console as a ROLLED line regardless of !rolldebug, and every activation, slot change and deactivation is bracketed with ACTIVATING/ACTIVATED, ADDING SLOTS/ADDED SLOTS and DEACTIVATING/DEACTIVATED breadcrumbs. A console ending in an unmatched ACTIVATING names 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. CCSPlayerPawn does not replicate m_Glow as a unit — CGlowProperty carries 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 between Teleport and AcceptInput as the surrounding code was reordered while the real culprit never moved. Replaced with per-field notifiers, including GlowTypeUpdated, 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 against Color(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 now kRenderTransAlpha.
  • RemoveXrayFromSlot despawned 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 Wallhack produced nothing while !memodifier Wallhack worked: a global toggle leaves AssignedSlots empty, IsAssignedTo reads 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. SetupXray runs from OnEnabled, which by design does not re-run when a slot joins an already-active modifier. OnSlotsAdded/OnSlotsRemoved are implemented, which also covers Mimic and ButterflyEffect handing it out or taking it away mid-round.
  • Swept .IsValid across every native handle in the plugin, then hardened it further. IsValid alone 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 at 0xFFFFFFFFFFFFFFFF. CSRollUtils.IsUsableHandle checks IsValid and rejects 0 and -1. 69 pattern sites across 28 files, plus the unconditional dereferences the sweep could not reach: TeleportPlayer and GameModifierRecall wrote pawn.Collision with no check, GameModifierMasterZeus indexed ServerControlPoints at hardcoded 0–3 with neither validity nor bounds checking, and TryGetItemDefinitionIndex read AttributeManager.Item behind a try/catch that could only ever have caught a managed exception.
  • Removed the spin-tick sound logging and the debugMode parameter carrying it. That sound fires once per spin frame, so it buried the console whenever !rolldebug was on.

v1.38.0-beta.1 — Custom HUD (test build)

Choose a tag to compare

@LCrew LCrew released this 28 Aug 21:58

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:

  1. SwiftlyS2 >= 1.4.6 on the server — CCSCustomHudLayout does not exist before it
  2. The Panorama Workshop addon delivered to clients — see tools/HUD_SETUP.md
  3. CustomHud.Enabled: true in config.jsonc — it defaults to false

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
  • GetHudTimer hook on GameModifierBase, implemented for Vanish, Recall and Flanker
  • resources/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

Choose a tag to compare

@LCrew LCrew released this 25 Aug 12:20

Version bump only. Adds an empty test.txt at the repo root; no gameplay, config or modifier behaviour changed from v1.37.0.

v1.37.0

Choose a tag to compare

@LCrew LCrew released this 25 Aug 10:28

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).
  • GetSpawnLocation took every info_player_terrorist/info_player_counterterrorist entity on the map, ignoring SpawnPoint.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

Choose a tag to compare

@LCrew LCrew released this 25 Aug 06:38

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

Choose a tag to compare

@LCrew LCrew released this 20 Aug 12:56

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 !rolltoggle during a spin double-activating a modifier
  • Fixed !memodifier bypassing 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:

  • DisabledModifiers entries with old names silently stop matching
  • Config sections renamed too - a persisted "LeadBoots": {...} block is ignored
  • !memodifier LeadBoots -> !memodifier HeavyBoots
  • FullInvisibility is now Vanish

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

Choose a tag to compare

@LCrew LCrew released this 18 Aug 13:23

BUGFIXES

  • WeaponRoulette: reverted OnGameTick's two GetAssignedPlayers() calls back to the manual GetAllValidPlayers()+IsAssignedTo loop 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

Choose a tag to compare

@LCrew LCrew released this 18 Aug 13:10

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 !rolltoggle does; the actual intent was "can this modifier be rolled/added at all" (the same thing !disablemodifier does). Added EnableModifierByName as the missing undo — previously disabling a modifier had no way back short of a full plugin reload.
  • !rollmenu text 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 HtmlGradient to WeaponRoulette's "Rolling" text (gold→orange-red) — previously removed after being blamed for the rendering bug above, which was actually the frame-rate issue.
  • !rollmenu now has real color: chrome (footer/nav marker/guide line) themed via the Design API, modifier names in gold.

v1.33.0

Choose a tag to compare

@LCrew LCrew released this 18 Aug 12:10

FEAT

New !rollmenu admin command — a SwiftlyS2 menu-based configuration UI:

  • Random Rounds on/off toggle (routed through ToggleRandomRounds so 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

Choose a tag to compare

@LCrew LCrew released this 18 Aug 11:29

FEAT

  • Reveal banner and spin frames are now sized (fontSize-l title, fontSize-xxl name) 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's csgostyles.css only defines fontWeight-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-* and CriticalText, both recommended by SwiftlyS2's docs, exist in no CS2 stylesheet and are deliberately unused.