SpongeMods-SpongePEAKOptimized icon

SpongePEAKOptimized

Fixes and optimizations in one mod, each individually toggleable. Includes disconnected-player persistence and rejoin handling.

Last updated 7 hours ago
Total downloads 61
Total rating 0 
Categories
Dependency string SpongeMods-SpongePEAKOptimized-1.0.0
Dependants 1 other package depends on this package

This mod requires the following mods to function

BepInEx-BepInExPack_PEAK-5.4.75301 icon
BepInEx-BepInExPack_PEAK

BepInEx pack for PEAK. Preconfigured and ready to use.

Preferred version: 5.4.75301
SpongeMods-SpongePEAKCore-1.0.0 icon
SpongeMods-SpongePEAKCore

Shared foundation for Sponge PEAK mods: logging, config, reflection caching and patch hosting. Not a standalone mod.

Preferred version: 1.0.0
SpongeMods-SpongePEAKLib-1.0.0 icon
SpongeMods-SpongePEAKLib

Modding API for PEAK, and a Mods tab in the game's own settings menu for toggling any installed mod's features.

Preferred version: 1.0.0

README

SpongePEAKOptimized

Fixes and performance work for PEAK, bundled into one mod with a toggle for every feature.

Instead of installing eight single-purpose mods that each patch the game separately, this is one plugin where overlapping behaviour is resolved once and deliberately.

Features

Every feature has its own setting in BepInEx/config/com.sponge.peakoptimized.cfg, so if one misbehaves you can switch off just that one.

Feature Default What it does
AdaptiveNetwork on Measures each player's connection and lowers the room's send rate when someone is struggling, so weak connections stop rubber-banding. Host decides, clients match.
AudioFix on Stops audio dropouts by parking silent looping sounds and prioritising voice and nearby audio.
CarryDisconnectedPlayers on Lets you pick up and carry teammates who disconnected while alive, and marks them (Disconnected). Ghosts cannot be carried.
DecorationCulling on Hides small decorative meshes beyond a distance, spreading the work across frames.
DistanceCulling on Skips dynamic-bone secondary motion beyond a distance from the camera, and caps its update rate.
GrassAllocations on Reuses one MaterialPropertyBlock for grass instead of allocating a new one every frame.
GrassFrustumCulling on Skips grass chunks outside the camera frustum. Grass casts no shadows, so this cannot change what you see.
KeepDisconnectedPlayersInWorld on Keeps a disconnected player's character alive and simulated until they rejoin, die, or the timeout expires. Room settings are applied when you host; every client tracks who is away.
LateJoinFix on Warps players who join mid-run to the party member furthest from the summit, then revives them.
LightSampleCache on Caches baked light volume samples, which cost a CPU 3D-texture readback per call.
LobbyJoinFix on Retired. PEAK now defers lobby invites until the session is connected, so this is no longer needed.
NullGuards on Stops two vanilla per-frame exceptions: pocket updates before a player exists, and particle culling with no observed character.
PerformanceLOD on Throttles physics updates for distant characters and avoids redundant rigidbody writes.
PhysicsThrottle on Caches wind shelter raycasts and removes the per-search scene scan from bot vision.
PlatformTuning on Applies the few engine settings that genuinely differ under Proton/Wine versus native Windows. Does nothing on Windows unless explicitly configured.
ProximityGating on Skips per-step updates for traps and ambient particle spawners with no player nearby.
ReconnectCatchup on Warps returning players to the party member furthest from the summit instead of the level start.
RejoinVoiceFix on Resets Photon Voice when leaving a game so voice chat works in the next lobby.
RestoreRejoinPosition on Returns a rejoining player to where they disconnected, if the gloom has not risen past it.
RopeShooterFix on Fixes the vanilla rope cannon refusing to fire: a single frame of lost footing or aim wobble cancelled the whole cast. Also stops spare cannons raycasting every frame.
SoftDependencyFix on Keeps partially-loaded assemblies usable, so a mod with a missing optional dependency does not hide unrelated console commands.
Telemetry off Shows frame time and what each optimization is doing, so the effect can be measured.
VineClimbFix on Stops rubber-banding when climbing vines and chains.
VisualQuality on Trades visual fidelity for frames: LOD bias, shadow bias and directional shadow tuning.
ZeroAllocHotPaths on Removes per-frame allocations from falling-rock physics and player proximity checks, reducing GC micro-stutter.

Disconnected players

The headline feature. Normally a player who drops has their character deleted instantly, so you cannot help them.

With this installed by the host, a disconnected player's character stays in the world: afflictions keep ticking, hazards still affect them, and teammates can pick them up and carry them to safety even though they are not incapacitated. When they rejoin they take their character back. If they die while away they become a normal ghost, and ghosts cannot be carried.

Two things worth knowing:

  • The host decides. Room settings come from whoever creates the lobby, so if the host has this mod, every player sees the behaviour, mod or not. If the host does not, it is inactive regardless of what clients have installed.
  • An absent player holds a slot until the timeout expires (default 5 minutes, configurable). That is the cost of keeping their character alive.

Compatibility

This mod covers the same ground as several existing mods. Running both means two mods acting on the same thing, so disable these if you have them:

Mod Overlap found
Cryo-PEAK_VineFix patches the same method, CharacterVineClimbing.RPCA_SyncVineClimb
KinTheInfinite-BetterFPS patches the same FixedUpdate methods on character physics
IceMods-PeakLobbyJoinFix targets OnLobbyJoinRequested; see the note below
Sapphire009-LateJoinFix sends the same WarpPlayerRPC and RPCA_ReviveAtPosition on join
Ayzax-Reconnect_Catchup sends WarpPlayerRPC on join, and warps every joiner
PatchNote-PeakAudioFix same audio-source prioritisation and pausing behaviour
PatchNote-RejoinVoiceFix both reset the Photon Voice client when leaving a game
PEAKModding-SoftDependencyFix same ReflectionUtility type-loading fix
reis637-PeakOptimizer patches the same ShakyRock, DynamicBone and PlayerHandler hot paths
LIGHTNING_X-CubeX partial: its bundled "Better FPS" patches the same CharacterRagdoll and CenterOfMass methods as PerformanceLOD. The rest of CubeX (its menu and tools) does not conflict. Disable CubeX's Better FPS options, or turn off PerformanceLOD here.

How this was determined: by comparing the game methods and Photon RPCs each mod touches against the ones this mod patches, using the installed binaries. The first three are direct patch collisions on identical methods. The rest are behavioural: different mechanism, same effect on the same game state.

The worst pairing is LateJoinFix + Reconnect_Catchup, which conflict with each other even without this mod: both warp a joining player, so two warps race for the same character. Resolving that is a large part of why this bundle exists. Here a single arbiter classifies each join once and dispatches to exactly one handler.

Not tested running side by side with these mods in a live session; the overlap above is from binary and behavioural comparison, which is why the guidance is to disable rather than to expect a specific failure.

A note on LobbyJoinFix

Investigated and deliberately not implemented. PEAK's own GameBooter now defers a pending invite until ConnectedAndReady:

if (!NetCode.Session.IsConnectedAndReady)
    NetCode.ConnectionEvents.ConnectedAndReady += JoinLobbyAfterRelayReady;
else if (NetCode.Matchmaking.HasPendingInvite)
    NetCode.Matchmaking.ConsumePendingJoin(andJoin: true);

That is the same defer-and-replay the mod added, so reimplementing it would race the game's own logic. IceMods-PeakLobbyJoinFix also targets SteamLobbyHandler.OnLobbyJoinRequested, which has since moved to Peak.Network.SteamLobbyAPI.

Prior art

Independent implementation, written against PEAK's own assemblies. The problems it solves were identified by earlier mods listed above, and this bundle exists because those solutions overlapped and sometimes fought each other.

Differences worth noting:

  • One arbiter decides how a joining player is handled, so late-join, position-restore and catch-up cannot race.
  • Per-feature toggles with failure isolation: a feature whose patches fail to bind is reported by name rather than silently counted as working.
  • SoftDependencyFix is an IL transpiler over a single Assembly.GetTypes() call, recovering the types that did load instead of discarding the whole assembly.
  • Disconnected-player persistence, carrying disconnected teammates, rejoin position restore and the mod handshake have no upstream equivalent.

Adaptive networking

If one player is on a weak connection, everyone feels it as rubber-banding and characters running in place. This measures each player's connection and adapts the room to suit the weakest one.

  • No extra traffic. It reads latency, jitter, packet loss and send-backlog counters that Photon already maintains. It does not send ping packets, which would burden exactly the connections that can least afford them.
  • Jitter matters more than ping. A steady 250ms connection plays fine; a 90ms one that spikes to 400ms is what actually causes rubber-banding, and that is what this reacts to.
  • The host decides one rate and everyone matches it, because the game interpolates other players against the local send rate. A client changing its own rate would cause the very stutter this removes.
  • Nothing happens if nobody is struggling, and players without the mod are never counted as bad, so they cannot drag the room down.
  • Everyone in the lobby needs the mod for the rate to change. The game interpolates other players against the local send rate, so a vanilla player left at 30Hz while the room sends slower would stutter. If anyone lacks it, the room stays at vanilla 30Hz.

Works for satellite, Starlink, tethered mobile, congested Wi-Fi and long-haul connections.

Turn on Telemetry (F6) to see your own latency and jitter, the room's current send rate, and each player's connection quality, so you can tell whose link is actually struggling.

Proton and Linux

PEAK is a Windows build, so under Proton it reports itself as Windows and ordinary platform checks cannot tell the difference. This mod detects the real situation (via the wine_get_version marker that Wine exports and Windows does not) and applies the few settings that genuinely differ:

  • Background loading priority is raised under Proton only, so more DXVK shader-pipeline compilation happens during loading screens instead of stuttering during play.
  • Everything else is unchanged, because the rest of the optimizations remove work from hot paths, which helps identically on every platform.

On native Windows this does nothing unless you configure it. The detected platform is written to the log, which is worth including in any performance report.

Requirements

BepInEx, SpongePEAKCore and SpongePEAKLib. r2modman installs these automatically.

Performance features absorbed from PeakOptimizer

Feature Default What it does
Light sample cache on The baked light volume is sampled with a CPU texture readback, every frame, per speaking player and per character in a wind zone. Cached.
Physics throttle on Wind shelter raycasts are cached (terrain does not move), and bot vision no longer scans the whole scene each search.
Decoration culling on Small scenery stops drawing at distance. Only small meshes, and only the draw is disabled, so nothing you can stand on ever disappears.
Grass allocations on Grass allocated a property block every frame; now reuses one.
Grass frustum culling on Grass behind the camera was still drawn. It casts no shadows, so skipping it cannot change the image.
Proximity gating on Citadel traps stop raycasting every physics step when nobody is near them.
Null guards on Fixes two vanilla exceptions thrown every frame: pocket updates before a player exists, and particle culling in menus.
Visual quality off LOD and shadow tuning. Trades looks for frames, so opt-in. PEAK_Visuals is better at this.
Telemetry off Frame time and cull counters, so the above can be measured rather than assumed.

Conflicts with reis637-PeakOptimizer. Both patch the same methods. Run one or the other. Its experimental GPU occlusion culler is not reimplemented here: it is disabled by default even in that mod, and marked use-at-your-own-risk. Run PeakOptimizer if you specifically want it.

License

Free to use, stream, and include in modpacks. No attribution needed for any of that.

Attribution is only required if you decompile it and reuse the code. Please do not reupload it elsewhere or sell it.

Full terms in LICENSE.

Keybinds

Key Opens Setting
F8 Telemetry overlay (feature is off by default) TelemetryToggleKey

All rebindable, in the config file or in Settings > Mods.

Configuration

Every setting is in BepInEx/config/com.sponge.peakoptimized.cfg, or in the game's own Settings > Mods tab.

AudioFix

Setting Type Default What it does
ScanInterval number 0.5 Seconds between audio source scans. Lower reacts faster but costs more CPU; FindObjectsByType is not cheap.

Diagnostics

Setting Type Default What it does
TelemetryInterval number 0.5 Seconds between readout refreshes.
TelemetryToggleKey key F8 Key that shows or hides the readout while the feature is enabled.
Telemetry on/off false Shows frame time and what each optimization is doing, so the effect can be measured.

Fixes

Setting Type Default What it does
VineClimbFix on/off true Stops rubber-banding when climbing vines and chains.
AudioFix on/off true Stops audio dropouts by parking silent looping sounds and prioritising voice and nearby audio.
RejoinVoiceFix on/off true Resets Photon Voice when leaving a game so voice chat works in the next lobby.
LobbyJoinFix on/off true Retired. PEAK now defers lobby invites until the session is connected, so this is no longer needed.
SoftDependencyFix on/off true Keeps partially-loaded assemblies usable, so a mod with a missing optional dependency does not hide unrelated console commands.
RopeShooterFix on/off true Fixes the vanilla rope cannon refusing to fire: a single frame of lost footing or aim wobble cancelled the whole cast. Also stops spare cannons raycasting every frame. (replaces (vanilla bug))
NullGuards on/off true Stops two vanilla per-frame exceptions: pocket updates before a player exists, and particle culling with no observed character.

Network

Setting Type Default What it does
AdaptSendRate on/off true Lower the room's network send rate when a player's connection cannot keep up. Host decides; clients follow the host so everyone's interpolation matches. Off means always use the vanilla 30Hz.
SampleIntervalSeconds number 5 How often to read connection quality. This costs no packets: it reads counters Photon already maintains, so a short interval is cheap and reacts sooner.
MinimumSerializationRate number 15 Lowest serialisation rate the host may drop to, in Hz. Vanilla is 30. Below about 15 the game's own interpolation starts to look obviously soft.
LogConnectionQuality on/off true Log connection tier changes and rate adjustments. Useful for diagnosing whose connection is actually causing trouble.
AdaptiveNetwork on/off true Measures each player's connection and lowers the room's send rate when someone is struggling, so weak connections stop rubber-banding. Host decides, clients match. (replaces )

Performance

Setting Type Default What it does
NearUpdateRate number 60 Physics updates per second for nearby remote characters. 0 disables their updates entirely.
MediumUpdateRate number 30 Updates per second for characters past MediumDistance.
FarUpdateRate number 10 Updates per second for characters past FarDistance.
MediumDistance number 30 Distance (metres) at which a character drops to MediumUpdateRate.
FarDistance number 60 Distance (metres) at which a character drops to FarUpdateRate.
ZeroAlloc_ShakyRock on/off true Replaces allocating physics queries and leftover debug logging in falling-rock updates.
ZeroAlloc_ProximityChecks on/off true Uses squared-distance comparison instead of Vector3.Distance for player proximity checks.
CullDistantDynamicBones on/off true Skips dynamic-bone updates beyond DynamicBoneDistance from the camera. Purely visual.
DynamicBoneDistance number 40 Metres from the camera beyond which dynamic bones stop updating. Lower is faster; too low shows stiff foliage nearby.
CapDynamicBoneUpdateRate on/off true Caps dynamic-bone update rate at 30 Hz instead of the default 60.
LightSampleGridSize number 1 World-space cell size for cached light samples, in metres. Smaller is more accurate and hits the cache less often.
LightSampleCacheEntries number 4096 Maximum cached samples. The cache clears wholesale when full, which is cheaper than tracking per-entry age for a value this cheap to recompute.
WindShelterInterval number 0.1 Seconds between wind shelter raycasts per character. Terrain does not move, so this only needs to keep up with the player.
OptimizeBotVision on/off true Replaces the scene scan in bot vision with the list the game already maintains.
DecorationCullDistance number 90 Distance beyond which small decorations stop being drawn.
DecorationMaxExtent number 1.5 Largest bounds extent, in metres, that counts as a decoration. Anything bigger is left alone, so climbable geometry is never hidden.
DecorationChecksPerFrame number 64 How many decorations to test each frame. Lower spreads the cost further.
TrapActiveDistance number 80 Distance within which traps keep updating. Well beyond their own reach, so this cannot stop a trap that could actually hit someone.
ReportPlatform on/off true Log which platform was detected and the evidence for it. Useful when reporting a performance problem, since Proton and Windows behave differently.
ProtonBackgroundLoadingPriority number 2 Proton/Wine only. How much time per frame the engine may spend on background loading, which is when DXVK compiles shader pipelines. 0 leaves the engine default, 1 is low, 2 is normal, 3 is high. Higher trades slightly longer loads for fewer first-encounter stutters. Ignored on native Windows.
MaxQueuedFrames number -1 Frames the CPU may queue ahead of the GPU. -1 leaves the engine default (2). Setting 1 can reduce input latency under DXVK, at some risk to throughput. Applies on any platform, because it is a preference rather than a fix.
PerformanceLOD on/off true Throttles physics updates for distant characters and avoids redundant rigidbody writes.
ZeroAllocHotPaths on/off true Removes per-frame allocations from falling-rock physics and player proximity checks, reducing GC micro-stutter. (replaces reis637-PeakOptimizer (partial))
DistanceCulling on/off true Skips dynamic-bone secondary motion beyond a distance from the camera, and caps its update rate. (replaces reis637-PeakOptimizer (partial))
LightSampleCache on/off true Caches baked light volume samples, which cost a CPU 3D-texture readback per call.
PhysicsThrottle on/off true Caches wind shelter raycasts and removes the per-search scene scan from bot vision.
DecorationCulling on/off true Hides small decorative meshes beyond a distance, spreading the work across frames.
GrassAllocations on/off true Reuses one MaterialPropertyBlock for grass instead of allocating a new one every frame.
GrassFrustumCulling on/off true Skips grass chunks outside the camera frustum. Grass casts no shadows, so this cannot change what you see.
ProximityGating on/off true Skips per-step updates for traps and ambient particle spawners with no player nearby.
PlatformTuning on/off true Applies the few engine settings that genuinely differ under Proton/Wine versus native Windows. Does nothing on Windows unless explicitly configured. (replaces )

Rejoin

Setting Type Default What it does
LateJoin_AfterWarpDelay number 2 Seconds between warping a late joiner and reviving them. Too short and the revive can land at their pre-warp position.
LateJoin_WarpForwardOffset number 2 How far (world forward) to offset the warp from the target player, so the two do not spawn inside each other.
LateJoin_ReviveHeightOffset number 3 How far above the target player to revive the late joiner.
CatchUp_HeightOffset number 1 Metres above the target player's head to place a returning player.
Restore_FogSafetyMargin number 10 Metres of clearance required between the gloom and a player's saved position before restoring them there.
Restore_MaxAwayTimeSeconds number 300 Longest disconnect, in seconds, that still restores the original position. Past this they are caught up to the party instead.
DisconnectedPlayerTimeoutSeconds number 300 How long a disconnected player's character stays in the world before Photon reclaims it. They occupy a player slot for this whole period, so keep it in line with your player cap. Only applies to lobbies you host.
LateJoinFix on/off true Warps players who join mid-run to the party member furthest from the summit, then revives them.
RestoreRejoinPosition on/off true Returns a rejoining player to where they disconnected, if the gloom has not risen past it. (replaces (new behaviour))
ReconnectCatchup on/off true Warps returning players to the party member furthest from the summit instead of the level start.
CarryDisconnectedPlayers on/off true Lets you pick up and carry teammates who disconnected while alive, and marks them (Disconnected). Ghosts cannot be carried. (replaces (new behaviour))
KeepDisconnectedPlayersInWorld on/off true Keeps a disconnected player's character alive and simulated until they rejoin, die, or the timeout expires. Room settings are applied when you host; every client tracks who is away. (replaces (new behaviour))

Visuals

Setting Type Default What it does
LodBias number 1 Level-of-detail bias. Below 1 swaps to simpler meshes sooner: more frames, more visible popping. 1.0 leaves it alone.
TuneShadowBias on/off true Adjusts directional light shadow bias to reduce acne, which allows a lower shadow distance without obvious artefacts.
ShadowDistance number 0 Maximum shadow draw distance in metres. 0 leaves the game's value alone.
VisualQuality on/off true Trades visual fidelity for frames: LOD bias, shadow bias and directional shadow tuning.