Welcome under the hood. This document details the technical architecture, zero-alloc network protocol, and compilation guidelines used in the Shrapnel Overhaul Mod (v1.0.0).
If you are a modder or a C# developer, this guide explains how the mod bypasses Unity's standard limitations to achieve massive scale and perfect multiplayer synchronization under Scav game version 6.1.
The mod replaces standard Unity Instantiate/Destroy calls with a custom engine to achieve zero-GC (Garbage Collection) allocations during steady-state gameplay.
-
Flat-Array Ring Buffer: Pre-allocates up to 8,500 custom particle slots (
AshParticlePooled). UsesSetActive(false)for recycling. -
Frame-Staggered Physics: Particles simulate quadratic drag (
$F \propto v^2$ ) and thermal lift. Expensive Perlin-noise turbulence is staggered (calculated every 3rd frame with a$\times3$ multiplier) to drastically reduce CPU overhead. -
GPU-Batched Sparks: Small, fast sparks bypass GameObjects entirely. They are routed to Unity's
ParticleSystem(ParticlePoolManager) usingRenderMode.Stretch. This allows thousands of sparks to render with near-zero CPU cost. -
Shader Self-Healing: Vanilla Scav has a bug where chunk unloading corrupts
Shader.Findreferences. The mod runs a background routine (HealMaterials) every 60 frames to detect and repair broken materials on the fly.
Unity JIT occasionally ignores Harmony Transpilers. To ensure 100% reliable shot detection without breaking the game:
- Hybrid Polling: Instead of risky IL injection, the mod uses lightweight
MonoBehaviourpolling to detect rising edges onGunScript.muzzleParticle.isEmittingandTurretScript.didShoot. - Dynamic Power Scaling: Weapon power is extracted via Reflection:
Power = structureDamage * (1 + knockBack/10) * max(1, shotsPerFire)(v1.0.0 fix: Clamped inputs prevent unboxing exceptions, unboxing reflected fields is managed via type-safe converters).
The mod features a custom, server-authoritative network protocol built via Reflection into Unity.Netcode. It does not require the MP mod to compile or run in singleplayer.
Calling reflected MethodInfo.Invoke() inside hot loops (processing hundreds of shards every frame) introduces severe CPU overhead and generates massive GC garbage because parameters must be boxed into object[] arrays.
To solve this, ShrapnelNetSync compiles fast delegate wrappers at startup using LINQ Expressions:
- Write/Read Delegates:
Action<object, T>andFunc<object, T>are generated forFastBufferWriter.WriteValueSafe<T>andFastBufferReader.ReadValueSafe<T>. - Native Performance: These delegates unbox the boxed writer/reader struct on the heap, and call the JIT-compiled generic methods directly. This matches native C# execution speeds with absolute zero GC allocations on every network tick.
Previous versions sent position updates 10 times a second for every flying shard. Protocol v4 deletes this entirely.
MSG_SPAWN(Reliable, Batched): Server sends initial vectors (Position, Velocity, Rotation, Type, Weight, Heat).- Real Client Physics: Clients create a real
Rigidbody2DandCircleCollider2D. The local Unity physics engine handles bouncing and ricochets perfectly. - Damage Gating: On the client,
IsServerAuthoritative = falseis set. The FSM runs, but collisions with limbs/entities are silently ignored to prevent phantom double-damage. MSG_STATE(Rest Correction): When a shard stops moving on the server, it sends a finalMSG_STATE. The client smoothly snaps the shard to this authoritative resting position (ForceToState).MSG_DESTROY: Triggers a 150ms visual fade-out on the client to hide any slight positional desync before deletion.
Embedded stuck shards now track the exact surface normal vector they hit (_lastHitNormal). When checking if they should fall down (CheckSupportAndFall), they evaluate the block opposite to the normal. This ensures wall, ceiling, and floor-stuck shards fall immediately when their supporting block is destroyed, preventing "floating shards" bugs.
Instead of a slow
To build the project under game version 6.1 without committing your absolute system paths or manually copying game DLL files, configure your local environment:
Create a file named LocalDev.user in the project root directory (next to ScavShrapnelMod.csproj). This file is ignored by Git. Paste the following XML and set your game folder path:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- Adjust this path to point to your local Scav v6.1 installation -->
<GameDir>D:\SteamLibrary\steamapps\common\Casualties Unknown Demo\</GameDir>
</PropertyGroup>
</Project>Directory.Build.propsimports yourLocalDev.userearly.- It calculates
ManagedDirdynamically. ScavShrapnelMod.csprojdetermines if the Assemblies exist in your game'sCasualtiesUnknown_Data/Managed/directory.- If they do, it compiles directly against your local game files. If not, it falls back to the
Libraries/directory.
Open the project in Visual Studio Code.
- Press
Ctrl + Shift + B(or select thebuildtask) to compile and auto-deploy the DLL into your BepInEx plugins folder. - Run the
build-and-launchcompound task to compile, deploy, and launch the game executable automatically.