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

MacosModpackIntegration

The fixes, content and cross-mod integration MACO's modpack needed and no published mod provides: CodeRebirth's weapons crafted from scrap instead of a coin economy, crafting parts on every moon, 36 weather combinations and fifteen fixes.

By MACO
Date uploaded 3 days ago
Version 1.0.0
Download link MACO-MacosModpackIntegration-1.0.0.zip
Downloads 13
Dependency string MACO-MacosModpackIntegration-1.0.0

This mod requires the following mods to function

BepInEx-BepInExPack-5.4.2305 icon
BepInEx-BepInExPack

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

Preferred version: 5.4.2305
XuXiaolan-CodeRebirth-1.6.9 icon
XuXiaolan-CodeRebirth

Content Expansion mod with Custom Moon, Enemies, Weathers, Items and more! [V80]

Preferred version: 1.6.9
TeamXiaolan-DawnLib-0.9.25 icon
TeamXiaolan-DawnLib

A modern API for Lethal Company content and all sizes of mods [V81]

Preferred version: 0.9.25
MACO-CraftingLibrary-1.0.3 icon
MACO-CraftingLibrary

A crafting library for Lethal Company. Scrap lying in the ship becomes other items, from recipes written in plain text or registered by other mods. Ships no recipes of its own.

Preferred version: 1.0.3
mrov-WeatherRegistry-0.8.8 icon
mrov-WeatherRegistry

A mod for controlling the game's weather system: scrap multipliers, weather chances, blacklisting and more!

Preferred version: 0.8.8
mrov-WeatherTweaks-1.1.11 icon
mrov-WeatherTweaks

Difficulty tweaks to the weather system in Lethal Company.

Preferred version: 1.1.11

README

MACO's Modpack Integration

A mod written for my own modpack. It exists because that pack needed fixes and cross-mod integration that no published mod provides: CodeRebirth's weapons without the coin economy that comes with them, crafting parts that turn up on all sixty-six moons rather than two, weather combinations the weather mods define and then skip. It is shared as-is and built around that pack rather than as a general-purpose mod, and anyone installing it should know that going in. Every feature is a switch, so whatever does not suit your install can be turned off.

Requires CodeRebirth and DawnLib. The recipes need Maco's Crafting Library and the weathers need WeatherRegistry and WeatherTweaks. Everything else it reaches - Fair AI, Chameleon, JLL's interiors, TerminalFormatter, Wesley's Weathers, Moonswept - is optional: each feature looks for its mod and does nothing when it is not there.

Everyone in the lobby needs this installed, with the same Economy / Removed list. The store list and the item registry have to match across clients or the terminal desyncs. Only the host's settings decide what spawns.

What it does

Content

  • CodeRebirth's eight merchant weapons, obtainable without the coin economy they are bundled with.
  • Sixteen recipes to build them, written into Maco's Crafting Library's own recipe file.
  • 43 pieces of CodeRebirth scrap that it registers and never spawns, switched on as crafting parts.
  • Ten combined weathers: four WeatherTweaks defines but skips over a version check, six for weathers that were in no combination at all.
  • Six weathers that turn into a tornado partway through the day, or out of one.
  • Twenty more combinations built on Wesley's Weathers' five.
  • The Ship Upgrade Unlocker rerolled so it hands out something worth having.

Fixes

  • Dropped items drifting up through the ceiling.
  • The Rail Slugger firing level with your eyes instead of at what you are looking at.
  • The Rail Slugger missing an enemy that is already touching you.
  • The laser turret firing through the walls of a custom interior.
  • Fair AI's turret rewrite costing 23-26 ms of a 36 ms frame on a moon with 57 turrets.
  • Every snail cat throwing an unhandled RPC exception as it spawns.
  • The Stoptime Watch leaving something behind every time it is used.
  • The Oxidizer leaving you unable to press E, and any other interact lock that sticks.
  • The EZ Bake Oven not hurting enemies.
  • Chameleon's door fixer cutting level setup short on interiors it does not expect.
  • The game hitching while the Ship Upgrade Unlocker's video decodes its first frame.
  • Store items whose first word is already a terminal keyword being impossible to type.
  • The Grand Armory's teleporter doors ignoring the apparatus being pulled: Wesley's events need LethalToolbox, which cannot load on v81.
  • A door or turret that outlives its level throwing a NullReferenceException once a frame for the rest of the session.

Balance

  • Crafting parts held to a rate in landings per copy on every moon, instead of per-moon weights that leave most moons without them.
  • Interiors that place their own scrap thinned so they cannot farm those parts.
  • Moons that spawn hundreds of pieces a landing left out of the rate entirely - no rate survives them.
  • The three crystals tied to the weather's name rather than to a list of moons.

Integration

  • The >moons catalogue as one unbroken list, sorted by risk letter, with weather names held to a width so a combined weather stops pushing the risk column onto a line of its own.
  • Weather combinations registered only when every weather in them is registered, so nothing is gated behind a version string.
  • One build runs on either DawnLib 0.9.25 or DawnLibExperimental 1.0.x.
  • Diagnostics: a frame-timing probe, a per-script Update timer covering every installed mod, and a scene ablation pass that switches categories off and times each one. All off by default - they are measurements, not features.

Made with AI

All of the code in this mod and its documentation were written by Claude (Anthropic's AI, through Claude Code), directed and play-tested by me. The mod ships no items, models or assets of its own: everything it touches is CodeRebirth's content or the base game's.

CHANGELOG

Changelog

1.2.0

  • Fixes / SteadyEmoteCamera: an emote you can walk in no longer turns you on the spot. The game keeps your pitch on the camera and your yaw on the body, so the camera's own local yaw is always zero, and TooManyEmotes builds on that: while you are moving during an emote it copies the camera's local rotation onto the emote camera's pivot every frame, and adds whatever yaw the pivot holds to your facing. Camera Overhaul writes its lean, its shake and the Bracken neck-snap into exactly that local yaw, so a fixed offset was being integrated once a frame - the view rotated on its own, and because movement follows the body, the same key sent you off sideways. The pivot's yaw is now cleared after the copy, except while you hold TooManyEmotes' own rotate-character key, which is the one time that yaw is meant to turn you. Pitch and lean are untouched.
  • Fixes / RepairRadarNames: the name on the ship monitor belongs to the crewmate on the ship monitor. The monitor draws radarTargets[i].name beside a camera pointed at radarTargets[i].transform, and the game writes those names by player index whenever somebody joins - which is only correct while the list is still in player order. It does not stay that way: switching a radar booster, Wesley's fog reducer or one of CodeRebirth's gals onto the radar re-sorts the whole list, players included, by network object id, and MoreCompany appends its extra slots. Each entry is now named from the player it actually points at, right after the game has named them.
  • Fixes / SyncRadarTarget: everybody's ship monitor shows the same crewmate. All the game sends when someone presses the monitor is an index into a list each machine builds for itself, and a client whose list is shorter than the index it is sent ignores the switch outright and is pointed elsewhere for the rest of the session. The host now says which network object its own monitor is showing - a few bytes on a change, and once every three seconds otherwise - and each client points its own monitor at that object, adding it to its radar list if it never got it. The game's own switching is untouched; this corrects the result of it. Every player needs this mod installed for it to work.

1.1.2

  • Fixes / RestorePoseAfterEmote: the held item is put back in the right hand. 1.1.0 restored the bones and 1.1.1 replayed the hold animation; the diagnostic those shipped with said what was actually wrong. A carried item is parented to a point under your first-person arms, and to a point under the body model's hand on everyone else's screen. TooManyEmotes moves yours to the body for a third-person emote, because during one you are looking at your body - and the move back does not always happen, so the item stays welded to a body you cannot see, hanging in the air beside the arms that should be holding it. The parent of everything in the player's slots is now recorded on the way into an emote and written back on the way out, and only where the emote is what moved it: an item dropped since, or taken over by something else, is left alone. Recording it rather than assuming which of the two is right keeps this correct for the other players in the lobby, whose items belong on the body.
  • ResetPerformingEmote is no longer treated as the end of an emote. TooManyEmotes only calls it on the way into another one, so a chained emote was throwing away the recording it still needed.

1.1.1

  • Fixes / RestorePoseAfterEmote now actually puts the item back in the hand. 1.1.0 restored the bones the emote posed, which was half the problem and not the half you could see. The game keeps its hold pose on two animator layers that are entered when an item is picked up or moved between slots, and nothing re-enters them when an emote ends - so the arm comes out of the emote playing something that is not the hold pose, the item hangs off it wherever it lands, and the animator rewrites those bones every frame, over anything restored. Dropping the item and picking it up fixed it because picking up is what re-enters the layer. The game is now told to replay its hold animation instead, with the same parameters it sets itself on a slot change: no sound, nothing dropped, nothing networked, and it corrects how you look to everyone else as well as how the item looks to you. The bone restore stays - the hold clips do not pose every finger.

1.1.0

  • Added Fixes / DespawnOfficeElevator. LC Office spawns its elevator cabin and the shelf inside it as network objects that survive the scene, and relied on a listener its Awake added to LethalLevelLoader's onShipLeave to despawn them. The v81 compatibility fix has to skip that Awake and adds the listener back nowhere, so the elevator was never removed: it kept its last position for the rest of the session, inside whatever interior generated next - a rack of shelves in a Bunker room, an invisible wall around it, a prompt to place an apparatus - and its storage script threw once a frame, 754,848 times in one session. The host now despawns every copy as the ship leaves, and the second dropped listener - the elevator reacting to the apparatus leaving its dock, the office's screen going blank - is back as well.
  • Added Fixes / RestorePoseAfterEmote. After a TooManyEmotes emote, a held item sat at the wrong angle in the wrong grip until it was dropped and picked up again. The emote copies its own skeleton onto the player every frame and then stops; the game's animator rewrites only the bones its clips animate, and the hold pose leaves the fingers and wrist alone, so they stayed where the emote left them. The pose from just before the emote is now recorded and written back the moment it stops.
  • Added Terminal / WeatherShortNames and Terminal / ColorMoonListWeather. A combined weather shortened to fit the catalogue was printed in WeatherRegistry's five-letter form - Storm+Solar for Stormy + Solar Flare - which reads only if you already know which is which. Each part is now written with a short name of its own, Storm+Flare, from a list you can edit, and every part is coloured as the ship's map screen colours it.

1.0.0

  • Renamed. MerchantSalvage is now MACO's Modpack Integration, because a mod that fixes turret timing, writes weather combinations and rewrites the moons catalogue had outgrown a name about a merchant. The merchant work is still the largest single piece of it.
  • Your settings do not carry over on their own. The config file is named after the plugin GUID, which changed from AhojKubas.MerchantSalvage to AhojKubas.MacosModpackIntegration, so a first launch after updating writes a fresh BepInEx/config/AhojKubas.MacosModpackIntegration.cfg at the defaults. To keep what you had, copy AhojKubas.MerchantSalvage.cfg to that name before launching, and delete the old plugin folder so the previous build does not load alongside this one. The AhojKubas prefix stays because BepInEx awakes plugins in GUID order and this one has to come before CodeRebirth; MACO's other mods use Maco., this one cannot.
  • Recipes are not rewritten. The marker line at the top of the block in recipes.txt says MerchantSalvage on every install made before this version; that line still counts as written, so a file you have retuned is left exactly as it is. New installs get the new wording.
  • The three Diagnostics measurements now ship off. FrameProbe, FrameProbeTimers and FrameProbeAblation were bound true because they were written to answer a live question about one moon, and that question has an answer - Fair AI's turret rewrite, fixed in 0.9.2. Left on, a fresh install wraps a few hundred per-frame methods at startup and then, after every landing, switches sound, particles, turrets and LOD groups off one at a time for about a minute. They are all still there and still work; turn one on when something needs measuring.
  • Added Fixes / RestoreArmoryApparatusEvents. Wesley's Grand Armory wires the doors in eight sealed doorways to flip when the apparatus is pulled, through LethalToolbox's ApparatusTakenEvent. Wesley's Interiors neither ships nor declares LethalToolbox, and its last build cannot load on v81, so the script is missing on every install and the doors ignore the apparatus; the events also passed the trigger no player, which the game dereferences. The host now flips every one of those doors the moment the apparatus leaves its dock, through the trigger's own RPC. Finding them means matching the EntranceCloser they sit in: the game spawns those under mapPropsContainer, not under the tile they were authored in, so there is no DunGen Tile above them to match on. When it finds none it now says what it saw at each step rather than reporting a success.
  • Added Fixes / SilenceDeadRadarBlips. A door or turret that outlives its level dereferences its destroyed map-screen icon once a frame, for as long as the local player stands in the ship. One object logged 5,500 NullReferenceExceptions in a single session. The check is now skipped when the icon is gone, and the first such object is named in the log once a session.
  • WeatherRegistry and WeatherTweaks are now declared dependencies. Nothing crashes without them - the weather code asks for them by name - but 36 of the weathers this mod adds cannot exist, which is a third of what it does.

0.11.0

  • Added Terminal / MoonListWeatherWidth, default 16. The moons catalogue is a fixed-width table padded to its widest cell, and 0.10.0's combined weathers are wider than it has room for: Eclipsed + Meteor Shower is 24 characters and Meteor Shower + Earthquakes 27, against the 16 left over once 66 moons have taken 21 for the name column and 5 for the price on a 48-character screen. The risk letter no longer fit on the line and wrapped onto its own row for every moon on the page. A name over the width now prints as WeatherRegistry's short form - Eclip+Meteo - which is what TerminalUtils meant to do: PreviewWeather declares the same 16 as its MaxLength and GetWeatherName swaps in the short form at that length, but the next line overwrites it with the full name whenever WeatherRegistry is installed, and TerminalFormatter calls Value rather than ValueWithMaxLength. Only the catalogue column is affected; the route page still shows the whole name.

0.10.0

  • Added Fixes / WesleyWeatherCombos. Twenty combined weathers built on Wesley's Weathers: Minefield in fog, snow, a blizzard or an eclipse; Forsaken with an eclipse, fog, snow, a blizzard, a solar flare or Hallowed; Hallowed after dark or in fog; a Hurricane with a flood, an eclipse or a tornado; Earthquakes in fog, in the dark, in a storm, a heatwave or a meteor shower. No progressions into them, on purpose: everything they put in the world is placed by JLL's JRandomPropPlacer, which runs once per landing after generation, so a Wesley weather arriving mid-day would be colour grading over an empty field.
  • Components / MinimumRatesSkipMoons now ships naming only Dine. Lecaro, Trite and Carnate were skipped on the arithmetic of their configured scrap tables (28 to 190 points). The floor measures the pool at spawn time, where ImmersiveScrap's flat six per item and the DawnLib scrap put every moon in the pack above 380 points, so on those three the one-per-six rate asks for a weight of 1.3 to 2.3 and is held; only Dine's 224 pieces a landing outrun a single point of weight. Every crafting part is now floored on 65 of the 66 moons.
  • A combination now checks that its weathers are registered rather than that a plugin is loaded. Wesley's weathers come from a .weatherbundle WeatherRegistry reads in its own Awake and have no plugin to look for. The older ten combinations and six progressions go through the same check, which changes nothing for them.

0.9.5

  • Removed Fixes / MobileTurretShootsEnemies and Diagnostics / MobileTurretLog. The feature worked up to the last step and no further: 0.9.4's diagnostic showed a turret locking onto an Eyeless Dog and then holding back every one of 30 shots as a miss, so the aim never satisfied the turret's own 15°/13m gun check and the target's health never moved. Two bugs deep with a third in front of it was not worth more of the session, so it is out rather than left half-working. The findings are written up in the FairAI turret memory if it is ever worth picking up again.

0.9.4

  • Fixed: the Mobile Turret would not shoot an enemy while anybody was watching. 0.9.3 stood down whenever targetPlayer was set, on the reasoning that a player should always come first. But targetPlayer is sticky: DoChasingInterval sets it from TargetClosestPlayer(5f, true, 70f, ...), whose line-of-sight test reaches 40 metres - the five is a hysteresis buffer, not a range - and neither firing state ever clears it again. Only the patrol interval does, and only once a player is already beyond five metres. So one glimpse of anyone within forty metres left a live player target in place indefinitely and switched the feature off, which is precisely the situation anybody testing it would be in.
  • The rule is now a player within the same 5m at which the turret notices you in the first place, and the stale target is cleared otherwise - the same assignment its own patrol interval makes, for the same reason. That also stops AimAtTarget dragging the barrel toward somebody forty metres away while this tries to hold it on something adjacent.
  • New setting Diagnostics / MobileTurretLog (default off): one line when a Mobile Turret locks on, one when it lets go, with shots fired, shots held back as misses, and what the enemy's health did. This exists because nothing else can answer the question - this turret and a vanilla one both damage through the same Fair AI method at the same configured amount, so the game's own Local client hit enemy ... with force of 1 lines belong to either and prove neither, and on a moon that also places vanilla turrets there is no way to tell them apart.

0.9.3

  • New setting Fixes / MobileTurretShootsEnemies: Moonswept's Mobile Turret now shoots enemies as well as players. Fair AI gives every vanilla turret the sense to shoot a monster standing in front of it, and cannot do the same here: all of that code is bound to the vanilla Turret class - typeof(Turret) reflection for the private state, centerPoint/aimPoint/ rotationRange for the geometry, Resources.FindObjectsOfTypeAll<Turret>() to find them at all - and the Mobile Turret is an EnemyAI. Its own targeting is TargetClosestPlayer and its own gun damages localPlayerController and nothing else.
  • The rules stay Fair AI's. Two of its methods ask for no turret and are public: CanMob(parent, identifier, mobName) and HitTargets(List<GameObject>, Vector3). So which enemies may be shot, which may be hurt and the TurretConfig / Enemy Damage number are all read from Fair AI's config by Fair AI's code. An enemy excluded there is excluded here, and changing a setting changes both.
  • Only the aiming is new, and every number in it is the turret's own: it notices an enemy at 5m in a 70° cone - the rule it uses to notice you - and hits at 13m in a 15° cone with the same Room-layer wall check its gun already makes. Searchlight, muzzle flash, one-second lock-on and three-second burst are untouched; it is driven through its own states rather than around them.
  • A player always wins. It is an enemy that hunts you and must not wander off to fight a Thumper.
  • The target is chosen only on the machine that owns the turret, because DoAIInterval runs nowhere else, so the damage - which broadcasts through HitEnemyServerRpc and applies on every client - is sent exactly once.
  • Corrected the description of Fixes / SpeedUpFairAiTurrets, which still named the reflection as the cost. 0.9.2 replaced that diagnosis and the config file had not caught up.

0.9.2

  • Fixes / SpeedUpFairAiTurrets now caches the thing that was actually costing the frame. 0.9.1 cached Fair AI's reflection, which measured no improvement at all - the reflection was real but it was not the bottleneck. The bottleneck is the first line of the turret's per-frame method, which asks whether a feature is enabled:

    public static bool Can(string identifier)
        => Config.Keys.Where(e => RemoveInvalidCharacters(e.Key.ToUpper()) == target)
                      .Any(e => Config[e].BoxedValue.ToString().Equals("TRUE", ...));
    

    That walks every setting in the file building two throwaway strings each. Fair AI ships 638 settings, so one call allocates ~1,900 strings, and because the setting it asks about (CheckForPlayersInside) is false, the walk never short-circuits. Fifty-seven turrets at 27fps is about 2.9 million string allocations a second - the frame time, and the reason garbage collection ran three times a second against a 700MB heap.

  • Can and CanMob are pure functions of the config, so each answer is now computed once by Fair AI's own code and remembered. The cache is dropped whenever a Fair AI setting changes, so editing one through LethalConfig still takes effect immediately.

  • The 0.9.1 reflection caching is kept. It was worth nothing while the config walk dominated and becomes the next cost once that is gone.

0.9.1

  • New setting Fixes / SpeedUpFairAiTurrets: caches the reflection in Fair AI's turret rewrite. Fair AI replaces Turret.Update so turrets can see and shoot modded enemies, and reaches the turret's private state with Type.GetField, looked up fresh on every access - 21 read sites, 46 write sites and 5 method calls, inside a method that runs once per turret per frame. Measured on Trite, which places 57 turrets: Turret.Update was 23-26ms of a 36ms frame, 75% of it, and disabling the turrets took the frame from 36.0ms to 8.9ms. Each lookup is now resolved once and kept. Same field, same type, read the same way, so no turret behaves differently and Fair AI keeps its feature; a name that fails to resolve falls through to the original. Does nothing without Fair AI, and nothing measurable on a moon with few turrets.
  • This one presents as a graphics problem and is not one, which is worth recording because it cost two wrong diagnoses. The frame was 31ms of main-thread work against 3ms of waiting, so the GPU was idle and no shadow, resolution, reflection or draw-distance setting moved it at all.
  • New Diagnostics section, which is how the above was found rather than guessed: FrameProbe logs the frame time split into main-thread and waiting time, plus every value that can pin a frame rate; FrameProbeTimers wraps Update, LateUpdate and FixedUpdate on every script in the game and in every installed mod and names the expensive ones; FrameProbeAblation switches categories of the scene off one at a time after landing and reports what each was costing. The probe defaults on and is cheap; the other two default on for one run and should be turned off once a question is answered.

0.9.0

Written the day Wesley's Moons 7.0.0 landed, which took the pack from 13 moons to 66.

  • New setting Terminal / MoonListGroupSize: the >moons catalogue as one unbroken list. The page is drawn by TerminalFormatter, or by TerminalUtils when TerminalFormatter is absent, and both put a blank row after every third moon from a literal 3 in the method - ldloc; ldc.i4.3; rem; brtrue - with no setting anywhere. Three blank rows per nine moons was fine for eleven moons and is a fifth of the page at sixty-six, and the gaps read as tier boundaries once the list is sorted by difficulty, which they are not. A transpiler rewrites that one constant in both mods to whatever the setting says; 0, the default, means never.
  • LethalLevelLoader's own Moons Catalogue Group Split Count is not the same setting and does not help: it only feeds LethalLevelLoader's text, and TerminalFormatter replaces that page before anyone sees it.
  • New setting Terminal / SortUnrankedMoonsByLetter: a moon whose risk level is not a plain letter now sorts by the letter it starts with. TerminalUtils' difficulty sort strips + and -, looks the rest up in Safe, F, E, D, C, B, A, S, and files anything it cannot find past the end of that list. Of this pack's 53 modded moons, 48 matched and 5 did not: B.. for Bees is a B and ??? is the ? the list already holds, and all three were sorting after Artifice. QUACK and I see you have no letter in them and still sort last, which is right for a secret moon. The tier list is read out of TerminalUtils rather than copied, so it stays correct if that mod changes it.
  • Components / MinimumRatesSkipMoons gained Lecaro, Trite and Carnate, and its names no longer need the moon's number. One point of weight is the least a spawn entry can carry and still exist, so on a moon that rolls a lot of pieces the floor cannot express a slow rate at all: Lecaro rolls 54 pieces a landing, Trite 50 and Carnate 41, against a typical 20 to 30. Dine's 224 was already the reason that setting exists.
  • Matching a skipped moon now also tries the name without its leading number, because Wesley's Moons 7.0.0 renumbered Roart from 398 Roart to 84-2 Roart and a list written with the number would have stopped matching without saying so.
  • New warning on landing when a part cannot be held to its rate, naming the parts and how many times too often they will arrive. This was the one way the floor could be wrong with nothing in the log to show it. Worth reading on any new moon pack, because the pool the floor sees is not the pool in the config: LethalLevelLoader injects modded items from a prefix on RoundManager.GeneratedFloorPostProcessing, which calls SpawnScrapInLevel four lines later.

0.8.9

  • New setting Shop / CrateOnly: items that turn up in CodeRebirth's wooden crates without being for sale. Until now those were the same list. A wooden crate picks one random shop item and builds its pool from every item DawnLib registered with a shop entry and no scrap entry — and DawnLib registers the terminal's own buyableItemsList too, so the crate pool is the store. Nothing could be a thing you only ever find.
  • It ships naming Rocket Launcher (LethalThings), which is registered but unreachable in a default install: not scrap, not sold, no spawn weights. One rocket is 100 damage, a 1.5 m kill radius, 12.5 m of falloff and an enemy hit force of 10; it spawns loaded with four, and its Missile ammo is bought at the terminal.
  • The patch is a postfix on ItemCrate.Start appending to the public static ItemCrate. ShopItemList, which CodeRebirth never clears. It deliberately waits for that list to be non-empty: the fill it follows returns early for a non-wooden crate, and again if the list already has anything in it, so adding to an empty list would take the real fill's place.
  • Names that no installed mod registered are named in the log instead of being skipped in silence.

0.8.8

  • The hitch on using the Ship Upgrade Unlocker was this mod, and it is fixed. 0.8.7's timing line named it on the first try: pool 854 ms, grant 847 ms, jingle 0 ms. Both of those are AccessTools.TypeByName, which finds a type by walking every type in every loaded assembly - about 850 ms in a pack this size. It was called twice on every click: once to read Lategame Upgrades' store into the pool, once to grant the upgrade. The second use, which rolled a plain ship unlockable and so never touched Lategame Upgrades, shows the difference exactly: grant 1 ms.
  • The type, its GetPurchaseableUpgradeNodes and its TriggerUpgradeRankup(node) are now resolved once, at startup, where a second costs nobody anything. Expect pool and grant in single milliseconds.
  • Reading the store also did a fresh property lookup per node per field - four properties across thirty-odd nodes, a hundred and twenty lookups a click. Every node is the same type, so the handles are cached by name now.
  • The same mistake, found by audit rather than by report: the EZ Bake Oven. RegionOf cached its answer per oven, but ovens are per-round objects and the cache is cleared as it grows, so the first use of each new oven paid the same 850 ms lookup. The type is resolved once now.
  • The per-use line gained a fourth number, notice, so it accounts for the whole click: pool N ms, grant N ms, jingle N ms, notice N ms.
  • Fixes / SmoothUnlockerVideo from 0.8.7 is kept. It measured jingle 0 ms - but that was measured with the flag already cleared, so whether the video would have stalled without it is untested. It costs nothing and the reasoning stands.

0.8.7

  • The hitch on using the Ship Upgrade Unlocker was the video, not the unlock. Measured from a play-test log: Lategame Upgrades finished a whole shared-upgrade grant, RPCs and save included, in about 2 ms both times it was used. What runs next is CodeRebirth's jingle, and the tablet screen's VideoPlayer ships with waitForFirstFrame on - which asks Unity to hold the game still until the first frame has decoded into the texture, on the main thread, at the moment of the click, and worst on the first play when the decoder is still being built.
  • New Fixes / SmoothUnlockerVideo, default true: clears that flag on the instance just before the video is activated, so playback starts when it is ready rather than the game waiting for it. Worst case the video misses a frame or two at the top of a six-second jingle.
  • Each use now logs where its time went - pool N ms, grant N ms, jingle N ms. The pool is this mod reading what is left to unlock, the grant is Lategame Upgrades or the game, the jingle is CodeRebirth's sound and video. If a hitch survives, that line says which third to look at, which is the thing the previous version could not answer.
  • The six seconds between using one and the item vanishing are not a hang: CodeRebirth's despawn coroutine waits for the 6.63 s ShipUpgradePadUse clip to finish before destroying the item.

0.8.6

  • The rate floor no longer ratchets. MinimumRates raises a moon's existing entries to the weight its rate needs, and put back only the entries it had added — never the ones it had raised. DawnLib never resets vanilla items between rounds (ShouldSkipIgnoreOverride is true for anything with a lethal_company key), so a raised Big bolt stayed raised for the session, the next landing on that moon counted it in the pool total, worked out a higher floor from it and raised again. Bounded, but on a moon that rolls ten pieces it converges toward three quarters of the loot being crafting parts. Every change is now undone after the roll, on the list it was made to, so each landing starts from the moon as authored.
  • Filler and mid rates turned down: filler 1.5 → 5, mid 4 → 6. Measured over six sessions, the old rates put about half of Experimentation's scrap into crafting parts on a first landing (one landing was 10 of 11 pieces). These parts are a guarantee, not a supply — most are common vanilla scrap already — and the model puts every recipe median where it was: toys 2–3 landings, Guardsman Phone and Lifeform Analyser 5, Oxidizer and FogHorn and InfiniKey 8, Mole Digger 12. The six gates stay at 8 and Gold bar at 12; they were never the volume.
  • New Components / InteriorSpawnerChance, default 0.25. Some interiors place their own scrap through JLL's ItemSpawner, and it is all crafting parts: Mones' Endless Hall drops 15–35 Big bolts and Tea kettles a landing on top of a roll of 8–15 pieces, the Attic about ten, Underwater Mines a few. A spawn of a part named in MinimumRates now goes ahead a quarter of the time. Parts the spawner places that are not in MinimumRates — a Tower elevator key — are never touched. 1 restores the interiors exactly; 0 stops them placing crafting parts at all. Does nothing without JLL.
  • The floor says what it did, one line per landing: how many entries it raised and added, the pool total before and after, and the parts' share of it. It had been invisible.
  • The Ship Upgrade Unlocker says what it gave, and how many milliseconds the grant took. A successful use was silent, which made "did it work" unanswerable from the log.

0.8.5

  • One build now runs on both DawnLib 0.9.25 and DawnLibExperimental 1.0.x. CodeRebirth 1.6.10 moved to the experimental library, which ships the same assembly names as the stable one and so can never sit beside it — meaning a pack has to go all the way over or not at all. This mod no longer cares which one is installed.
  • The only thing standing in the way was one call. NamespacedConfigWeight.ConvertManyFromString was deleted in 1.0.0, and its replacement lives on Dawn.UnresolvedNamespacedWeight — a struct, unrelated to the old type, returning a list of itself, which cannot be handed to a property still typed List<NamespacedConfigWeight>.
  • So the parse happens here instead, copied from 0.9.25's implementation down to its quirks: entries split on ,, each lowercased and trimmed with runs of whitespace becoming _, split on = with empties dropped, the operator taken from the first character, the value parsed with its sign and then without it, and the result stored as an absolute value. A config written for the old library still means exactly what it meant.
  • MathOperation is written by reflection because it is the one piece DawnLib both renamed and moved: Dusk.MathOperation in dusk.dll through 0.9.25, Dawn.MathOperation in dawnlib.dll from 1.0.0. Everything else this mod touches — NamespacedConfigWeight, NamespacedKey, DuskItemDefinition — kept its name and its assembly.
  • The project file accepts either DawnLib package, preferring the experimental one when both are somehow present, and only references interfaces.dll when it exists.
  • Verified with Mono.Cecil rather than by launching: the built DLL resolves all 30 of its DawnLib references against 0.9.25 and against 1.0.6, and references no type that changed assembly between them.

0.8.4

  • The six parts the recipes gate on moved from Components / Weights to Components / MinimumRates. A weight has to name the moons it applies to, and the six named the eleven vanilla ones — so any moon installed later carried none of them and six of the sixteen recipes quietly became vanilla-only. A rate names no moon at all, so a new moon is covered the day it arrives.
  • Nothing about how often they turn up changes. The weights being replaced were a per-moon snapshot of the same calculation MinimumRates does at spawn time, tuned to one copy every eight landings; the setting now says Hand Drill : 8 and works it out per moon instead, which also means it follows the pool when another scrap mod is added or removed.
  • MinimumRatesSkipMoons still leaves Dine out, which was the only reason these six were given explicit moon keys in the first place.
  • The three meteor crystals are now none in the shipped Weights default, matching what the setting's own documentation already described: they are found during an eclipse (WeatherNameRates) and by meteor shower, not by moon weight.

0.8.3

  • The laser turret no longer fires through walls. LaserTurret.FireLaser decides what the beam hit with one sphere cast, and the mask it uses is Colliders | Room | Player | InteractableObjectDefault is not in it. Vanilla interiors keep walls on Room, so the turret behaves there; a custom interior that leaves a wall on layer 0 is invisible to that cast, and the beam goes through the wall and burns whoever is behind it. Met in Underwater Mines.
  • CodeRebirth's cast still runs exactly as written. The same sweep is then repeated against the Default layer alone — ignoring triggers, so a reverb zone never stops a laser in mid-air — and whichever hit is nearer is used. The beam can only be shortened, never lengthened, and no new damage is possible, because a wall is not a player.
  • New Fixes / FixLaserTurretWalls, default true. Does nothing without CodeRebirth.
  • A snail cat spawning no longer throws an unhandled RPC exception. The message that gives a new snail cat its name and size also carries who is holding it, which for a wild one is nobody. DawnLib writes that as player id -1, and converting it back throws instead of returning null — while CodeRebirth's own null check sits on the line after the conversion. The cat is unharmed, since the throw is the last statement in the method, but every spawn painted a red block in the log.
  • The one conversion in that method now asks IsValid first and returns null when the reference names nobody, which is what the next line already expects. New Fixes / FixSnailCatOwner, default true. Not fixed in CodeRebirth 1.6.11.

0.8.2

  • TornadoProgression ships on. Both directions have been play-tested — the tornado arrives when the weather turns and is gone when it turns back — and it does nothing at all without both CodeRebirth and WeatherTweaks, so there was no longer a reason to make people find the setting.

0.8.1

Six tornado progressions instead of three, at times that land mid-day.

  • Four ways in and two ways out: Stormy > Tornado (0.30), None > Tornado (0.35), Rainy > Tornado and Foggy > Tornado (0.40), Tornado > Stormy (0.50), Tornado > None (0.55). Weight 15 each, in line with WeatherTweaks' own progressing weathers.
  • The day does not start at zero, which 0.8.0 got wrong. StartOfRound sets TimeOfDay.globalTime = 100 for each new day against a totalTime of 700, so normalizedTimeOfDay is already about 0.14 the moment the ship doors open - higher on a moon with a faster DaySpeedMultiplier. 0.8.0's changes were scheduled at 0.12 and fired on the first tick after landing. The usable window is roughly 0.2 to 0.85, since the ship also starts warning at 0.9 and leaves on its own at 0.996.
  • One step each, always taken. WeatherTweaks' own progressions pair a likely early entry with a certain late one, but a second entry naming the same weather runs the change again - and for the tornado that means despawning the one in the sky and spawning another twenty seconds later.

0.8.0

Weather that turns into a tornado, and back.

  • New Fixes / TornadoProgression, off by default. Adds None > Tornado, Stormy > Tornado and Tornado > None. The change lands about a tenth of the way into the day and always happens - these are made to be watched, not balanced. Raise or lower their Default weight in mrov.WeatherRegistry.cfg once you have seen one.
  • Off by default because a weather arriving mid-day is only safe if it does nothing to the level when it starts. CodeRebirth's tornado qualifies: TornadoWeather.OnEnable reads the outside AI nodes, borrows some of the level's enemy power budget and spawns one tornado twenty seconds later, away from the doors and the ship; OnDisable kills what it spawned and hands the budget back. Nothing there needs a freshly generated level. LethalElements' snow does not qualify - SetupLevelForSnow remeshes the terrain, rebakes the masks and refreezes the water - so no snow weather progresses here.
  • Needs CodeRebirth and WeatherTweaks.

0.7.0

Six more weather combinations, for weathers that were in none at all.

  • Eclipsed + Blizzard, Foggy + Toxic Smog, Eclipsed + Toxic Smog (LethalElements) and Stormy + Tornado, Eclipsed + Meteor Shower, Foggy + Meteor Shower (CodeRebirth). Blizzard, Toxic Smog, Tornado and Meteor Shower appear in no combination WeatherTweaks or anyone else ships. Each is gated on the mod that supplies its modded half, so a pack without CodeRebirth gets the LethalElements three and nothing broken.
  • All of them are combined weathers, none progress, deliberately. A combination turns every part's effect on at once before anyone lands, so a snow weather inside one builds its terrain exactly as it would on a plain Snowfall day. A progressing weather swaps effects mid-day instead, which for LethalElements' snow means tearing the terrain down and remeshing, rebaking and refreezing it while players stand on it - it re-rolls the snow height and the time snow reaches it, so the depth pops rather than accumulates, and it resets the thickness manager under whoever is walking in it. LethalElements itself ships progressions that remove its snow and none that add it.

0.6.0

Four weathers that were written down but never happened.

  • New Fixes / RestoreWeatherCombos. WeatherTweaks defines Stormy + Solar Flare, Foggy + Solar Flare, Foggy + Snowfall and Eclipsed + Snowfall, then only creates them if LethalElements reports version 1.3.0 exactly - MrovLib's compatibility check compares the string and defaults to exact matching. The only LethalElements that runs on v81 is the 1.4.x fork, so all four are skipped on every launch, silently, because a compatibility gate that finds nothing has nothing to say. This registers them with the names, pairs and weight the author wrote for them, and stands aside if WeatherTweaks has already made them. Needs both mods; does nothing without either.

0.5.0

The Ship Upgrade Unlocker stops being a lottery for furniture.

  • New Unlocker section. RerollShipUnlocker replaces CodeRebirth's roll, which went flat across all 28 unlockables the game had left to give — four of which do anything and 24 of which are suits and ornaments. Pool picks the categories, and defaults to real ship upgrades plus every Lategame Upgrades upgrade, which could never come up before: they live in that mod's own store as CustomTerminalNodes rather than in unlockablesList, so the roll could not see them. An upgrade you already own advances a level instead of being passed over. Nothing is charged either way.
  • Announce puts the result on everyone's screen, because the unlock is silent and happens out of sight, so the only way to find out used to be to walk round the ship or open the store. It is the tip box by default, and can be the centred banner, the chat box or nothing; the choice is per player. The message is carried by this mod rather than by chat, so hiding the chat box - which plenty of packs do - does not hide it.
  • Upgrades are told from ornaments by the game's own alwaysInStock flag, which is also what DawnLib sets in SetShipUpgrade() and clears in SetDecor(), so modded content sorts itself and no list of names goes stale.
  • Only the holder rolls now. ItemActivate runs on every machine for an item with syncUseFunction (GrabbableObject.ActivateItemRpc, SendTo.NotMe) and CodeRebirth's body buys from wherever it runs, so one activation could have bought one unlockable per player.
  • A client holding the unlocker gets the jingle. PlaySoundClientRpc is a ClientRpc: called from a plain client it sends nothing and executes nothing, so there was no sound, no video, and — since that RPC is what sets usedOnce — no record that the item had been spent.

0.4.2

Housekeeping, no behaviour change to anything that was working.

  • Removed Components / WeatherWeights. It was added in 0.4.0 and superseded within a day by WeatherNameRates, which does the same job and also works on combined weathers. A setting that is empty by default, duplicates another one, and fails silently against a mod most packs run is worse than no setting at all. Delete the line from your config if it lingers there.
  • A weather rule that matches nothing is now a warning. On the first landing the log says how many of the game's weathers each rule matches and names them, or warns and lists every weather there is. The whole failure mode of a weather rule is that it never fires and you never find out.
  • Declared the AI authorship in the assembly metadata and the README, which Thunderstore asks for and this package was missing.
  • Packaging now declares Maco's Crafting Library as a dependency. The code carries on without it, but the weapons are not sold and no longer drop, so an install without it is one where nothing this mod adds can be obtained.

0.4.1

The eclipse rule from 0.4.0 was only finding half the eclipses. This finds all of them.

  • New Components / WeatherNameRates, as Name : text : landings entries. Ruby Crystal : eclips : 2 means one Ruby every second landing whose weather has "eclips" anywhere in its name. The three crystals moved here and WeatherWeights is now empty.
  • Why the DawnLib route was not enough. A DawnLib weather rule resolves the current weather through TimeOfDay.effects[level.currentWeather] and then GetDawnInfo(), and WeatherRule.CanApply returns false when that is null - so a weather DawnLib never registered skips the rule in silence and leaves the item at zero. DawnLib registers whatever is in the effects array when its Terminal.Start hook runs, fifteen weathers in a pack like this one. WeatherTweaks builds twelve combined weathers; Aurora Borealis and Eclipsed Flare are in that fifteen, the ten with a + in the name are not, and neither are the progressing ones written with a >. Measured against this pack's weather weights, naming the vanilla eclipse reached 8.2% of landings while every eclipse-flavoured weather together is 16.9% - so more than half of all eclipses dropped nothing, with no error to show for it.
  • Matching on the name instead covers all of them, because a name is the one thing every weather has and every weather mod fills in. WeatherNames asks WeatherRegistry through reflection, so it stays an optional dependency, and falls back to the vanilla effect name and then the enum for anyone not running one.
  • A line in the log names the weather and the items whenever a rule fires, so it is obvious from the first eclipse whether it is working.

0.4.0

Crafting parts are inputs, not loot, so they now turn up at the same rate wherever you land, and the meteor crystals moved to the weather instead of the map.

  • New Components / MinimumRates. A list of Name : landings entries saying how often an item must turn up: Chemical jug : 4 means one every four landings, on every moon. It is a rate rather than a weight, so the number needed is worked out per moon from that moon's pool and how many pieces it spawns, and it is a floor rather than a cap, so a moon already carrying more keeps what it has. Twelve of the sixteen vanilla parts had holes before this - Chemical jug was on two moons out of twelve, Gold bar effectively on one - which made those recipes a trip to a specific moon rather than a cost.
  • New Components / MinimumRatesSkipMoons, default 7 Dine. Dine spawns 200-250 pieces a landing in v81, ten times any other moon, so a single point of weight there is already a copy every four landings and no rate can be held to. It stays the moon covered in body parts.
  • New Components / WeatherWeights. The same Name : weights form for the weather track, which DawnLib adds to the moon track rather than replacing it - so an item with weather weights and no moon weights spawns only in that weather. The three meteor crystals use it: they are found during an eclipse now, on any moon, and meteor showers stay the second and rarer source. Their moon rule is lethal_company:dine=*0, which works because Dusk applies additive rules before multiplicative ones, so the eclipse's +80 lands first and Dine alone zeroes it again.
  • The six gate parts use explicit per-moon weights instead of biome tags. DawnLib divides a weight by however many tags matched, so tundra=+4,vanilla=+2 was worth three points on Rend and two everywhere else; naming the moons sidesteps that and leaves Dine out by omission.
  • Fixed: Spud Tater asked for the tag forest and Plastic Cake for fun, neither of which any installed moon carries, and Ducky Tube had no rules at all. All three were registered, visible in config, and impossible to find.

0.3.0

A balance pass over the sixteen recipes, priced against what each item actually does in the decompile rather than against how many parts the line had.

  • Recipes are now priced by their rarest part, not their part count. Filler (Big bolt, Metal sheet, Large axle, Bottles, Cookie pan, Tea kettle) is one to three runs; mid parts three to ten; gates (Hand Drill, Rusted Pick Head, Saw Blade, Mirror, Hard Hat, Alarm Clock, Gold bar, crystals) eight to twenty-five. A run-defining item gets two gates, a strong one gets one, a toy gets none. The full table and the reasoning are in the README.
  • Four recipes came down. The Mouse Trap wanted a Saw Blade - the Rail Slugger's own gate - for an item that does 5 damage to a player, 1 to an enemy and snaps on whoever picks it up armed; it is now filler only and builds two at a time. The EZ Bake Oven and the Oxidizer each wanted a Hard Hat on top of what they already cost. The Mole Digger wanted two Rusted Pick Heads and a Hand Drill, three gates for a dig tool, and is down to one of each.
  • Three came up. The FogHorn calls ChangeWeatherTo(None) on the moon you are standing on and only gets less reliable with use (5% failure, plus 5% per use after) - the strongest economic effect in the set, previously an Airhorn and some sheet metal. The Nitroglycerin Crate deals a flat 100 to every enemy within fifteen metres with no falloff and at most 20 to a player at the centre, which is a room-clearing charge you can stand next to, and it was one Chemical jug and a flashbang. The InfiniKey unlocks any door or Pickable instantly, forever, with no battery and no cooldown, and gains a Control pad.
  • The Ship Upgrade Unlocker drops a Metal sheet and the WalkieYellie drops its Control pad. Neither was carrying its cost: the Unlocker is already two trophy parts for a random unlockable, and the WalkieYellie is a shout button.
  • Ruby Crystal | Allow Editing Config must be false. Set to true, Dusk keeps the config's empty Preset Moon Weights instead of the definition this mod writes, so the Ruby spawns nowhere and the Rail Slugger cannot be built - the recipe has been dead since 0.2.0 in any profile where that toggle was flipped. The README now says so where the weights are explained. The Sapphire and Emerald stay meteor-only on purpose; their two recipes are trophies.

Three CodeRebirth bugs turned up while doing it. All three are on by default and each has its own switch under [Fixes].

  • The Stoptime Watch no longer leaves movement speed behind. Starting the effect divides movementSpeed by Time.timeScale * 0.8 (x6.25 at its 0.2 timescale); ending it divides by 6. Those are not the same number, so every use left the player about four per cent faster — permanently and compounding, because movementSpeed is assigned in exactly one place in the whole game, its field initialiser. Death, revival and a new round all leave it alone, so the drift lasted until the game was closed; seventeen uses is roughly double base speed.

    This is why Lategame Upgrades looked implicated and was not. Running Shoes and the other movement upgrades are transpilers that read movementSpeed and add on top of it, so they amplify a corrupted base without ever writing one. Only Sick Beats writes the field, and its symmetric plus-and-minus comes out crooked if the watch multiplies in between. Fixing the watch fixes both.

    The correction cancels the ratio between the two operations rather than restoring a snapshot, so anything else that had a claim on movementSpeed during those thirty seconds survives.

  • Hold-to-interact no longer speeds up permanently after using the watch. While time is slowed, whichever InteractTrigger you look at gets timeToHoldSpeedMultiplier /= Time.timeScale, and the undo multiplies it back — but both read the timescale live, and the flag that gates them is cleared a full second after the timescale is restored to 1. Stop a hold inside that window and the x5 is never undone. Doors repair themselves; the ship lever does not. Each trigger's real multiplier is now recorded and put back.

  • The Oxidizer no longer leaves you stuck. Pressing the trigger sets PlayerControllerB.activatingItem, which stops you picking anything up and changing slots while it is up (doors and the terminal keep working - it skips BeginGrabObject, not the whole handler). Releasing is supposed to clear it, but ItemActivate returns early when the tank is not charged — before it gets to that line. Filling the tank or using the alt-fire supercharge mid-spray puts it in exactly that state, and the stock game only clears the flag on drop or death, which is why dropping the flamethrower appeared to be the cure.

  • A kill animation that never finishes no longer locks you out of everything. When an enemy starts killing you the game sets inAnimationWithEnemy, and your death is what clears it - PlayerControllerB.KillPlayer nulls it at line 6792. While it is set every interaction is refused, and unlike the other interact locks there is no timeout on the player's side. So anything that stops the death leaves it up for the rest of the round; god mode is the usual cause, and it is reachable in ordinary play too because MouthDogAI.KillPlayerServerRpc only broadcasts the kill coroutine when !inKillAnimation, so a dog that grabs a second player while already mid-kill sets their flag and never runs the code that would clear it.

    Released when the enemy is dead or gone, or after fifteen seconds with the player still alive. Every real kill animation is shorter than that and ends with a corpse.

    New ReportInteractLocks names the culprit next time the interact key does nothing: press E, get Interact was refused. Blocked by: ... in the log. There are a dozen fields that can do this and they look identical in play, so guessing is a wasted session. It hooks the keypress rather than polling, so sitting in the terminal or climbing a ladder produces no line.

    New ClearStuckActivation covers the general case: the flag set with an empty hand is stranded by definition, whatever set it, so it is cleared. Deliberately the narrowest test that is worth having — a shovel held over the head sets the same flag with nothing in use, so anything wider would cancel every heavy swing in the game.

  • The EZ Bake Oven now reaches enemies. Its damage and its netcode were always fine — four hit-damage a second plus explosion force, four times a shovel's rate. What failed was finding anything to hit, and there are three candidates that all live in the prefab rather than the code: a trigger volume on a layer that never reports enemies, a GetComponent lookup that only answers for enemy colliders carrying the hit component themselves, and a line-of-sight test asking for QueryTriggerInteraction.Collide, which counts every trigger volume in the way as a wall. Vanilla's own melee code uses Ignore.

    CodeRebirth's tick now runs untouched and this only steps in on a tick where it found no enemies at all, so nothing is ever hit twice. The replacement covers the same baking region, resolves colliders to the enemy they belong to, and uses vanilla's line of sight. The first time it lands a hit the original missed, it reports which of the three causes it was.

    Other players are left to CodeRebirth's own code, which works.

  • The recipes write themselves into the crafting library's file. On first launch this mod appends its sixteen recipes, as one block under a marker line, to BepInEx/config/CraftingLibrary/recipes.txt - the same file a player writes their own into. The block goes in above anything already written, so a player's recipe for the same product still wins. Keep the marker line and the block is never written again; a player's edits to it survive every update. Nothing is written when the library is not installed. Needs CraftingLibrary 1.0.0.

Also in the shipped recipes: the EZ Bake Oven's description said it cooks, which nothing in it does — the charred food comes from CodeRebirth's microwave map object, not the oven. And the Stoptime Watch's said six seconds, which is six scaled seconds at a 0.2 timescale, so thirty real ones.

0.2.0

  • The merchant weapons are no longer sold. Shop / Stock is empty by default. None of them were buyable in vanilla, and a store entry makes every other way of getting one pointless. Fill the setting in to put them back on the shelf.

  • They are crafted instead. Recipes ship as BepInEx/config/CraftingLibrary/10-coderebirth.recipes and need Maco's Crafting Library installed to do anything. All seven products are worth 0 — equipment, not loot.

  • Sixteen recipes, not seven. Every merchant item that does something is now craftable: the four weapons and three demolition tools, plus the Rubber band, Old Booze, Mouse Trap, FogHorn, WalkieYellie, Lifeform Analyser, InfiniKey, Stoptime Watch and Ship Upgrade Unlocker.

    The line is behaviour, not value. An item with its own ItemActivate is crafted; one that only sits there is found. A merchant item with no behaviour is a 22-line class of netcode boilerplate in the decompile, which makes the two easy to tell apart.

  • New setting Components / Weights. Six CodeRebirth items are switched on as crafting components — Rusted Pick Head, Saw Blade, Hard Hat, Hand Drill, Mirror and the Ruby Crystal — and nine more come back as plain scrap: Alarm Clock, Birthday Card, Disposable Camera, Music Box, Rolling Duck, Scribbled Paper, Teddy Bear, Walking Cane, Wilted Rose.

    This is a fix, not an override. Nothing in CodeRebirth is disabled: of the 43 items with no moon weights, 21 have a working source (meteor craters drop the crystals, burning a wooden crate drops the burnt flesh, the microwave makes the charred food, the Puppeteer drops its needle, Compactor Toby leaves a flattened body). The other 22 were the Merchant's stock, and RemoveCoinEconomy deletes the Merchant — so this mod is what orphaned them, and this puts them back.

  • Weights can now be cleared as well as set: Name : none switches an item off. The Mole Digger, Nitroglycerin Crate and Remote Detonator use it — they are the only merchant items CodeRebirth gives weights to, and finding one on the floor would make its recipe pointless.

    The weights have to be set from here rather than in CodeRebirth.cfg. Dusk rewrites <name> | Preset Moon Weights from the definition on every launch whenever <name> | Allow Editing Config is false, which is the default, so a hand-edited weight lasts until the next start. This writes the definition. If registration finishes and a component still has no weights, that is logged with the config entry to fix.

    The other five meteor crystals are deliberately untouched — meteor impacts already drop one of the six at random, which is a better way to find ore than tripping over it in a corridor.

0.1.7

  • New setting Fixes / GuardChameleonDoorFixer, on by default. Chameleon's door-mesh fixer trips over a door on some custom interiors (Mones' Underwater Mines for one) and the error cut short everything that was still to run at the end of level generation, including other mods' hooks. That one error is now caught and logged as a warning, and setup carries on. Doors on that interior keep their stock look. Does nothing when Chameleon is not installed.

0.1.6

  • New setting Fixes / FixSluggerPointBlank, on by default. The Rail Slugger could not hit an enemy already touching you, because its sphere cast ignores anything it starts inside of. The same sphere is now also asked what it is touching, and those hits count like any other. Players are never added this way.

Earlier versions predate this changelog.