You are viewing a potentially older version of this package. View all versions.
SpongeMods-SpongePEAKQOL-1.0.0 icon

SpongePEAKQOL

Quality-of-life improvements for PEAK, each individually toggleable.

Date uploaded 7 hours ago
Version 1.0.0
Download link SpongeMods-SpongePEAKQOL-1.0.0.zip
Downloads 41
Dependency string SpongeMods-SpongePEAKQOL-1.0.0

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

SpongePEAKQOL

Quality-of-life improvements for PEAK, bundled with a toggle for every feature.

Sibling to SpongePEAKOptimized, deliberately kept separate. That mod is for fixes and performance, things that make the game work as intended. This one is for convenience, things that change behaviour because it is inconvenient rather than broken. Keeping them apart means you do not have to accept preference changes to get bug fixes.

Features

Every feature has its own setting in BepInEx/config/com.sponge.peakqol.cfg.

Feature Default What it does
BackpacksForEveryone on Gives every player a backpack when a run starts, if they do not already have one. Host only.
CatchFallingPlayers on Cushions the landing of teammates who fall close to you, using the game's own catch mechanic.
DroppablePassport on Lets you drop and throw the Passport instead of it occupying a slot permanently.
ExampleCustomItems on Adds example cloned items (Grape Berrynana, Nuclear Dynamite) that spawn naturally. Demonstrates the item cloning API.
GhostPing on Lets dead players ping locations, so they can still help the group navigate.
ItemInfo on Shows remaining uses and details for the item you are holding.
LastChanceCast on Delays passing out while you are mid-cast, so a last-second item use is not wasted.
MushroomInfo on Shows what each mushroom does in this run, instead of learning by trial and error.
Push on Lets players shove each other. On by default; the host owns it for the whole lobby, because being pushed is not something the person falling gets to opt out of.
RopeCutting on Lets players cut a rope down so a badly placed one is not permanent. Refuses a rope with someone on it unless that guard is disabled. The host can switch it off.
RopeSwinging on Lets players swing on ropes rather than being dropped when the rope passes vertical. The host decides whether it is allowed for the lobby.
TeammateStats on Shows nearby teammates' stamina above their heads so you can tell who needs a rest.

A note on LastChanceCast

This is the one feature here that changes outcomes rather than convenience, so it is worth being explicit: the reprieve lasts only while a cast is actively running. It cannot be held indefinitely. The moment the cast completes or is cancelled, the pass-out proceeds, and afflictions keep accumulating throughout.

It removes a timing coin-flip, not the consequence. If you would rather not have it, turn it off and the rest still works.

Compatibility

Mod Overlap
Icebox-IForgorPassport same Passport drop/throw change
IntRabbit-Last_Chance same mid-cast pass-out delay
Yueby-ItemInfo same held-item readout
Kirshoo-MushroomsNOW same mushroom effect display
nickklmao-PeakStats same teammate stamina display
boxofbiscuits97-GhostPing both allow pinging while dead
tony4twenty-Catch_Players both cushion nearby falling players
Nozz-BagsForEveryone both hand out backpacks at run start

Determined by comparing the game methods and fields each mod touches against ours. Disable those if you have them, or disable the matching feature here.

Not tested running side by side with them in a live session.

Prior art

Independent implementation, written against PEAK's own assemblies. The problems it addresses were identified by the mods listed above.

Custom items

ExampleCustomItems demonstrates the item cloning API in SpongePEAKLib: new items built from existing ones, with recolouring, scaling, custom effects and natural spawning. Two examples ship, and are enabled by default. They are additive: nothing vanilla stops spawning.

  • Grape Berrynana — a purple berrynana whose effect changes with each cook: drowsy and mildly filling raw, properly filling at two cooks, poisonous when burnt. Spawns in jungle berry bushes and luggage.
  • Nuclear Dynamite — five times the size, green, two hundred times the blast and two hundred times the force on loose objects, and it leaves a poison cloud. Rare, deep-biome luggage only, and barred from solo runs.

Like any content mod, everyone in the lobby should have it installed. Item ids are derived by hashing the item name rather than allocated in order, so every player independently arrives at the same id for the same item, whatever else they have installed. No coordination needed.

A player who is missing the mod will see log errors and be unable to pick the item up, but their game keeps running rather than breaking.

Host-only features

BackpacksForEveryone is host-driven by necessity: spawning is networked, so if every client did it independently each player would get one backpack per client in the room. If the host does not have this mod, the feature does nothing regardless of what clients have installed.

Everything else is local and works for you whatever the host is running.

Requirements

BepInEx, SpongePEAKCore and SpongePEAKLib. r2modman installs these automatically.

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
F7 Mushroom effect list MushroomInfo_ToggleKey
F Push the player you are looking at PushKey
G Cut the rope you are looking at RopeCutKey

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

Configuration

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

Communication

Setting Type Default What it does
GhostPing on/off true Lets dead players ping locations, so they can still help the group navigate.

Display

Setting Type Default What it does
ItemInfo_ShowUses on/off true Shows remaining uses for consumable items.
ItemInfo_FontSize number 18 Font size for the held-item readout.
MushroomInfo_ToggleKey key F7 Key that shows or hides the mushroom effect list.
MushroomInfo_StartVisible on/off false Whether the list is shown without pressing the toggle key.
MushroomInfo_FontSize number 15 Font size for the mushroom effect list.
TeammateStats_ShowNames on/off true Shows each teammate's name above their stamina bar.
TeammateStats_MaxDistance number 30 Metres within which a teammate's stamina is shown.
ItemInfo on/off true Shows remaining uses and details for the item you are holding.
MushroomInfo on/off true Shows what each mushroom does in this run, instead of learning by trial and error.
TeammateStats on/off true Shows nearby teammates' stamina above their heads so you can tell who needs a rest.

Items

Setting Type Default What it does
Backpacks_PrefabName text Backpack Name of the backpack prefab to spawn, resolved under the game's 0_Items resource path.
Backpacks_SpawnDelaySeconds number 3 Seconds to wait after a run starts before handing out backpacks, so inventories are ready.
DroppablePassport on/off true Lets you drop and throw the Passport instead of it occupying a slot permanently.
BackpacksForEveryone on/off true Gives every player a backpack when a run starts, if they do not already have one. Host only.
ExampleCustomItems on/off true Adds example cloned items (Grape Berrynana, Nuclear Dynamite) that spawn naturally. Demonstrates the item cloning API. (replaces (new behaviour))

Movement

Setting Type Default What it does
RopeSwingMaxAngle number 150 How far past vertical a rope may swing before it drops you, in degrees. The game uses 90. Higher allows a fuller swing; beyond about 170 the rope can invert and look wrong.
PushKey key F Key that shoves the player you are looking at. Only works when the host allows pushing.
PushForce number 18 Impulse strength. Around 18 is a firm shove; much higher launches people, which is funny once and then ends someone's run.
PushRange number 3.5 How close you must be, in metres.
PushCooldown number 1 Seconds between pushes. Prevents holding the key from stunlocking someone and flooding the room with RPCs.
RopeCutKey key G Key that cuts the nearest rope. Only works when the host allows rope cutting.
RopeCutRange number 3 How close to the rope you must be, in metres.
RopeCutRequireEmpty on/off true Refuse to cut a rope somebody is currently climbing. Turning this off allows dropping other players, which is why the host rule exists at all.
RopeSwinging on/off true Lets players swing on ropes rather than being dropped when the rope passes vertical. The host decides whether it is allowed for the lobby.
Push on/off true Lets players shove each other. On by default; the host can switch it off for the being pushed is not something the person falling gets to opt out of.
RopeCutting on/off true Lets players cut a rope down so a badly placed one is not permanent. Refuses a rope with someone on it unless that guard is disabled. The host can switch it off.

Survival

Setting Type Default What it does
LastChance_Enabled on/off true Holds off passing out while an item cast is in progress. The reprieve ends as soon as the cast finishes or is cancelled.
Catch_Radius number 4 Metres within which a falling teammate's landing is cushioned.
Catch_MinFallSeconds number 0.6 How long someone must have been airborne before catching applies, so ordinary jumps are ignored.
LastChanceCast on/off true Delays passing out while you are mid-cast, so a last-second item use is not wasted.
CatchFallingPlayers on/off true Cushions the landing of teammates who fall close to you, using the game's own catch mechanic.

CHANGELOG

Changelog

1.0.0

First public release. Nothing before this was ever published, so everything below is new rather than a change from a version anyone has installed. The entries are kept in the detail they were written in, because most of them explain a real bug in the game or in these mods and that reasoning is worth more than a one-line summary.

  • Three of the four example items were cloning an item that does not exist. They named their source "Banana". PEAK's fruit is a Berrynana, and each colour is a separate prefab, so the lookup correctly found nothing and those clones were dropped. Only Nuclear Dynamite ever appeared, which is why the spawner said "1 custom".

    Source names refer to prefab assets rather than code, so a wrong one compiles fine and passes every assembly-level test. Two things now close that gap: tools/extract-item-names.py derives the real item list from the game's own asset files, and tools/check-item-sources.py fails the build if any clone names a source that does not exist, suggesting near matches. A clone can also declare fallback source names now, so a game update renaming a prefab degrades instead of silently deleting the item.

    The lookup also now ignores spaces and underscores, because PEAK's prefab and display names disagree about them constantly ("Airplane Food" versus "Airline Food").

  • Custom items were being lost to a load-order race. Three of the four example clones never got built, and the item spawner reported "1 custom" instead of 4.

    BepInEx loads plugins alphabetically, so SpongePEAKCheats initialises before SpongePEAKQOL. The clone builder ran as soon as ItemDatabase.Instance was non-null, which Cheats triggered with an empty queue, marking the build as done. Every later registration then built immediately, at plugin-load time, when the database object exists but its item lookup is still empty. Every source item resolved as missing, and the warning blamed the item name rather than the timing.

    Building now waits for the lookup to actually contain items, and a failed lookup lists similarly-named items so a genuine typo is obvious instead of looking like this bug.

  • The lobby browser's "YOUR LOBBY" heading rendered as a vertical column of letters. The label helper sizes for a stretched anchor, where the width is an inset from the panel edges, and the heading re-anchored to a point without setting its own width. The inset then became a literal negative width, so the text wrapped at one character per line.

  • Nuclear Dynamite is 200x, and its force on objects now actually works. The blast, damage, knockback and object force are all 200x vanilla, up from 20x. Radius 5 becomes 1000 world units; expect a visible hitch on the frame it detonates, which is affordable because AOE.Explode runs its overlap query once at detonation rather than every frame.

    Two bugs were also hiding behind each other. The game computes an object's impulse as (dir * knockback + up * verticalKnockback) * factor * itemKnockbackMultiplier, so knockback is already in the product; scaling the item multiplier by the requested force as well multiplied the two, which at these numbers would have been 40000x. The knockback is divided back out, so the item-force number means the force on objects relative to vanilla.

    Meanwhile none of it did anything unless AOE.canLaunchItems is true, which vanilla leaves false on some explosions, silently discarding every force value. It is enabled when a force above 1x is requested.

  • Everything is on by default now, except two things. VisualQuality and LobbyJoinFix were the last features shipping disabled. VisualQuality is on because trading a little fidelity for frames is what an optimisation mod is for, and its defaults are mild with every knob exposed. LobbyJoinFix is on because it installs no patches at all any more, so there is nothing left for it to race; enabling it is a no-op.

    The two deliberate exceptions: Telemetry, which draws a diagnostic overlay over the game, and listing your lobby publicly, which makes you visible to strangers.

  • The lobby browser works on the main menu, and has a button there. A LOBBY BROWSER entry now sits beside the vanilla menu buttons, and F6 works there too. The menu is where you are choosing a game to join, so it is the browser's most useful location; joining takes a Steam lobby ID and never depended on being in a run.

  • The mushroom effect list stays blank outside a run, unavoidably. MushroomManager is a level generation step, so which mushroom does what is randomised when the level is built. Before a run there is no table to show, and showing the last run's would be confidently wrong. Its hotkey is ignored on the menu so it cannot be toggled into a state that surprises you when the run starts.

  • Telemetry moved from F6 to F8. F6 was bound twice, by Telemetry and the lobby browser, so one key did two things. It was only latent because Telemetry shipped disabled; making it enable-able exposed it. F7 was already taken by the mushroom readout.

  • SpongePEAKAll, a modpack. One install that pulls in all seven mods at matching versions, so nobody has to add them one at a time or work out the dependency order. It ships no code of its own, only dependencies; a modpack that also shipped a DLL would install that DLL twice.

  • Custom items now actually appear. They were registered at startup and then never built, so the item spawner listed none and reported "no custom items: enable them in Mods settings" even though the feature was enabled. The build step hung off a Harmony patch on ItemDatabase.LoadItems, which exists, is public, and patches cleanly, but has an empty body and is never called by the game. Nothing reported an error because nothing was wrong at the patching level; the postfix simply never ran.

    Clones now build from ItemDatabase.OnLoaded, which the asset singleton really does invoke, with a direct build on startup as well in case the database was already resolved. The spawner's message now distinguishes "registered but not built" from "none registered", so those two very different problems can no longer look identical.

    A new gate rejects any Harmony patch whose target method has an empty body, which catches this exact class of silently-dead patch. It was confirmed to fail on the original bug before being kept.

  • SpongePEAKOptimized: the rope cannon fires again. This is RopeShooter, the cannon that shoots an anchor at a wall, not the rope spool you unwind by hand. RopeShooter.Update recomputes item usability from a raycast every frame, and the game cancels an in-progress cast the moment usability goes false, resetting cast progress to zero. Since the check requires both isGrounded and a terrain hit, and both flicker for a frame on slopes, steps, and ordinary mouse movement, the cast kept restarting. Usability is now latched for the duration of a cast; placement still re-validates your aim, so nothing can be placed where vanilla would refuse.

    Not confirmed in a live run. The mechanism comes from the decompiled game, but the report that prompted it was about the rope spool, which is a different item and is unaffected.

    The same fix removes a per-frame physics raycast for every rope cannon in the world, including ones nobody is holding, which vanilla paid for every frame.

  • All mod windows now use PEAK's own UI, and the mouse cursor works. Previously every window was drawn with Unity's IMGUI and set the cursor itself, which never worked reliably: CursorHandler re-locks the pointer every frame unless the game believes a menu is open, so the game and the mod each wrote the cursor every frame and the game usually won. The windows appeared and could not be clicked.

    The item spawner, run rules, name prompt, and lobby browser are now built from PEAK's own button and slider prefabs, inherit the game's fonts, and register as real MenuWindows so the game grants the cursor through its own path and stops routing clicks to the held item. They also look like the rest of the game rather than like a debug overlay.

  • Settings lists that are too long now scroll. PEAK's settings UI has no scroll view at all, because vanilla tabs never overflow, so a mod adding enough entries simply pushed them off the bottom of the screen where they could not be reached. Our tab now builds its own viewport and scroll view.

  • Run rules are reachable in-game. A RUN RULES button in the pause menu opens the host settings; clients see the values greyed out with a note that the host controls them.

  • Renaming yourself no longer overlaps the passport number. The rename control sits beside your name instead of on top of the number.

  • SpongePEAKLobby: a new mod. A lobby browser with lock codes. PEAK only ever creates friends-only or private Steam lobbies, so a browser mod is what makes a lobby publicly listable at all. That is normally all-or-nothing. A lock code is the setting in between: set one on your lobby and it disappears from every lobby browser, including this one, while staying joinable by Steam invite, from your friends list, and by anyone who types the code. So a friend can bring a friend and nobody browsing a public list ever finds you.

    It hides for a real reason rather than a cosmetic one: Steam does the filtering on its own servers, so a browser searching for public lobbies never receives a locked one. Codes ignore case and surrounding spaces, and are stored hashed rather than in plain text. If the host leaves, the promoted host re-asserts the lock so the lobby does not quietly become visible.

    "Hidden" means hidden from browsers, not invisible to your own Steam friends, and it is obfuscation rather than security. The mod says so plainly instead of implying otherwise.

  • SpongePEAKQOL: rope swinging, pushing, and rope cutting. All three are host-controlled, because opting out of being pushed is not something a client can decide for itself, so the host decides once for the lobby.

    All three are on by default, like everything else in the family. Everyone in a lobby installed the same pack on purpose, so the opt-out is choosing not to play with that group, and shoving your friends off a mountain is the point rather than a hazard. Where a real accident is possible it is prevented in code instead: cutting refuses a rope that someone is currently on. The host can still switch any of them off for the lobby.

    Swinging raises the rope angle limit the game uses to drop you, and deliberately adds no force of its own: the momentum is the one the game's physics already produce. Pushing sends the game's own force RPC on the target's view, so their client applies it and authority stays where the game put it. Cutting requests Photon ownership before destroying, since a non-owner's destroy is simply refused, and it refuses ropes with someone on them unless you turn that off.

  • SpongePEAKTweaked: campfire safe zone. Near a lit campfire, stamina stops draining, and optionally one resting player is enough to hold the gloom back rather than requiring the whole group, so a scout going ahead does not restart the timer for everyone at camp. Host-controlled and on by default: it only ever helps, and it helps everyone equally.

    Note that the game already stops hunger and already pauses the gloom at a campfire, so this deliberately adds only the parts that were genuinely missing rather than reimplementing behaviour that ships with PEAK.

  • SpongePEAKOptimized: adaptive networking. Measures every player's connection quality from telemetry Photon already maintains (latency, jitter, retransmissions, send backlog) without sending any probe packets, and lowers the room's send rate when someone cannot keep up, so a struggling player stops rubber-banding for everyone. The host decides one rate and clients match it, because the game interpolates remote players against the local serialisation rate. Nothing changes when nobody is struggling, players without the mod are never counted as the weakest link, and the rate only moves when every player in the room has the mod, so nobody is left interpolating against a rate they cannot follow.

  • SpongePEAKOptimized: Proton/Wine aware tuning. PEAK is a Windows build, so under Proton it reports itself as Windows and normal platform checks cannot tell. Detection now uses the ntdll!wine_get_version marker (read via the MonoMod that BepInEx already ships, so no native interop is added). Under Proton, background loading priority is raised so more shader pipeline compilation happens during loads rather than as first-encounter stutter. On native Windows nothing changes unless configured.

  • SpongePEAKLib: a "Mods" tab in the game's own settings menu. Lists the on/off settings of every installed BepInEx mod, rendered with the game's own settings rows rather than a custom window. Changes write to each mod's own config file. Rows changed this session are marked "restart to apply", because mods install their patches at startup. Core and Lib are marked "required" and cannot be disabled from the panel, since Lib draws it.

  • SpongePEAKTweaked: change your in-game name from the passport. A [ change name ] control sits under your name on the passport; the passport number updates with it. The name persists across restarts and is visible to players without the mod. On by default but inert: until you choose a name your Steam name is used, untouched. Per-player rather than host-controlled.

Foundations

  • Three-tier split: Core (shared foundation), Lib (modding API), Optimized (fixes bundle).
  • Eleven independently toggleable features in SpongePEAKOptimized.
  • Disconnected players stay in the world, can be carried to safety while alive, and are restored on rejoin when the gloom has not risen past where they left.
  • Single join arbiter so late-join, position-restore and catch-up never race.
  • Mod handshake over Photon player properties for host/client capability checks.