

ScaleManager.UpdateOptions(GameObject, ScaleOptions) plus a ForceUpdateOptions variant that skips the lock check. Replaces the stored options on a live session so cart mods can retune RestoreSpeed / SuppressImpactFlash / SuppressCameraShake when a config slider moves mid-session, instead of reflecting into the private _options field. Pairs with the existing read-only CurrentOptions getter: read, mutate, pass back. Fields consumed once at dispatch (Factor, MassCap, BonkImmuneDuration) don't reapply retroactively, the next Apply picks them up.ScaleOptions.RestoreSpeed, animation speed for the expand direction. 0 falls back to Speed.ScaleOptions.SuppressImpactFlash, skips the impact flash on shrink/expand.ScaleOptions.SuppressCameraShake, skips the camera shake on expand. Pair with SuppressImpactFlash for a silent restore.ScaleOptions.SuppressVoicePitch, skips the audio pitch shift and per-frame voice chat overrides.ScaleOptions.IgnoreBonkExpand, damage doesn't restore the controller. Gated inside DispatchExpandNow so every bonk path honors it (player, valuable, enemy, cosmetic).ScaleOptions.RejectExternalApply plus ScaleManager.ForceApply / ScaleManager.ForceRestore. Opt-in lock so other mods' Apply/Restore/RestoreImmediate no-op on your controller; the Force* variants bypass.ScaleController.CurrentOptions, read-only snapshot of the active session's options.BotSystemSpringPoseAnimator) walks down a cached LimbChain.lenBind[] to place joints in world space, those values are full-size, the body wasn't. Idle path put joints outside the shrunken body, reach path left a gap between elbow mesh and the hand target. LoomVisualHandler now snapshots lenBind at Setup and writes orig * ratio every LateUpdate while shrunken, restoring the originals on expand.-up*0.3 offset in StartGrabbingPhysObject that doesn't scale, the new postfix lifts the puller back proportionally to player size.Apply with a different factor on an already-scaled controller re-fired Handler.OnScale on non-host clients, which read already-scaled singleton values as the new originals and compounded to factor². ApplyLocalPlayerShrinkEffects and RestoreLocalPlayerShrinkEffects are now guarded by a LocalEffectsApplied flag.PlayerAvatar.PlayerDeathRPC. Inverted/challenge mode skipped so dying small in that mode stays small.PackOpts slot 7, PackBools slots 2-6). Decoder length-guards every slot, old hosts can still drive new clients.EnemyBonkPatch now calls ctrl.DispatchExpandNow() directly instead of going through ScaleManager.RestoreImmediate. Internal bonk paths bypass the RejectExternalApply lock, only external mod calls honor it. Matches what ValuableHandler and CosmeticHandler already did.ScaleManager deduplication, the handler-type filter and lock check moved into IsTargetAllowed / IsLockedFromExternal helpers used by Apply/ApplyIfNotScaled/Restore/RestoreImmediate.ScaleController deduplication, PlayImpactEffect(), PlayCameraShake(), and ResolveExpandSpeed() helpers replace the repeated gate + ternary that had been inlined at every dispatch site.PlayerHandler.GetBaseGrabStats was guarding only one of three StatsManager upgrade dictionaries with ContainsKey before indexing all three. v0.4 (or some combination of mods + game state) leaves players with a strength entry but no range/throw entry, so the indexer threw KeyNotFoundException. The throw aborted OnRestore before RPC_PlayerPitchCancel could fire, killed ApplyLocalPlayerShrinkEffects partway through (camera/FOV/collision/grab range never scaled, so shrunken players looked tiny but played full-size), and inside CleanupAll's foreach it killed the whole loop after the first bad controller — leaving every player past that one stuck in shrunken state across level transitions. Switched to TryGetValue, missing entries default to 0 which matches the "no upgrades purchased" baseline.RunManager.ChangeLevel early-returns on non-host during gameplay, so the existing LevelChangePatch postfix never reached CleanupAll for them. Their OnUpdate kept re-asserting voice pitch every frame, overriding the cancel the host RPC'd in. Added a RunManagerPUN.UpdateLevelRPC postfix gated to non-host — that RPC fires on every client via AllBuffered, so the cleanup runs everywhere.CosmeticWorldObject) are shrinkable. They have PhysGrabObject but no ValuableObject or ItemAttributes, so neither the handler predicates nor the ScaleController attach patch matched, added a CosmeticHandler and extended AttachToValuablePatch to also pick up CosmeticWorldObject. Handler tracks NotValuableObject.healthCurrent for bonk-on-damage expand, same pattern ValuableHandler uses for dollar value.ItemVehicle.DeparentMesh runs meshTransform.SetParent(null, true) whenever a player sits in the vehicle. The visible mesh becomes a scene-root object that no longer inherits the vehicle's transform scale, while ItemVehicle drives meshTransform.position directly each frame. Shrinking the root therefore shrunk the colliders but left a normal-size mesh visibly floating around them; worse, the next time the game ran ReparentMesh (SetParent(originalParent, worldPositionStays: true)) Unity rewrote the child's localScale to 1/factor to preserve world scale, so when expand fired the mesh ended up at 1/factor times original size. Added a VehicleHandler that matches ItemVehicle ahead of ItemHandler and per-frame enforces meshTransform.localScale to track the intended world scale regardless of current parent state. Pocketing is picked up from the same path ItemHandler used.ItemVehicle, ValuableArcticSnowBike) now drive at proportionally lower top speed instead of full speed on a tiny chassis. Scaling the transform but leaving maxSpeedKmh / bikeForwardSpeed at their full 100 / 10 values made a half-size car try to do 100 km/h with full-size forces. Felt like driving a brick on ice. Added vehicle speed-cap fields (maxSpeedKmh, softMaxSpeedKmh, maxForwardSpeed, maxReverseSpeed, hyperMaxSpeed, bikeForwardSpeed) to the existing reflection-based field-scaling pass; they're restored verbatim on expand. Vehicles stay pocketable via the same path they did under ItemHandler.PocketHelper.CreateIconMaker was adding a SemiIconMaker component on an active GameObject, which fires OnEnable synchronously inside AddComponent, before we'd assigned iconCamera and renderTexture. OnEnable's if (renderTexture) branch skipped, renderTextureInstance stayed null, then the game's CreateIconFromRenderTexture NRE'd after teleporting the item to (-1000, -1000, -1000) for the render. The position-restore line never ran, the item fell out of world, the kill-zone destroyed it. The IconMaker is now created inactive, configured, then activated so OnEnable fires with everything in place.ItemVehicle.Semiscooter had no inventory icon (the small Semiscooter did). The icon-camera bounds calculation used item.GetComponentsInChildren<Renderer> on the vehicle root, which missed the deparented meshTransform and rendered an empty 5 KB PNG. Bounds now traverses meshTransform separately when it isn't a descendant of the root.ShrunkEquipBlockPatch was checking CartHandler.State and ItemHandler.State for AddedEquippable but not VehicleHandler.State, vehicles fell through and the block didn't fire. Added the missing case.ItemVehicle.UpdateSteering gates on DriverFullyMounted, which only becomes true once the player's tumble body comes within a hardcoded 0.05 world units of firstMountTransform. On a 0.4-scale vehicle that's basically inside the seat geometry; the player couldn't reach it, reachedFirstMount stayed false, steering clamped to 0. Postfixed the getter to return true when the vehicle has a seated player and is scaled.PhysGrabCart.CartSteer, EnemyVision.Vision) verified intact.PlayerHealth.Hurt routes through HurtRPC. Host-only now.PhotonNetwork.RaiseEvent byte codes (198/199) to a [PunRPC] component piggybacked on PunManager, no more arbitrary 0–199 numbers that could collide with another mod.MapCollapse is now public, other mods call MapCollapse.OnMapHit() to trigger the collapse eventScaleController.ChallengeMode public property, implementations set this to enable challenge modeSemiIconMaker generation for pocketed items, no more embedded PNGs, works for any itemShrinkChallengeMode and MapCollapse config removed, implementations own their settingsMapCollapseHitPatch removed, implementations provide their own hit detectionSuppressValueDropExpand option to ScaleOptions, valuables won't expand on damage while scaled. For cart mods where items bump into each other constantly.PreserveMass option to ScaleOptions, rigidbody mass stays at its original value while scaled. For cart mods where items should weigh the same regardless of visual size.ScaleManager.ApplyIfNotScaled(), scales only if not already scaled, no-op otherwise. Safe to call every frame from continuous triggers.ScaleManager.GetController(), returns the ScaleController for a game object, resolving through PlayerShrinkLink.playerKill no longer instakill when shrunkenenemyHost setInitial early access release.