diff --git a/Directory.Build.props b/Directory.Build.props
index 9e53fec..71ab1b2 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,6 +5,6 @@
enable
latest
true
- 1.0.3
+ 1.0.4
diff --git a/Outnumbered/Engine/RespawnFix.cs b/Outnumbered/Engine/RespawnFix.cs
new file mode 100644
index 0000000..a9ddde8
--- /dev/null
+++ b/Outnumbered/Engine/RespawnFix.cs
@@ -0,0 +1,23 @@
+using System;
+using CounterStrikeSharp.API.Core;
+using CounterStrikeSharp.API.Modules.Memory;
+
+namespace Outnumbered.Engine;
+
+// Workaround, pending a CounterStrikeSharp release carrying the upstream fix: CSSharp's
+// CCSPlayerController.Respawn() calls SetPawn(PlayerPawn.Value), which faults inside the engine's
+// network-state change code when the pawn is DEAD — the usual respawn case — on the current CS2
+// build (a bot respawned right after we kill it took the crash). This mirrors CSSharp's Respawn()
+// but only re-attaches a LIVE pawn; the CCSPlayerController_Respawn vfunc re-creates the pawn on
+// respawn regardless. Revert every SafeRespawn() call back to .Respawn() once the fixed package ships.
+internal static class RespawnFix
+{
+ public static void SafeRespawn(this CCSPlayerController controller)
+ {
+ if (controller is not { IsValid: true }) return;
+ var pawn = controller.PlayerPawn.Value;
+ if (pawn == null) return;
+ if (pawn is { IsValid: true, Health: > 0 }) controller.SetPawn(pawn);
+ VirtualFunction.CreateVoid(controller.Handle, GameData.GetOffset("CCSPlayerController_Respawn"))(controller.Handle);
+ }
+}
diff --git a/Outnumbered/Outnumbered.cs b/Outnumbered/Outnumbered.cs
index dc8fe2d..e5c18a0 100644
--- a/Outnumbered/Outnumbered.cs
+++ b/Outnumbered/Outnumbered.cs
@@ -10,7 +10,7 @@ namespace Outnumbered;
public sealed partial class OutnumberedPlugin : BasePlugin, IPluginConfig
{
public override string ModuleName => "Outnumbered";
- public override string ModuleVersion => "1.0.3-modes";
+ public override string ModuleVersion => "1.0.4-modes";
public override string ModuleAuthor => "snake";
public override string ModuleDescription => "Players-vs-bots RPG / perk mod.";
diff --git a/Outnumbered/Survival.cs b/Outnumbered/Survival.cs
index c44d965..cb5829e 100644
--- a/Outnumbered/Survival.cs
+++ b/Outnumbered/Survival.cs
@@ -657,7 +657,7 @@ public sealed class SurvivalDriver : IMatchDriver, IDraftDriver
// Respawn a pool bot, then (deferred a frame so the spawn settles) teleport it to a spawn point away from the squad.
private void DirectedBotSpawn(CCSPlayerController bot)
{
- bot.Respawn();
+ bot.SafeRespawn(); // CSSharp's Respawn() faults in SetPawn on a dead controller (see RespawnFix)
if (_spawnPoints.Count == 0 || _p.Config.Survival.MinSpawnDistance <= 0) return; // no candidates / disabled -> plain respawn
int slot = bot.Slot;
OutnumberedPlugin.NextFrameForSlot(slot, b =>
@@ -923,7 +923,7 @@ public sealed partial class OutnumberedPlugin
if (p is not { IsValid: true } || p.IsBot || p.PawnIsAlive || p.Team != CsTeam.CounterTerrorist) return;
if (p.AuthorizedSteamID?.SteamId64 is not { } sid) return;
var dest = teleportTo is { } t ? new Vector(t.X, t.Y, t.Z) : null;
- p.Respawn();
+ p.SafeRespawn(); // CSSharp's Respawn() faults in SetPawn on a dead controller (see RespawnFix)
NextFrameForSlot(p.Slot, sid, pl =>
{
var pd = PdOf(pl); var pawn = pl.PlayerPawn.Value;
diff --git a/Outnumbered/outnumbered.csproj b/Outnumbered/outnumbered.csproj
index 768d96b..f768397 100644
--- a/Outnumbered/outnumbered.csproj
+++ b/Outnumbered/outnumbered.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/README.md b/README.md
index 6a43d6b..b0ea153 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ servers.
## Requirements
- A CS2 dedicated server with **Metamod:Source** and **CounterStrikeSharp** installed
- (compiled against CounterStrikeSharp API **1.0.369**; use a matching or newer server build).
+ (compiled against CounterStrikeSharp API **1.0.370**; use a matching or newer server build).
- **.NET 10** — provided by the CounterStrikeSharp runtime; only needed as an SDK if you build from source.
- **Linux** — the damage path, native grenade spawning, and launch-flag parsing are Linux-specific.
- A database: **PostgreSQL** for production (recommended, required for multi-instance), or **SQLite** for single-server/dev.