Fixes a Counter-Strike 2 server crash caused by beam entities whose parent has been removed.
BeamCrashFix is a small, passive ModSharp plugin that stops a server crash: when a CBeam (a beam/laser
entity) is parented to another entity that then gets removed, the beam is left with a dangling parent — a parent
scene node whose owner entity is gone. The next time the engine computes that beam's world position, it dereferences
the missing owner and the server crashes. This plugin detours the responsible engine function and, when it detects
that dangling state, safely skips the crashing computation. No commands, no config — install it and the crash stops.
Copy the build output into your ModSharp install (<sharp> = your sharp directory):
| From | To |
|---|---|
.build/modules/BeamCrashFix.Core/ |
<sharp>/modules/BeamCrashFix.Core/ |
.build/modules/BeamCrashFix.Core/.assets/gamedata/beamcrashfix.games.jsonc |
<sharp>/gamedata/beamcrashfix.games.jsonc |
Restart the server (or change map) to load. There is nothing to configure.
None beyond the base ModSharp framework — the plugin only uses ISharedSystem (the hook manager, gamedata, and
entity access). No other plugins, no database, no shared contracts.
The crash is the same on both platforms, but the fixable code differs by compiler, so the plugin does the right thing for each and picks the correct one at load:
- Windows — the two
CBeamabs-position setters (SetAbsStartPos/SetAbsEndPos) exist as standalone functions. The plugin detours both and, whenGetSceneNode()?.GetParent()?.GetOwner()is null (the dangling state), writes the position directly instead of running the transform that would crash. This is the original fix authored by Kxnrl. - Linux — GCC inlines those two setters, so there is no standalone function to hook. The crash itself,
however, lives in one generic function:
CGameSceneNode's parent-relative abs-transform combine (the point where a parented node's world transform is computed). The plugin detours that one function and, when the node's or its parent's owner pointer is null, skips the recompute. The signature was reverse-engineered fromlibserver.so.
The guard is fail-safe either way: it only triggers when an owner pointer is null, which is an always-invalid, being-torn-down state — it can never fire for a live, valid entity, and the hook never allocates or throws. Note that the Linux hook sits on a generic transform (it runs for any parented entity, not only beams); the guard's null check means it is still a no-op for everything except the crashing case.
Signatures live in beamcrashfix.games.jsonc (per-platform, resolved lazily for the running OS). If a future CS2
update shifts a signature, the hook simply fails to install and logs it — it never mis-resolves.
dotnet build -c ReleaseOutputs .build/modules/BeamCrashFix.Core/BeamCrashFix.dll and the bundled beamcrashfix.games.jsonc. Requires the
.NET 10 SDK.
- Kxnrl — the original Windows crash-fix and the Windows signatures. Runs his servers on Windows, so the Linux side was never checked.
- yappershq — reverse-engineered the Linux crash site + signature and packaged the standalone cross-platform plugin.
Released under the GNU AGPL-3.0, matching the ModSharp module ecosystem this is built on.
Made with ❤️ by yappershq
⭐ Star this repo if you find it useful!