RuntimeCollective-lc_memsaver icon

lc memsaver

A BepInEx plugin that reduces Lethal Company's RAM consumption through multiple optimization systems. Works with vanilla and modded installs.

Last updated 3 minutes ago
Total downloads 31
Total rating 0 
Categories Tools BepInEx Performance
Dependency string RuntimeCollective-lc_memsaver-1.0.4
Dependants 0 other packages depend on this package

This mod requires the following mods to function

BepInEx-BepInExPack-5.4.2100 icon
BepInEx-BepInExPack

BepInEx pack for Mono Unity games. Preconfigured and ready to use.

Preferred version: 5.4.2100
BMX-LobbyCompatibility-1.5.1 icon
BMX-LobbyCompatibility

Towards a future with fewer lobby incompatibility errors.

Preferred version: 1.5.1

README

LC-MemSaver - Lethal Company Memory Optimizer

A BepInEx plugin that reduces Lethal Company's RAM consumption through multiple optimization systems. Works with vanilla and modded installs.

Features

Texture Optimization

  • Automatic downscaling of oversized textures (configurable max resolution, default 2048px)
  • Forced compression of uncompressed RGBA/RGB textures to DXT format
  • Mipmap streaming support to only load needed mip levels

Audio Optimization

  • Unloads audio data for long clips that aren't currently playing (reloaded on demand)
  • Configurable streaming threshold (default: clips > 10 seconds)
  • Optional mono audio to halve audio memory usage

Mesh Optimization

  • Marks meshes as non-readable after GPU upload, freeing CPU-side vertex data
  • Automatically skips meshes used by MeshColliders (needed for physics)

Garbage Collection Management

  • Periodic light GC passes (configurable interval, default 120s)
  • Aggressive full GC during level transitions (loading/unloading moons)
  • Large Object Heap compaction to prevent memory fragmentation

Level Transition Cleanup

  • Pre-cleans memory before loading new levels to prevent peak memory spikes
  • Post-cleans memory after level generation for optimal runtime usage
  • Hooks into Unity's SceneManager for comprehensive scene transition handling

Render Optimization (optional, disabled by default)

  • Configurable pixel light count and LOD levels
  • Shadow cascade reduction

Memory Monitoring

  • Logs detailed memory statistics (managed heap, Unity allocated/reserved)
  • Reports estimated memory savings from each optimization pass

Configuration

All features are configurable via BepInEx config (BepInEx/config/yutho.lc-memsaver.cfg):

Setting Default Description
EnableMemoryLogging true Log memory statistics
EnableTextureOptimization true Enable texture downscaling/compression
MaxTextureResolution 2048 Max texture dimension (256-4096)
ForceCompressTextures true Compress uncompressed textures
EnableMipmapStreaming true Enable Unity mipmap streaming
EnableAudioOptimization true Enable audio memory optimization
AudioStreamingThresholdSeconds 10 Threshold for audio unloading (seconds)
ForceMonoAudio false Force mono audio (may reduce quality)
EnableMeshOptimization true Free CPU mesh data after GPU upload
EnablePeriodicGC true Enable periodic garbage collection
PeriodicGCIntervalSeconds 120 Seconds between GC passes
EnableAggressiveLevelTransitionCleanup true Full cleanup on level transitions
EnableRenderOptimization false Apply render memory optimizations
PixelLightCount 2 Max per-pixel lights
MaxLODLevel 0 Minimum LOD level (0=best quality)

Installation

  1. Install BepInEx 5 for Lethal Company
  2. Place the plugin DLL in BepInEx/plugins/
  3. Launch the game - configuration file will be generated automatically
  4. Adjust settings in BepInEx/config/yutho.lc-memsaver.cfg as needed

Build

Release (recommended)

From the repo root:

  • ./build.cmd
  • or powershell -ExecutionPolicy Bypass -File ./build.ps1
  • or dotnet build -c Release

The plugin DLL will be in bin/Release/netstandard2.1/yutho.lc-memsaver.dll.

Debug

  • powershell -ExecutionPolicy Bypass -File ./build.ps1 -Configuration Debug
  • or dotnet build -c Debug

Compatibility

  • Client-side only - no impact on other players
  • Compatible with LobbyCompatibility (soft dependency)
  • Works alongside other mods - optimizes their loaded assets too

Versioning

BepInEx uses semantic versioning, or semver, for the mod's version info. To increment it, you can either modify the version tag in the .csproj file directly, or use your IDE's UX to increment the version. Below is an example of modifying the .csproj file directly:

<!-- BepInEx Properties -->
<PropertyGroup>
    <AssemblyName>yutho.lc-memsaver</AssemblyName>
    <Product>lc-memsaver</Product>
    <!-- Change to whatever version you're currently on. -->
    <Version>1.0.0</Version>
</PropertyGroup>

Your IDE will have the setting in Package or NuGet under General or Metadata, respectively.

Logging

A logger is provided to help with logging to the console. You can access it by doing Plugin.Logger in any class outside the Plugin class.

Please use LogDebug() whenever possible, as any other log method will be displayed to the console and potentially cause performance issues for users.

If you chose to do so, make sure you change the following line in the BepInEx.cfg file to see the Debug messages:

[Logging.Console]

# ... #

## Which log levels to show in the console output.
# Setting type: LogLevel
# Default value: Fatal, Error, Warning, Message, Info
# Acceptable values: None, Fatal, Error, Warning, Message, Info, Debug, All
# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)
LogLevels = All

Harmony

This template uses harmony. For more specifics on how to use it, look at the HarmonyX GitHub wiki and the Harmony docs.

To make a new harmony patch, just use [HarmonyPatch] before any class you make that has a patch in it.

Then in that class, you can use [HarmonyPatch(typeof(ClassToPatch), "MethodToPatch")] where ClassToPatch is the class you're patching (ie TVScript), and MethodToPatch is the method you're patching (ie SwitchTVLocalClient).

Then you can use the appropriate prefix, postfix, transpiler, or finalizer attribute.

While you can use return false; in a prefix patch, it is HIGHLY DISCOURAGED as it can AND WILL cause compatibility issues with other mods.

For example, we want to add a patch that will debug log the current players' position. We have the following postfix patch patching the SwitchTVLocalClient method in TVScript:

using HarmonyLib;

namespace lc_memsaver.Patches;

[HarmonyPatch(typeof(TVScript))]
public class ExampleTVPatch
{
    [HarmonyPatch("SwitchTVLocalClient")]
    [HarmonyPrefix]
    private static void SwitchTvPrefix(TVScript __instance)
    {
        /*
         *  When the method is called, the TV will be turning off when we want to
         *  turn the lights on and vice-versa. At that time, the TV's tvOn field
         *  will be the opposite of what it's doing, ie it'll be on when turning off.
         *  So, we want to set the lights to what the tv's state was
         *  when this method is called.
         */
        StartOfRound.Instance.shipRoomLights.SetShipLightsBoolean(__instance.tvOn);
    }
}

In this case we include the type of the class we're patching in the attribute before our ExampleTVPatch class, as our class will only patch the TVScript class.