Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Lithium fork
Modular balancing framework for Schedule I (IL2CPP): plants, mushrooms, mixing stations (Mk1 & Mk2), lab oven, cauldron, customers, shops, employees. Every feature is optional and JSON-configurable.
| Last updated | a day ago |
| Total downloads | 27 |
| Total rating | 0 |
| Categories | Tools Misc |
| Dependency string | EVB-Lithium_fork-1.0.9 |
| Dependants | 0 other packages depend on this package |
This mod requires the following mods to function
LavaGang-MelonLoader
The World's First Universal Mod Loader for Unity Games compatible with both Il2Cpp and Mono
Preferred version: 0.7.1README
Lithium_fork
Version : 1.0.9.2 • Target : Schedule I v0.4.5f2 (IL2CPP) • Loader : MelonLoader 0.7.1
Lithium_fork is a community-maintained fork of the original Lithium by DerTomDerTwitch — a modular balancing framework for Schedule I. Every module is independent and JSON-configurable under UserData/Lithium/. Enable only what you need. Recent work focused on making the Mk2 Mixing Station timer flow in real time, adding full mushroom (shroom) support to the Plants module, cleaning up the Plants config (separated Plants and Shrooms sections with inline notes), and major performance / log cleanup on the Mk2 UI path.
Not the official Nexus upload — use this fork only if you want the current-game-version build.
Table of contents
- Installation
- Features at a glance
- What's new — v1.0.9.2 highlights
- Changelog
- Module reference
- Building from source
- Troubleshooting
- Credits & links
Installation
- Install MelonLoader 0.7.1 on your Schedule I install.
- Launch the game once with MelonLoader so it generates
MelonLoader/Il2CppAssemblies/. - Copy
Lithium_fork.dllintoSchedule I/Mods/. - Launch the game. On first run, default JSON configs are created under
UserData/Lithium/with all modules disabled. - Open the config file(s) for the module(s) you want, set
"Enabled": true, tune the values, save, and restart the game.
⚠️ If you are migrating from the original Lithium.dll, remove it from
Mods/first. Only one of the two can be loaded at a time.
The existing UserData/Lithium/ JSON files from the original mod stay compatible (same folder, same module names, same keys with backward-compatible aliases where things changed).
Features at a glance
| Module | Config file | What it does |
|---|---|---|
| PropertyPrices | PropertyPrices.json |
Override the purchase price of every property. |
| Plants (pots) | Plants.json → Plants section |
Speed up / slow down weed / coca / meth growth. Soil drain rate. |
| Plants (shrooms) | Plants.json → Shrooms section |
Speed up / slow down mushroom growth. Substrate drain rate. |
| DryingRacks | DryingRacks.json |
Drying time per rack operation. |
| MixingStations | MixingStation.json |
Mix duration multiplier (Mk1 and Mk2), input capacity. |
| LabOven | LabOven.json |
Cook speed multiplier. |
| ChemistryStation | ChemistryStation.json |
Recipe cook speed multiplier (chem station only). |
| CauldronCustom | CauldronCustom.json |
Manual / NPC cauldron batch duration. |
| Employees | Employees.json |
Daily wages, walk speeds, max assignments, action timings (pour / water / sow / harvest). |
| Customers | Customers.json |
Effect-based contracts, strict handover rejection, effect-bonus payments, dealer suitability. |
| DynamicsOrders | DynamicsOrders.json |
XP-scaled contract quantity & payment (anchored brackets, smoothed interpolation). |
| Shops | Shops.json |
Shop & supplier prices (in-person + phone / Dead Drop), stock overrides. |
| StackSizes | StackSizes.json |
Override item / category stack sizes. |
| EffectCombos | EffectCombos.json |
Allow / forbid effect combinations. |
| TrashGrabber | TrashGrabber.json |
Grabber range and capacity. |
| WateringCans | WateringCans.json |
Capacity & refill behaviour. |
| Storyline | Storyline.json |
Storyline pacing tweaks. |
Every module has its own Enabled flag and defaults to false until you flip it.
What's new — v1.0.9.2 highlights
1. Mk2 Mixing Station timer actually flows in real time
In vanilla, the Mk2's screen counts down minute by minute (e.g. 30 → 29 → 28 …) while a mix runs. With the previous fork, the Mk2 screen froze on the initial duration even though the mix completed — only the Mk1's clock was being driven correctly. This is fixed:
OnMinPassadvancesCurrentMixTimeexactly once per in-game minute, debounced byTimeManager.DailyMinSum(no more 2-by-2 jumps from FishNet RPC echoes).- Mk2 UI is rewritten from
MixingStationCanvas/ station-meshTMP_Textreferences cached per station and written only when the remaining minutes value actually changes — no more per-frameGetComponentsInChildren+Regex.Replace. Il2CppObjectBase.TryCast<MixingStationMk2>()is now used everywhere for type checks, fixing IL2CPP-inheritance edge cases whereis/asreturnedfalseon legitimate Mk2 instances.- Authority for
CurrentMixTimeadvancement is resolved cleanly across solo / host / client modes. - Stack-overflow crash (recursive
OnMinPasstrampoline) is gone — prefix alwaysreturn false;and replicates vanilla deterministically.
2. Mushroom (Mushroom Bed / ShroomColony) growth support
PlantGrowth now supports mushrooms in addition to pot-based plants:
- Subclasses of
GrowContainer(e.g.MushroomBed) are discovered at runtime and patched directly onGetTemperatureGrowthMultiplier,GetCurrentGrowthRate, andOnMinPassso shroom-specific modifiers don't get masked by the base patches. - A separate
Shroomsconfig section means plants and mushrooms can have different speeds (e.g. mushrooms 2× faster, plants normal). - Water / substrate drain rate is configurable independently for plants and shrooms.
3. Plants.json — clearer structure
The config is now self-documenting and split into two named sections:
{
"Enabled": true,
"_Note": "Lithium 'Plants' module — configure PLANTS (section 'Plants') and MUSHROOMS (section 'Shrooms') separately.",
"Plants": {
"_Note": "POT-BASED PLANTS (Weed/Coca/Meth). GrowthSpeed: 1.0 = normal speed, 2.0 = 2x faster, 0.5 = 2x slower. WaterDrainModifier: soil drying speed — 1.0 = normal, 0.5 = dries 2x slower.",
"GrowthSpeed": 1.0,
"WaterDrainModifier": 1.0
},
"Shrooms": {
"_Note": "MUSHROOMS (Mushroom Bed). GrowthSpeed: 1.0 = normal speed, 2.0 = 2x faster, 0.5 = 2x slower. WaterDrainModifier: substrate drying speed — 1.0 = normal, 0.5 = dries 2x slower.",
"GrowthSpeed": 1.0,
"WaterDrainModifier": 1.0
},
"GrowthModifier": 1.0,
"WaterDrainModifier": 1.0
}
Plants.GrowthSpeedcontrols weed / coca / meth growth speed.Shrooms.GrowthSpeedcontrols Mushroom Beds.- The root-level
GrowthModifier/WaterDrainModifierstay as legacy fallbacks so older JSON files keep working unchanged. - Inline
_Notefields survive round-trips through the loader and document each section right in the JSON.
4. Performance & logs
- Mk2 lag from per-frame text scans is gone (cached refs + change-detection debounce).
- All diagnostic logs for
MixingStation/ Mk2 / canvas dump /OnMinPassticks have been removed — the log is quiet during normal play. - Harmony warnings about missing methods (
Update/LateUpdate/OnDestroynot declared on Mk2) are suppressed by switching the relevantTargetMethodlookups toAccessTools.DeclaredMethod.
5. Build / dev experience
Lithium.csprojnow fails fast with a clear error ifSCHEDULE_PATH(orLithiumScheduleGamePath) is missing, wrong, or points atMelonLoader/instead of the game root.AssemblyVersion/FileVersion/MelonInfoaligned on1.0.9.2. The Thunderstoremanifest.jsonuses1.0.9because Thunderstore enforces strict 3-segment SemVer.
Changelog
1.0.9.2 — Mk2 timer, Shrooms, Plants/Shrooms split, perf + log cleanup
- Fix: Mk2 Mixing Station UI timer now counts down minute by minute (was stuck on the initial value).
- Fix: Mk2
OnMinPassdebounce viaDailyMinSum—CurrentMixTimeadvances once per in-game minute (no more 2-by-2 jumps). - Fix: Stack overflow on
MixingStation::OnMinPass(Il2CppInterop recursion). - Fix: IL2CPP type-checks use
Il2CppObjectBase.TryCast<MixingStationMk2>()instead ofis/as(Mk2 instances are now correctly identified everywhere). - Fix:
MixingStationCanvasrewrites the "X mins remaining" string after vanilla each frame — vanilla can no longer re-assert the old value. - Add: Mushroom growth support —
GrowContainersubclasses (incl.MushroomBed) discovered at runtime; per-shroom Harmony patches forGetTemperatureGrowthMultiplier,GetCurrentGrowthRate,OnMinPass. - Add: New
Plants.jsonschema — explicitPlants(pots) andShrooms(mushroom beds) sections, each withGrowthSpeed+WaterDrainModifierand an inline_Note. Legacy root keys still respected as fallbacks. - Perf: Mk2 UI rewrite uses per-station
TMP_Textcache + change-detection debounce; no more per-frameGetComponentsInChildren/Regex.Replace. - Chore: Diagnostic logging removed from
MixingStationPatchLogic,MixingStationMk2Registry,MixingStationCapacityPatch,MixingStationCanvasUpdatePatch. - Chore: Harmony "method not found" warnings silenced via
AccessTools.DeclaredMethod. - Chore: All in-code notes and JSON
_Notestrings translated to English. - Build: Strict, friendly errors when
SCHEDULE_PATHis missing / wrong.
1.1.1 — pre-fork baseline (carryover from earlier fork builds)
- Stable Mk1 mixing-station patches, employee re-application after FishNet init, fork-specific Customers / DynamicsOrders / Shops behaviour.
(Earlier history follows the original Lithium changelog on Nexus.)
Module reference
Plants — UserData/Lithium/Plants.json
| Key | Type | Default | Effect |
|---|---|---|---|
Enabled |
bool | false |
Master toggle for the module. |
Plants.GrowthSpeed |
float | 1.0 |
Multiplier on growth tick rate for pot-based plants (weed / coca / meth). 2.0 = 2× faster, 0.5 = 2× slower. |
Plants.WaterDrainModifier |
float | 1.0 |
Multiplier on soil drying rate. 0.5 = dries 2× slower. |
Shrooms.GrowthSpeed |
float | 1.0 |
Multiplier on growth tick rate for Mushroom Beds. |
Shrooms.WaterDrainModifier |
float | 1.0 |
Multiplier on substrate drying rate. |
GrowthModifier (legacy root) |
float | 1.0 |
Fallback used when a section omits GrowthSpeed. |
WaterDrainModifier (legacy root) |
float | 1.0 |
Fallback used when a section omits WaterDrainModifier. |
Effective values used at runtime:
- Pots:
Plants.GrowthSpeed ?? GrowthModifier,Plants.WaterDrainModifier ?? WaterDrainModifier - Shrooms:
Shrooms.GrowthSpeed ?? Shrooms.GrowthModifier ?? GrowthModifier,Shrooms.WaterDrainModifier ?? WaterDrainModifier
MixingStation — UserData/Lithium/MixingStation.json
MixSpeed(float, default1.0) — scalesGetMixTimeForCurrentOperationwithFloor(result / MixSpeed).2.0≈ half the required minutes,0.5≈ double. Same semantics asLabOven.json'sSpeed.InputCapacity— setsMaxMixQuantityon every Mixing Station instance via aStartpostfix.- Mk1 & Mk2 both supported —
OnMinPassis patched on the baseMixingStationand onMixingStationMk2when the game overrides (not merely inherits) the method. - Mk2 UI is driven from
MixingStationCanvas+ station-mesh TMP refs cached per instance; the displayedX mins remainingis rewritten after vanilla each frame so it always tracksCurrentMixTime. - Legacy: if your file still has
MixStepsPerSecondandMixSpeedis left at1.0, that integer is used as the multiplier once.
LabOven — UserData/Lithium/LabOven.json
SpeedscalesOvenCookOperation.GetCookDurationwithMax(1, Floor(duration / Speed))(clamped to≥ 0.01).IsReadypostfix keepsCookProgress >= GetCookDuration()aligned with the scaled duration.
ChemistryStation — UserData/Lithium/ChemistryStation.json
Speed— required cook minutes =Max(1, Floor(StationRecipe.CookTime_Mins / Speed)). The chemistry station usesChemistryCookOperation.IsComplete+ChemistryStation.UpdateClock; postfixes alignCurrentTimeand refresh the alarm (DisplayCurrentTime = false).- Breaking: older configs used
BonusStepsPerTick— useSpeedinstead.
CauldronCustom — UserData/Lithium/CauldronCustom.json
ManualMinutesPerBatch/NpcMinutesPerBatch— when> 0, replaces vanilla remaining batch time with that many minutes. When0, falls back toManualCookSpeed/NpcCookSpeedwith the same semantics asLabOven.Speed.DebugLogOnce— log firstSendCookOperationonce per session.LogEverySendCookOperation— verbose; logs every batch with duplicate-skip reasoning. Does not requireEnabled.- Patches
Cauldron.SendCookOperationonly (notStartCookOperation) and de-duplicates RPC echoes viaNetworkObject.ObjectId. - Compatibility: do not run the Nexus Custom Cauldron Timers mod simultaneously with
CauldronCustom.Enabled: true.
Employees — UserData/Lithium/Employees.json
- Botanists:
MaxAssignedPots,WalkSpeed,DailyWage,SoilPourTime,WaterPourTime,AdditivePourTime,SeedSowTime,HarvestTime— applied per hire via Harmony postfixes onHarvestPotBehaviour.StartActionand any other*PotBehaviour.StartActionexposed at runtime; overwrites the behaviour'stimeRemaining/actionDurationafter each action. - Cleaners:
DailyWage,WalkSpeed,MaxBins— re-applied onNetworkInitialize___Early, again onNetworkInitialize__Late, then over the next ~45 frames so FishNet init doesn't overwrite them. - Chemists (
MaxStations) & Packagers (MaxStations,MaxRoutes,PackagingSpeedMultiplier) — same re-application pass.
Customers — UserData/Lithium/Customers.json
Enabledmust betruefor any fork Customers behaviour.Contracts.RejectHandoverWithoutPreferredEffects(defaulttrue) — block handover when delivered effects don't match the customer's preferred ones. Does not requireContracts.Enabled.Contracts.RequireXPForStrictHandover(defaultfalse) — gate strict handover onContracts.XPRequired. Leavefalseto always enforce strict matching.Contracts.Enabled(defaulttrue) — rewritesTryGenerateContractto use listed products + preferred effects instead of vanilla random pick.EffectBonus.Enabled— fork bonus payments on effect/quality match.- Notifications use
Contracts.MessageTemplates(player) /Contracts.DealerTemplates(dealer), gated bySendNotification*andNotificationCooldownInMinutes. ProcessHandoverandProcessHandoverServerSideboth guarded so deliveries skipping the normal path still respect strict handover.
DynamicsOrders — UserData/Lithium/DynamicsOrders.json
- Re-rolls contract payment & quantity based on
LevelManager.TotalXPafterCustomerContractRewriterruns. Global.XpPaymentBrackets— sorted byMinXp, each definesOrderQuantity{Min,Max}andPayment{Min,Max}. Smooth interpolation between brackets so tier crossings don't snap.Global.EnableOrderQuantityVariance(defaulttrue) — whenfalse, quantity sticks near the top of the band (stricter progression).Rules— optional per-NPC overrides keyed byCustomer.NPC.ID. Sparse entries supported. On first run, missing/emptyRulesis auto-populated with 66 customers atEnabled: false.- Counter-offer UI re-syncs price from
Customer.OfferedContractInfoso the form matches the message after Dynamics re-rolls.
Shops — UserData/Lithium/Shops.json
- Overrides re-applied each time a shop opens (
SetIsOpen) so lazy-loaded UIs (e.g. Dark Market) get the right prices. - Limited stock (
ItemOverrides.Stock) preserved across the same session (partial stock stays partial, real sold-out stays 0) with aShopCode|itemIdsession cache cleared on returning to the main menu. ArmsDealer→ShopCodearmsdealer.ShroomsSupplier→ShopCodeshrooms_shop. Dark Market → genericShopCodeshoponDarkMarketInterfaceGameObject.- In-person dealer prices use
WeedSupplier/CokeSupplier/MethSupplier/ShroomsSupplierblocks. Phone / Dead Drop prices use NPC supplier blocks:Albert,Shirley,Salvador,Fungal(mushroom supplier, e.g. Fungal Phil) viaPriceOverrides. PhoneMirrorListingPriceFields(defaultfalse) — only flip totrueif phone UI still shows wrong totals after overrides.
Building from source
- Set the game path before building (PowerShell):
…or pass$env:SCHEDULE_PATH = "D:\SteamLibrary\steamapps\common\Schedule I"-p:LithiumScheduleGamePath="…"directly todotnet build. - Launch the game once with MelonLoader so
MelonLoader\Il2CppAssemblies\exists. - From the repo root:
dotnet build .\Lithium.csproj -c Release - The DLL lands in
bin\Release\net6.0\Lithium_fork.dll. Copy it intoSchedule I\Mods\.
The .csproj will fail with an explicit error if SCHEDULE_PATH is missing, points at MelonLoader/ instead of the game root, or Il2CppAssemblies/Assembly-CSharp.dll isn't there.
Troubleshooting
- MelonLoader log line on startup:
Lithium_fork v1.0.9.2confirms the right build is loaded. If you see an older version, you have a staleLithium.dllorLithium_fork.dllinMods/. - Mk2 timer still frozen? Make sure
MixingStation.jsonhasEnabled: true. Look inMelonLoader.logfor anyMixingStationpatch failure — that usually means a game update renamed a method (open an issue with the game version). - Shrooms grow at vanilla speed? Confirm
Plants.jsonhasEnabled: trueand aShroomssection withGrowthSpeed != 1.0. The log should show[Lithium_fork][Plants] Shroom patches applied: …andShroom config in use: GrowthSpeed=…. - Phone / Dead Drop prices wrong after overrides? Try setting
PhoneMirrorListingPriceFields: trueinShops.json. If that still doesn't fix it, captureMelonLoader.logat the moment of Place Order and report with the game version. Customers.jsonignored? CheckEnabled: trueat the module root, and thatContracts.Enabled: trueif you want contract-product rewriting. The startup log prints[Lithium_fork][Customers] Config: …with the effective flags.- JSON encoding looks broken in PowerShell: the files are UTF-8 (the loader uses Newtonsoft, which is UTF-8-aware). The garbled console output is just the terminal codepage — the mod reads the file correctly.
Credits & links
| Role | Who |
|---|---|
| Original Lithium | DerTomDer / DerTomDerTwitch, YukiSora, and contributors per the Nexus page. |
| Lithium_fork | Community fork maintained for current Schedule I IL2CPP builds. Not an official Nexus upload of the original file. |
| Link | Description |
|---|---|
| Lithium on Nexus | Original mod page. |
| Original Lithium docs | Module concepts & sample configs. |
| Schedule I modding docs | IL2CPP / MelonLoader reference. |
Respect the original author's permissions on Nexus if you redistribute. Lithium_fork is a separate maintenance effort; credit DerTomDerTwitch and the original project when sharing.