-
Notifications
You must be signed in to change notification settings - Fork 0
Changelog
The 0.2.0-era limitation is gone. Custom items registered through ScavLib are
now fully spawnable at runtime — Utils.Create(id, ...) and
GameUtil.SpawnItem(id, ...) resolve custom IDs to a cloned template Prefab
instead of failing at the Resources.Load call.
The new CustomItemBuilder is the recommended entry point. It is a chainable
builder that constructs the ItemInfo, picks a clone template, registers the
ID, and (optionally) registers display-name and description locale keys in a
single fluent call:
CustomItemBuilder.Create("mymod_salve")
.FromTemplate(ItemTemplate.Bandage)
.Category("medical")
.Weight(0.3f).Value(15)
.Tags("medicine", "dressing")
.DisplayName("Herbal Salve")
.Description("A pungent paste that soothes burns and shallow cuts.")
.UsableOnLimb((limb, item) =>
{
limb.skinHealAmount += 15f;
limb.pain -= 20f;
item.condition -= 0.25f;
})
.Register();-
FromTemplate(ItemTemplate)— picks which vanilla Prefab to clone as the visual / physical base. TheItemTemplateenum covers the common bases (Bandage,Pills,Bottle,Generic, etc.). Falls back to a sensible default if omitted. -
Resource resolution — ScavLib applies a
Priority.LowHarmony Prefix to bothUtils.Create(string, Vector2, float)andUtils.Create(string, Transform). Registered custom IDs are intercepted and instantiated from the cloned template; unknown IDs are passed through to the game's normalResources.Loadpath, so other mods that patchUtils.Createkeep working. -
Owner Ledger — every registration records the owning mod name. The
scavlib checkcommand now lists custom items alongside commands, and conflicts are reported with both owners.
The legacy CustomItemRegistry.RegisterItem(id, info) and
RegisterSimpleItem(...) entry points are retained and now marked
[Obsolete] with a one-line message pointing to CustomItemBuilder. Existing
0.6.x mods that only registered metadata continue to compile and run; they
simply do not get a spawnable Prefab unless re-declared through the Builder.
See the CustomItemRegistry page for the full Builder
reference, ItemTemplate enum, and migration notes.
A new ScavLib.crafting namespace exposes RecipeBuilder, a chainable API
for adding entries to the game's Recipes.recipes list. Recipes plug into
the existing crafting UI and INT-skill checks — no extra wiring required.
RecipeBuilder.Create("mymod_salve_recipe")
.Category(RecipeCategory.Medicine)
.RequireINT(3)
.Ingredient("bandage", minCondition: 0.5f)
.Ingredient("alcohol", amount: 50f, isLiquid: true)
.IngredientByQuality(new CraftingQuality("herb", 1f))
.Result("mymod_salve", amount: 1, resultCondition: 1f)
.Register();-
Ingredient(specificId, ...)matches a concrete item ID; the underlyingRecipeItem.specificflag is set internally so callers never touch it. -
IngredientByQuality(quality)matches any item carrying the listedCraftingQuality(the same mechanism vanilla uses for "any blade", "any disinfectant", etc.). -
Result(...)/ResultLiquid(...)chooses the produced item and amount.DontDrainResultLiquid()exposesRecipeResult.dontDrainResultLiquidfor recipes whose product is itself aWaterContainerItemthat should arrive pre-filled. -
Failure behavior is unchanged from vanilla — INT shortfall of 1 may
reduce result quality to a 0.2 ~ 0.9 multiplier; a shortfall of 3 triggers
the gore penalty on both legs. Keep
RequireINTclose to your target player level.
Liquid results follow RecipeResult.SpawnResult exactly: ScavLib will first
try to top off a single-liquid container the player already carries, and
otherwise spawn a temporary craftingbottle that despawns after 300 s.
See the RecipeBuilder page for the full API.
ScavLib.liquid.CustomLiquidBuilder registers new LiquidType entries into
Liquids.Registry and exposes the two consumption hooks the game ships
with:
CustomLiquidBuilder.Create("mymod_tonic")
.DisplayName("Bitter Tonic")
.Color(new Color(0.35f, 0.55f, 0.20f))
.ValuePerLiter(8f)
.Quality("medicine", 0.4f)
.OnDrink((ml, body) =>
{
body.painShock -= 10f * (ml / 100f);
body.sicknessAmount = Mathf.Max(0f, body.sicknessAmount - ml * 0.05f);
})
.HealthUsable()
.OnHealthUse((ml, limb) =>
{
limb.skinHealAmount += 5f * (ml / 50f);
})
.Register();Delegate signatures match the game exactly:
OnDrink(float ml, Body body) and OnHealthUse(float ml, Limb limb). The
builder honours every vanilla LiquidType field — healthUsable,
injectable, injectionSickness, localeFromItem, and the qualities
list — and supports Quality(...) calls for crafting recognition.
See the CustomLiquidBuilder page for the full API.
ScavLib.locale.LocaleRegistry lets mods supply translations for their
custom IDs without shipping a forked Lang/EN.json. Entries are layered on
top of the game's Locale.GetItem / GetBuilding / GetMoodle / GetOther
lookups via a Harmony Postfix, so the vanilla fallback chain is preserved:
current language → EN → bare id.
LocaleRegistry.AddItem("mymod_salve", "EN", "Herbal Salve");
LocaleRegistry.AddItem("mymod_salve", "ZH", "草药膏");
LocaleRegistry.AddOther("mymod_salve_desc",
"EN", "A pungent paste that soothes burns and shallow cuts.");Bulk loading from JSON / dictionaries is supported via AddItems(lang, dict)
and friends. CustomItemBuilder.DisplayName(...) / Description(...) and
CustomLiquidBuilder.DisplayName(...) are thin wrappers over this system —
calling them is equivalent to manually adding the EN entry. Language
switches via Locale.ChangeLanguage(...) reload the scene, and
LocaleRegistry's table survives the reload.
See the LocaleRegistry page for the full API and the
mod-lang JSON loader.
-
scavlib checknow reports custom items, recipes, and liquids alongside Harmony patch status and commands, with owner-mod attribution and conflict detection. - All four registries (items, recipes, liquids, locale) sit behind the same Owner Ledger pattern introduced for commands in 0.4.2, so cross-mod conflicts surface in a single diagnostic.
None. I don't think adding back existing features is a destructive update.
The UguiBuilder control set is significantly expanded. All additions are
purely additive — existing AddLabel / AddButton / AddToggle / AddSlider
/ AddProgressBar / AddScrollView / AddSeparator / AddSpace signatures
are unchanged.
New input controls:
-
AddInputField(initialText, placeholder, onValueChanged, onEndEdit)— a single-line text field returningTMP_InputField.onValueChangedfires on every keystroke;onEndEditfires on focus loss / Enter. -
AddNumberField(initial, step, min, max, isInteger, onChange)— a numeric stepper laid out as[ - ][ field ][ + ], returning the newUguiNumberField. Reads throughValue; programmatic writes viaSetValue(value, notify);Step(direction)applies one increment. Values are clamped tomin/max, andisIntegerrounds to whole numbers.
New selection controls:
-
AddImage(sprite, pixelSize, maxSize)and theAddImage(spriteName, ...)overload — display a sprite sized from its texture (with a pixel multiplier and a max edge length), returningImage. Non-interactive by default. -
AddDropdown(options, initialIndex, onChange)— a self-contained dropdown returningUguiDropdown. The body is a compact button (current selection + ▼); options expand on a global overlay and collapse on outside click. ReadIndex/SelectedText; set programmatically withSetIndex. -
AddToggleGroup(options, initialIndex, style, onChange)— a mutually exclusive selector returningUguiToggleGroup.stylechooses betweenUguiToggleGroupStyle.Checkbox(one labelled checkbox per row) andButtons(a single row of equal-width buttons). ReadSelectedIndex; set withSetSelected.
-
BeginHorizontal(rowHeight)— returns aUguiHorizontalRowfor placing controls side by side. Supports fixed-width and text-fittedAddSmallButton, plusAddFlexibleSmallButtonfor equal-width fill. The row implementsIDisposable, so ausingblock settles it automatically. -
BeginTabs()— returns aUguiTabView. Add pages withAddTab(name, buildPage); switch withSelect(index)and read the current page viaActiveIndex. AlsoIDisposable— ausingblock defaults to the first page and completes initial layout on exit.
using (var tabs = b.BeginTabs())
{
tabs.AddTab("General", page => page.AddToggle("God Mode", false));
tabs.AddTab("Advanced", page => page.AddSlider("Rate", 0f, 10f, 1f));
}A shared overlay layer now backs both tooltips and dropdowns. It renders on a single persistent canvas, always above open windows, and survives scene transitions.
-
WithTooltip(name, desc)— a chainable extension on any control return value (orGameObject) that attaches a hover tooltip.
b.AddButton("Heal All", () => PlayerUtil.HealAll())
.WithTooltip("Heal All", "Restores every limb and clears status effects.");ScavLib's tooltips are deliberately isolated from the game's native tooltip system, so a control with a ScavLib tooltip no longer shows a duplicate game-native tooltip alongside it.
- Close button — windows can now show an X close button in the top-right of the title bar. It is enabled by default and is suppressed when the title bar is hidden. New theme metrics control its size and right-edge padding.
-
Click-blocking — a visible window with
BlockGameInput = truenow reliably absorbs clicks so they do not pass through to world-space actions (item pickup, etc.); clicks on empty space still pass through. -
Theme metrics —
UguiTheme.Metricsgains the layout values backing the new controls (small-button sizing, tab header height, input-field height and padding, stepper-button width, dropdown arrow width / row height / max visible rows, tooltip width / padding / cursor offset, toggle-group button height, default image max size, and scrollbar width).
None.
A full uGUI-based UI framework now lives under ScavLib.gui.ugui, intended as
the primary player-facing UI layer. The existing IMGUI windows are retained
as a debug-only facility (see the rename below). Public API:
-
UguiWindowBase — inherit and implementBuild(UguiBuilder)to define a window. Supports a hotkeyToggleKey, per-windowTheme, runtime-toggleable dragging (DefaultDraggable/SetDraggable), and click-blocking (DefaultBlockGameInput/BlockGameInput). Register viaUguiWindowBase.Register(window). -
UguiBuilder — control builder:AddLabel,AddButton,AddToggle,AddSlider,AddProgressBar,AddScrollView,AddSeparator,AddSpace. -
UguiTheme — immutable, chainable theme object. Derive variants withWithRowSpacing,WithRowHeight,WithHeaderHeight,WithWindowSize,WithPanelColor,WithContentPadding,WithTitleAlignment,WithHiddenTitle,WithTitlePadding, etc. The default theme matches the game's native look. -
UguiPixelBar — pixel-snapped fill bar used byAddProgressBar.
uGUI windows render through a single persistent overlay canvas, so they are available in both the main menu and in-game and survive scene transitions.
The IMGUI menu framework was moved into its own sub-namespace and renamed. This is a source-breaking change — IMGUI mods written against 0.5.x will not compile until updated.
| 0.5.x (old) | 0.6.0 (new) |
|---|---|
ScavLib.gui namespace |
ScavLib.gui.imgui namespace |
MenuWindow |
ImguiWindow |
MenuBuilder |
ImguiMenuBuilder |
MenuManager |
ImguiMenuManager |
Migration: change using ScavLib.gui; to using ScavLib.gui.imgui;, then
rename MenuWindow → ImguiWindow, MenuBuilder → ImguiMenuBuilder, and
MenuManager → ImguiMenuManager. Member names and method signatures are
unchanged, so no other edits are required.
PlayerUtil is now a single public static partial class split across
multiple source files for maintainability. The public API is unchanged by the
split; the files are PlayerUtil.cs (inventory), .Vitals, .States,
.Drugs, .Appearance, .Sleep, .LastStand, .Recovery, .RawWrites,
.Thresholds, and .Compat.
Coverage was completed to expose nearly every readable/writable Body field:
-
Drug components —
HasPainkillers/HasAntidepressants/HasSleepingPills, with matchingRemovePainkillers/RemoveAntidepressants/RemoveSleepingPills. PlusGetOpiateHappiness,GetAntidepressantHappiness, andGetCaffeinated. -
Last Stand —
TriedRollingLastStand,SuccessfullyRolledLastStand,GetLastStandTime,GetAntibioticImmunityTime(and theHasTriedLastStand/HasSuccessfullyRolledLastStandaliases in.States). -
Sleep —
GetBadSleepAmount,GetGoodSleepTime. -
Appearance —
IsDisfigured,IsEyeGone,IsBothEyesGone,IsMindWiped,GetHorrifiedLevel,GetClawHealth,GetWeightOffset. -
Extended state queries —
IsBreathing,IsInWater,HasScubaGear,IsStanding,IsCrouching,IsOnHardStimulants,UsedNeuralBooster,IsUsingSleepingBag,IsBothHandsUnusable,IsAboveMedicalCutoff,CanTakeNap,AllowUseItem,IsFibrillationRising,IsBrainDying. -
Computed read-only properties —
GetBloodVolumePercentage,GetTempDiffFromNormal,GetDesensitizedMult,GetCorpsesSeen,GetBloodPressureReadout,GetRespiratoryRateReadout, and several per-second movement / clotting / immunity multipliers. -
Raw writes — the
Set*Rawfamily was completed across every extended vital and boolean flag, each withMathf.Clampprotection.
HealAll() now also clears active Painkillers / Antidepressants /
SleepingPills components and resets badSleepAmount, opiateHappiness, and
antidepressantHappiness, mirroring Body.TryLastStand() cleanup.
The partial-class split renamed several boolean accessors from Get* to
Is* / Has*. The old names are preserved as thin aliases in
PlayerUtil.Compat.cs so mods written against 0.4.x compile unchanged:
GetDisfigured, GetEyeGone, GetBothEyesGone, GetSleeping,
GetFibrillationForced, GetHasPulmonaryEmbolism. Prefer the canonical
Is* / Has* names in new code.
Internal storage migrated to a ModSession-keyed dictionary. Each
registration now retains its EventBus adapter handle so the planned 0.5.1
enable/disable flow can unregister cleanly.
- New public
ModRegistry.GetSession(string name)returns the runtimeModSession(exposingInfo,Lifecycle, andIsEnabled). -
ModSession.IsEnabledis alwaystruein 0.5.0; toggling arrives in 0.5.1.
ModInfo dependencies are now backed by VersionedDependency, which supports
optional MinVersion / MaxVersion bounds with loose version parsing
(pre-release / build suffixes stripped, bare integers padded). Checks are
advisory only — a mismatch logs a warning but does not block loading. The
legacy string-array ModInfo constructor and the Dependencies name shim
remain for backward compatibility.
New EventBus.GetHandlerCount(Type) and generic GetHandlerCount<T>() report
the number of handlers subscribed to an exact event type. Handlers
subscribed to a base type are not counted (inheritance is resolved at Post()
time). Useful for skipping expensive payload preparation when nobody listens.
New CommandRegistry.GetOwner(string name) and GetAllRegistered() expose the
owner ledger for tooling. The scavlib check diagnostic is now built on top of
them, reporting Harmony patch status, command owners, and conflicts.
ScavLibPlugin now applies each Harmony patch class individually inside its
own try/catch, recording success/failure in PatchStatus / PatchErrors. A
single failing patch disables only its dependent events — the rest of ScavLib
keeps running, and scavlib check shows exactly which patch failed and why.
None. All additions are purely additive, and the renamed accessors retain their old names as aliases.
BaseCommand now supports an optional SubCommands dictionary for structured
command routing. The new ExecuteSubCommand() helper handles dispatch, help
output, and unknown-subcommand errors automatically — no more manual
if/else or switch blocks.
Subcommand keys are automatically merged into ArgAutofill[0] at registration
time, so first-level subcommand names get Tab completion for free.
Limitation: The game console only consults the top-level command's autofill table. Nested subcommand names (second level and beyond) cannot be Tab-completed — expose them via your help output instead.
SubCommands is rejected at registration time if ArgDescription[0] starts
with bool or position, because the game's Command constructor will
already auto-inject candidates for those types and the autofill keys would
collide.
CommandRegistry.TryRegister(cmd, ownerModName, out error) is the new
preferred registration API. It returns explicit success/failure info and
records which mod owns each command in an internal ledger. The legacy
Register(BaseCommand) overload is unchanged and records null as owner.
CommandRegistry.Unregister(string name) removes a previously-ScavLib-registered
command from the game's console. Only commands present in the owner ledger can
be removed — game-native commands are protected automatically.
New diagnostic subcommand. Run scavlib check in the developer console to see:
- Status of every Harmony patch ScavLib applies.
- All commands ScavLib has injected, paired with their owner mod name.
- A conflict summary if any names collide.
ScavLib's Harmony patches are now applied one class at a time inside individual
try/catch blocks. A single failing patch no longer takes down the entire
plugin or its dependents — only the events tied to the failed patch go quiet,
and scavlib check shows exactly which one failed.
GameUtil.Log now splits on \n and emits one console call per line. The
game's log command tokenizes input on spaces and previously lost everything
after an embedded newline. CRLF line endings are handled correctly; empty
lines are skipped.
BaseCommand.ValidateName is invoked at registration time and rejects:
- null or empty names
- names containing spaces
- names that collide with the 47 built-in game commands
A soft warning (not a rejection) is emitted for names without an underscore
prefix, encouraging the <modname>_<commandname> convention.
None.
-
EventBus deduplication —
EventBus.Register()now silently unregisters any existing handlers from the same listener before re-registering. CallingRegister()more than once on the same object no longer causes callbacks to fire multiple times. -
LayerLoadedPatch performance — The private
instantiatingWorldfield is now resolved via reflection once and cached, eliminating aTraverseallocation on everyWorldGeneration.Update()frame. -
WorldUnloadingPatch refactor — Patch classes have been promoted from nested to top-level, improving Harmony compatibility and avoiding potential class-resolution issues on some runtimes.
-
ModRegistry O(1) lookup —
TryFind()andIsRegistered()now use a name-keyed dictionary index instead of a linear scan. -
ScavLibCommand line output — Each line of
scavlib statusoutput is now issued as a separate console call, fixing truncated display in the in-game console.
None.
v0.4.0 introduces a first-class lifecycle system for mods. By passing an
IModLifecycle implementation to ModRegistry.Register(), your mod's
callbacks are automatically wired into the EventBus — no manual
EventBus.Register() call required.
ModRegistry.Register(new ModInfo("MyMod", "1.0.0", "desc"), new MyLifecycle());The IModLifecycle interface defines six callbacks:
| Callback | When it fires |
|---|---|
OnEnabled() |
Immediately after successful registration |
OnDisabled() |
Reserved for future use |
OnWorldLoaded(WorldLoadedEvent) |
World fully initialized, Body safe to access |
OnLayerLoaded(LayerLoadedEvent) |
Every layer (biome) finishes generating |
OnWorldUnloading(WorldUnloadingEvent) |
Before layer transition or save-and-exit |
OnWorldDestroyed(WorldDestroyedEvent) |
WorldGeneration.OnDestroy() completes |
ModLifecycleBase provides default empty implementations of all six
callbacks. Inherit from it and override only what you need.
Three new pre-defined game events are now built into ScavLib and triggered automatically via Harmony:
Fired every time a layer (biome) finishes generating and is playable, including the very first layer of a session.
| Property | Type | Description |
|---|---|---|
BiomeDepth |
int |
Depth of the layer that just loaded. 0 = first layer. |
IsFirstLoad |
bool |
true only on the first layer of the session. |
Fired before WorldGeneration.Clear() runs, giving you a last chance to
read player and world state safely.
| Property | Type | Description |
|---|---|---|
CurrentBiomeDepth |
int |
The depth being torn down. |
NextBiomeDepth |
int |
The depth to be generated next, or -1 on save-and-exit. |
IsExitToMenu |
bool |
Convenience: true if NextBiomeDepth < 0. |
Fired after WorldGeneration.OnDestroy() completes. Use for global cleanup
that must survive layer transitions.
| Property | Type | Description |
|---|---|---|
LastBiomeDepth |
int |
Last known biome depth before destruction. May be -1. |
WasSaveAndExit |
bool |
true if triggered by save-and-exit. |
ModInfo now accepts an optional dependencies parameter listing the names
of mods this mod depends on. Missing dependencies are logged as warnings at
registration time (advisory only — load order is still enforced by BepInEx
[BepInDependency]).
new ModInfo("MyMod", "1.0.0", "desc", "Author", "ScavLib", "OtherMod")scavlib status now displays declared dependencies after the mod entry:
ScavLib Activated.
Version: 0.4.0
Registered Mods: [
MyMod v1.0.0 by Author [F] Deps: [ScavLib, OtherMod]
]
The [F] tag indicates the mod was registered with an IModLifecycle object.
None.
PlayerUtil has been expanded to cover virtually every writable field on the
player Body component, up from the ~15 methods in 0.2.3. The new additions
are organized into named sections within the source file:
-
Circulation / Blood —
BloodViscosityBloodVesselSizeFibrillationProgressHeartRatePressureOffsetFibrillationForcedHasPulmonaryEmbolismStrokeAmount -
Adrenaline —
AdrenalineCurAdrenaline -
Infection / Toxicology / Sepsis —
SepticShockSicknessAmountVenomTotalVenomCurrent -
Bleeding —
InternalBleedingHemothorax -
Neurology / Psychology —
ShockPainShockTraumaAmountRadiationSicknessHorrifiedLevelFocusedLevelBrainGrowSickness -
Happiness / Weight —
HappinessBaseWeightOffset -
External Conditions —
WetnessDirtynessSnowAmountHearingLoss -
Claws —
ClawHealthClawRegrowTime -
Immunity —
ImmunityAntibioticImmunityTime -
Stimulants —
Caffeinated -
Appearance —
DisfiguredEyeGoneBothEyesGone -
Sleep —
SleepingBadSleepAmount -
Read-only derived properties —
AveragePainTotalBleedSpeedIsBreathingIsInWaterHasScubaGearIsStandingIsCrouchingIsOnHardStimulantsUsedNeuralBooster
Each writable field provides both a Get read and a SetRaw direct-field
write with Mathf.Clamp protection. The two-path convention (recommended
writes vs. Raw writes) introduced in 0.2.0 is preserved throughout.
PlayerUtil.Thresholds has been expanded from ~50 to 60+ named constants,
now covering every threshold used by the game's moodle system:
| Category | Constants added |
|---|---|
| Blood pressure |
CRITICAL_LOW LOW_1~3 HIGH_1~3 CRITICAL_HIGH
|
| Bleeding speed |
CRITICAL HEAVY MEDIUM
|
| Internal bleeding | CRITICAL |
| Hemothorax |
PRESENT HEAVY
|
| Stroke | CRITICAL |
| Happiness | Full 8-tier scale (MISERABLE → HAPPY_4) |
| Weight offset | Full 8-tier scale (UNDERWEIGHT_4 → OVERWEIGHT_4) |
All values were extracted directly from MoodleManager.AddAllMoodles() and
match the thresholds used by the game's own UI.
LimbUtil gains several new aggregate query methods:
-
HasBrokenBone()—trueif any non-dismembered limb is broken -
HasDislocation()—trueif any non-dismembered limb is dislocated -
HasInfection()—trueif any non-dismembered limb has an active infection -
HasDismemberment()—trueif any limb has been dismembered -
GetMaxInfection()— highest infection amount across all limbs (0 ~ 100) -
GetAveragePain()— mirrorsBody.averagePain -
GetTotalBleedSpeed()— total bleed speed across all limbs
-
PlayerUtil.HealAll()— Now also resetsshock,adrenaline,curAdrenaline,painShock,traumaAmount,wetness,dirtyness,hearingLoss,hasPulmonaryEmbolism,venomCurrent,venomTotal,internalBleeding,hemothorax, andclawHealth— fields that were silently left dirty in 0.2.x.
None.
-
PlayerUtil — Fixed wrong namespace (ScavLib_API.util→ScavLib.util) and wrong access modifier (internal class→public static class). The class was previously invisible to all external mods. -
ItemPickupPatch — Removed unusedbool forceparameter from thePostfixsignature to eliminate unnecessary Harmony reflection binding. -
CommandRegistryPatch — Added[HarmonyPriority(Priority.High)]to guarantee commands are registered beforeWorldLoadedEventfires.
-
PlayerUtil — 9 new methods:-
GiveItem(string id)— Spawn item at player feet and auto-pickup -
TakeItem(string id)— Drop first matching item from inventory -
HasItem(string id)— Check surface inventory by ID -
GetAllItems()— Get all slot inventory items -
IsAlive()/IsConscious()/IsDying()— State queries -
GetHunger()/GetThirst()— Vital reads
-
-
MenuManager — Fixed menu windows not rendering. MigratedMenuManagerfrom a standaloneDontDestroyOnLoadGameObject to aMonoBehaviourrenderer attached toPlayerCamera. Removed the now-unusedMenuWindowStyleenum.
-
PlayerUtil — FixedBody.PickUpItemcall signature: parameter type corrected fromItem ittoItem item.
-
PlayerUtil — Vital sign reads, state queries, recommended writes, raw writes, inventory shortcuts, andPlayerUtil.Thresholds(~50 named constants from the game's moodle system). -
SkillUtil — TypedSkillTypeenum, level/XP reads, XP writes, raw level set, globalXpMultiplier. -
ItemUtil — World-space item scanning, safe condition modification, favourite toggling, safe destruction, global registry queries. -
CustomItemRegistry — Register customItemInfodefinitions intoItem.GlobalItemswith automatic injection timing.
- Added pre-defined game events:
WorldLoadedEvent,ItemPickedUpEvent,ItemDroppedEvent— triggered automatically via Harmony, no manual patching required. -
EventBus.Post<T>now dispatches along the full inheritance chain. - Exception isolation improved: handler errors now include event type context in the log message.
-
GameUtil — AddedIsWorldLoaded,GetWorld(),SpawnItemAt(id, Transform),Notify(). -
ModRegistry — AddedTryFind(name, out ModInfo)andIsRegistered(name). Duplicate registration now logs a warning instead of silently succeeding.
-
MenuWindow — Fixed auto-height:Height = 0now uses true IMGUI content-adaptive sizing instead of a hardcoded 400px fallback. -
MenuManager — Removed erroneoususing UnityEngine.Windowsreference. -
CommandRegistry — Removed deadInit()body; method is now a documented extension point called explicitly fromScavLibPlugin.Awake().
-
EventBus.Post<T>now dispatches to base-type subscribers. Only affects code subscribing toBusEventdirectly, which was not meaningful in 0.1.0. -
MenuWindowwithHeight = 0now resizes to content instead of 400px. Addpublic override float Height => 400fto restore the previous behavior.
-
MenuWindow/MenuBuilder— IMGUI menu framework. -
ConfigManager— BepInEx config wrapper. -
EventBus/[Subscribe]/BusEvent— Attribute-based event bus. -
CommandRegistry/BaseCommand— Console command registration. -
GameUtil— Basic player state and item spawning helpers. -
ModInfo/ModRegistry— Mod metadata registration.