Shadows Of Midgard
A stealth and perception engine for Valheim. Creatures see, hear, remember and doubt - vision cones, line of sight, noise, light, weather and camouflage feed a Stealth Brain that tracks each player separately. Server-synced, dedicated-server ready.Changelog
All notable changes to Shadows of Midgard.
A note on the history below. 2.0.0 is the first public release. Everything under it is internal development history, kept because it is an honest record of what the mod was and what was wrong with it — but none of those version numbers ever reached a registry, and nobody has ever run them but the author.
The project was also not under version control for most of that time, so the middle of the line cannot be attributed to specific builds. Those entries are grouped by theme rather than invented as individual versions. Entries are newest first.
2.0.9 — The Night Counts
Fixed — a clear night hid you no better than noon
-
Night now hides you. Shadows of Midgard judged how bright it was by the strength of the sun or moon light alone. Valheim does not make night by turning that light down: it turns the same light into the moon and gives it a dark blue colour, and in clear weather the moon is set just as strong as the sun. So a clear midnight counted exactly as bright as noon, and a rainy night counted brighter than a rainy day. The light's colour now counts as well, the same way the game's own stealth check measures light. Clear days are unchanged. A clear moonlit night now adds well under half the light of noon, and rain, snow and the Mistlands are darker again after dark. In light kit, a player standing still in the open is now spotted from roughly half as far away on a clear night as at noon; before, it was the same distance.
-
It matters most in light gear. Armour adds more to how visible you are than daylight does, so a player in heavy armour is still easy to see at any hour.
Fixed — the README promised torches mattered
- Shadows of Midgard has never measured light from torches, fires or forges, only from the sun and
the moon, but the README said a held torch was the main reason you got spotted. The README and the
LightPenaltydescription now say what the mod actually does: a torch in your hand counts only as one more item you are carrying.
No setting changed meaning. If you strengthened the shade or weather settings to make nights stealthier, try the defaults again first.
2.0.8 — Creatures Fight Back In The Dark
Fixed — creatures stopped attacking mid-fight and walked circles around you
-
An alerted creature no longer goes blind when you step past its shoulder. Every creature kept its 120° vision cone even while fighting you, so stepping to its side or behind it made it lose sight of you — and a Valheim creature will not swing at something it cannot see. It stopped attacking, wandered in circles around the spot where it last saw you, and soon gave up and walked away. The cone now applies only until a creature has been alerted to you; after that it sees all round, exactly as vanilla creatures do. A creature fighting one player still has its blind spot for anyone else sneaking up behind it.
-
Darkness no longer hides you from something you are already fighting. At night, in shade or in rain, your visibility could drop below the sighting threshold even face to face, with the same result. The new setting
CloseQuartersRange(section8 - Detection Ranges, default 4 m, server-synced) fixes this: once a creature is fighting you, it sees you within that distance of its body whatever the light, cover or camouflage. Walls, shut doors and mist still block it. It never sees you where a vanilla creature could not, and it only applies to a creature that already has you, so one that is merely searching can still be hidden from. Set it to0to turn it off.
Sneaking is otherwise unchanged: a creature that has not noticed you still has its cone, and light,
cover, camouflage and noise work exactly as before. If you widened VisionConeHalfAngle or softened
the shadow and weather settings to stop creatures losing you mid-fight, you can put them back.
2.0.7 — Valheim 1.0.16
Changed
- Rebuilt for Valheim 1.0.16. Rebuilt against the 1.0.16 game assemblies (client Steam build
25527674 / dedicated server build 25527701, network version 40 — save formats unchanged) and
BepInExPack Valheim 5.4.2350, unchanged. 1.0.16 removes only
ObjectDB.GetAllFoodItems()andButtonSfx.Start()from the assembly SoM compiles against, and SoM calls neither, so there is no source change and no behaviour change. Verified with a static reference check against both the 1.0.16 client and dedicated-serverManagedfolders (3,475 references, 23 Harmony targets, all resolved) and a headless boot on a real 1.0.16 Linux dedicated server, where the log reads[SoM/VanillaBind] 27/27 vanilla capabilities bound, every gate openand[SoM/Patches] 11 applied, none failed.
2.0.6 — Valheim 1.0.7
Changed
- Built for Valheim 1.0.7. Rebuilt against the 1.0.7 game assemblies (client build 25185596 /
server build 25185644, network version 39) and BepInExPack Valheim 5.4.2350, which the package
now lists as its dependency in place of 5.4.2333. All eleven patch targets and all 27 capability
rows in
VanillaBindwere checked against the 1.0.7 decompile: every one is present with the same signature, so there is no source change and no behaviour change. Verified on a real 1.0.7 Linux dedicated server, where the log reads27/27 vanilla capabilities bound, every gate openand11 applied, none failed.
2.0.5 — Fleeing Creatures Turn And Run, And Bosses Never Flee
Fixed — the moonwalk
-
A creature ordered to retreat no longer glides away backwards while staring at you. The retreat used to write the movement direction directly, and in Valheim a monster's body only ever rotates toward its look direction — which nothing was updating. The body stayed locked facing the player while the velocity dragged it away, and the animator, seeing motion opposite the facing, played the backpedal blend at speed: the moonwalk. Retreats are now routed through vanilla's own flee behaviour — the creature picks a reachable flee point (water and lava avoided), turns in place first, and then runs, exactly like a vanilla animal bolting.
-
Fleeing creatures actually sprint now — and are then deliberately slowed. The old code set a run flag vanilla recomputes and discards every physics frame, so a "sprinting" retreat quietly jogged. With the real run gait engaged, the new
FleeSpeedFactor(section2 - StealthBrain, default 0.6, server-synced) scales the retreat to a fraction of the creature's own run speed, so a wounded creature runs away convincingly but can still be chased down. Relative, likeSearchSpeedFactor, so fast creatures still flee faster than slow ones.
Fixed — bosses and Blighted World Heart sub-bosses never flee
-
Bosses do not run. Vanilla bosses never flee only because their prefabs ship without flee parameters; SoM's health-based retreat logic didn't know that convention and would order a boss into a strategic retreat below half health. Any creature flagged as a boss is now refused by the flee evaluator outright.
-
Blighted World Heart sub-bosses are refused too, even though BWH deliberately clears the vanilla boss flag on them (to stop the native boss bar crashing): SoM recognises their marker component directly. BWH itself now also stamps its sub-bosses with SoM's networked stealth exemption at spawn, which removes them from SoM entirely on every peer — including a peer the sub-boss migrates to mid-fight, where the marker component does not exist. (That half ships with the next BlightedHeart build; the SoM-side refusal works on its own for the common case.)
2.0.4 — Stealth Telemetry, and a Draggable HUD Again
Added — the server now publishes per-player stealth statistics
-
A new export file,
config/ShadowsOfMidgard/barrkbot_stealth.json, written by the server once a minute for the BarrkBOT Discord bot's generic scanner. Per player: sneak time and distance, times seen, times heard, alerts caused, engagements, and undetected kills — seeBARRKBOT_CONTRACT.mdin the source repo for the exact shape and the rules about what may never be renamed or summed. Totals cover the current server session; a restart resets them.Each client counts what only it can observe (its own player's pose; detection events on the creatures it owns) and publishes the counters as one rarely-written field on its own player's ZDO, riding replication that is already being paid for — no new RPC, no extra network surface. The server merges every reporter's counters per player and writes the file atomically (temp-then-rename), so the bot can never read a torn half-file as truth.
-
TelemetryExport(section1 - Systems, default on, server-synced) turns the counting and the file writes off together. An already-written file is deliberately left on disk — delete it by hand if you opt out permanently, because a stale file that still parses reads as live data. -
Nothing about gameplay changes: the counters observe the existing evaluation results and add no perception, no allocation on the hot paths, and no writes to any creature.
Fixed — the eye and the bar can be dragged again
-
The HUD widgets are draggable out of the box once more — in every menu, not just some. Two things were wrong, stacked. 2.0.1 put dragging behind
AllowDrag, default off, so by default the widgets never accepted pointer input at all and the HUD read as stuck. And the machinery itself was fragile even with the switch on: it was built on Unity's drag events, and whether those ever reach a widget living inside the vanilla HUD depends on which GUI is open above it in the canvas stack — in testing the same build dragged fine with the pause menu up and did nothing minutes earlier in the same session. A drag that works in one menu and silently dies in another reads as haunted. (v1 sidestepped this by building its own canvas with its own raycaster — the same construction whose duplicate EventSystem caused the swallowed-clicks bug.)Dragging is now read straight from the mouse instead, so it depends on nothing being delivered: grab either widget while any menu has freed the cursor — inventory, container, map, pause — move it, release, and the position is saved. The widgets are no longer raycast targets at all, so they can never block or swallow a click, during play or in menus. The trade-off that justified shipping the switch off no longer exists.
AllowDragsurvives as a position lock, default on; turn it off to pin the HUD in place. Existing config files are migrated (schema v4): a storedfalsewas the old default rather than a choice, so it is reset once, and afalseyou set from now on stays.
2.0.1 — Animals, and Four Things the First Testers Found
The first release shaped by somebody other than the author playing it. Everything below except the animal feature was found in a single external test session, and two of the four had been silently broken since the mod was written.
Added — the stealth model now covers animals
-
Deer, hares, chickens, boar piglets, wolf cubs, lox calves and the greydwarf gem obey stealth. These use Valheim's
AnimalAIrather thanMonsterAI, and every build of Shadows of Midgard before this one refused to register them — so a deer bolted from a player who was crouched, unlit, downwind and completely hidden. The most stealth-shaped creatures in the game were the only ones the stealth mod ignored.Animals reach the same sensing model as everything else: the same visibility, noise, hiding and camouflage terms, the same detection ramp, the same line-of-sight cast. What they do not get is the behaviour layer, and that is deliberate — an animal has no target to be handed, no ally to call and no attack to suppress. It flees or it does not. Driving one with the monster act layer would be inventing behaviour vanilla does not have.
-
A fleeing animal now settles the moment it loses you, not four seconds later. Vanilla's calm-down is a timer, not a re-check: once alerted, an animal keeps its target for a full
m_timeToSafe(4 s) and flees the whole time, with no range test and no line-of-sight test. In a stealth mod that is the entire experience — you break line of sight, the model correctly says the deer has lost you, and the deer keeps bolting anyway. It now drops the target on the same tick, but only when SoM is confident: the measurement must be fresh, sight and hearing must both be negative, the detection ramp must be at zero, and the animal must not have been escalated past Suspicious. Anything else is left to vanilla.This can only ever make an animal less aware than vanilla would have made it. Nothing in the animal path ever gives a creature a target it did not already have.
-
DriveAnimals(section1 - Systems, default on, server-synced) turns the whole animal half off and restores the older behaviour.
Fixed — the noise channel was dead, and had always been
-
Your noise was mathematically pinned at zero whenever you crouched in any weather. The two reductions subtracted:
noise = movement + armor - crouch - weather. With the shipped defaultscrouch = 0.6andweather = 0.4sum to exactly 1.0, which is exactly the ceiling of the two additive terms — so crouching in rain produced silence no matter what you did. Sprinting. In full metal. Carrying everything you own. Zero.The test log settles it: 243 of 243 sampled ticks read
noise=0.00, with the sub-terms sitting atmove=0.31 armor=0.57 crouch=0.60 weather=0.40. The hearing half of detection could not fire once in an entire session, and the HUD's noise bar never left its floor — which is how it was reported: "the bar is stuck."The reductions now attenuate:
noise = (movement + armor) × (1 - crouch) × (1 - weather). The config file already described it this way — both entries read "Fraction of your noise removed…", and a fraction of a total is a multiplication. No setting changed meaning and no description had to be rewritten; the arithmetic was simply not doing what the file said.
Fixed — the eye could not survive its own tint
-
The gem was invisible until something noticed you.
eye.pngshipped as a 40×40 stone tile with every pixel opaque and an average luminance of 103/255. Unity'sImage.coloris a multiply, so tinting that byColor.blue— the Unaware colour — produced a near-black square in the corner of a dark HUD. It only appeared when the tint changed to yellow or red. Reported as "the eye comes and disappears with detection", and that is exactly what it did.The icon is now alpha-masked to a disc with its levels lifted, and no rung of the colour ramp is a fully saturated primary any more — every one keeps a floor in all three channels so the artwork reads as itself. Unaware is a pale ice blue. The original flat asset is kept in the source tree.
-
The HUD widgets no longer swallow clicks. Both were raycast targets so they could be dragged, which meant they quietly intercepted pointer input in their patch of screen whenever an inventory or container was open. They bought nothing for it: Valheim locks the hardware cursor during play, so a drag can only ever be delivered while a menu is already open anyway. Dragging is now behind
AllowDrag(sectionUI, default off); the four position values are editable by hand either way. Dragging also used to fight the pointer — the widget re-asserted its configured position every frame while you were moving it — which is fixed regardless of the switch. -
The noise meter's backing plate is darker and nearly opaque, so the fill has something to read against and the border is visible. The gem no longer pops when a creature disengages.
Fixed — the armour catalogue could not be saved or trusted
-
The armour file was being written empty. A save of 663 classified items reached a tester's disk as a 24-byte stub containing nothing but
{"DataVersion": 3}— the entireArmorsarray absent, with no exception and no warning, while the log cheerfully reported success. Every"Protected": truea user sets would have been lost on the next launch, and the whole catalogue re-derived from scratch every time.The file is now composed and parsed by Shadows of Midgard itself instead of by
UnityEngine.JsonUtility, the save is verified by reading it back before it is reported as written, and a save that would replace a good file with an empty one is refused outright. A broken hand edit now reports where — the character offset and the character it did not expect — instead of a bare "could not read". -
Silver gear was classified as cloth. So was most black metal. The material matcher looked for whole words only, and vanilla is inconsistent about its own capitalisation:
AxeBlackMetalsplits intoblack+metaland scored as Metal, whileSwordBlackmetal,AtgeirBlackmetal,BattleaxeBlackmetalandShieldBlackmetaldo not split and scored as Cloth — the quietest material in the table. Four of the game's seven black-metal items. And nothing ever matched "silver" at all, in any version of this mod, so mountain-tier silver gear was five times quieter than the bronze it replaced.Fused compounds now match at a word boundary (with a three-character floor, so the false positives whole-word matching was introduced to kill — "hide" inside "Hidden", "root" inside "Rooted" — stay dead).
silverandsteeljoined the metal list;furandpeltjoined the leather list. The armour data version is bumped to 4, so every catalogue re-derives once on the next launch. Entries you marked"Protected": truesurvive, as they survive everything.
Fixed — two of the four sensing terms had never been logged
HidingandCamowere computed correctly and printed nowhere. Visibility and noise logged themselves; the method that was supposed to print all four had no caller anywhere in the mod. The eye's size is driven byVisibility × (1 - Hiding) × (1 - Camo), so a bug report about the eye could not be checked against two of the three numbers behind it. All four now print together.
2.0.0 — The First Release
The first build of Shadows of Midgard that has been run in Valheim, and the first that works. The stealth model is the one described in the README and has been stable for a long time; what changed here is that the engine underneath it can now actually reach the game.
Fixed — the one that mattered
-
The mod could not touch a single game object, and said nothing about it. Every direct read of a vanilla field threw
FieldAccessExceptionat runtime —Character.m_nview,BaseAI.m_characterand everything reached through them. The player roster came up empty, the creature registry came up empty, and the discovery sweep died on its first pass. With no records to answer from, all ten Harmony patches correctly reported "no opinion" and fell through to vanilla.The result was the worst possible failure shape: a flawless startup log — every capability bound, every patch applied, no errors — attached to a mod that did nothing whatsoever. Cause: the project compiled against a pre-publicized copy of the game assembly, which satisfies the compiler but not the runtime. The missing half was
[assembly: IgnoresAccessChecksTo("assembly_valheim")], which only the MSBuild publicizer emits. The build now publicizes the stock assembly at build time, like every other mod in the family.
Fixed — features that had never once run
Three subsystems were fully implemented, documented, and wired to nothing. Each failed silently, because the mod's entire design philosophy is "hold no opinion and let vanilla decide", and a component that is never called holds no opinion very convincingly.
- Armour never affected anything. The classifier existed and the data store existed, but nothing
ever triggered the classification pass, so the catalogue was permanently empty and every item
scored as uncatalogued — which correctly contributes zero. Plate was exactly as stealthy as rags.
Two triggers added, at
ZNetScene.AwakeandPlayer.OnSpawned. - Nothing ever called for help. Ally calls were queued into a ring buffer that had no drain. After the first few requests the buffer was permanently full and silently refused everything after. Now drained once per frame by the scheduler.
SoM_Ackwas never written on any creature. The replication seam called only the digest half of the write, skipping the acknowledgement entirely — so Mists of Avalor and Dvergr Allies readack == 0and concluded SoM was not installed. Exactly the silent failure that key exists to prevent.
Fixed — packaging and tooling
- The deploy script pointed at a profile that did not exist, warned about it in yellow, and then printed a success banner anyway. Every deploy since the test profile was renamed copied nothing while appearing to work. An explicit deploy that cannot happen is now a hard failure.
Changed — the startup log
- A healthy launch is two lines instead of thirty-seven. The capability probe used to print all
twenty-five rows on every launch, each ending in a word like
FatalorFeatureOff— the impact if that row ever failed, printed on rows that had passed. Under a header that mentioned failures, a clean run read convincingly as a total collapse. The table now prints only when it has something to say, and its header states outright that nothing failed when nothing did. - Any failure still prints everything, at its own severity, with no configuration required. Which rows failed together is the diagnostic, so a broken launch is now louder relative to the noise around it, not quieter.
ShowPatchSagaaccordingly changed meaning — it now forces both full tables on a healthy launch — and defaults to off. Config schema migrates to v3 and resets it; a storedtruewas the old default nobody had turned off, not consent to the new behaviour.
Changed — the armour catalogue
-
Roughly a fifth the size, and no longer full of things you cannot wear. The pass catalogued anything vanilla's
IsEquipable()accepted, which includes every monster attack in the game — a fuling's club and an abomination's swing genuinely are equipable weapon items. A real world produced 1182 entries, mostlyAbomination_attack1,troll_log_swing_handblob_attack_aoe, along with 69 warnings about name collisions between pairs of monster attacks.Items must now also carry an icon, which is vanilla's own test for "a player can hold this" —
Humanoid.Pickuprefuses an iconless pickup for players. No stealth number moves: an item that cannot be picked up cannot be equipped, so it was never scored. Armour data migrates to v3, which drops the stale entries; entries marked"Protected": truesurvive, as always.
Changed — the config file
-
Dead settings are now removed instead of being rewritten forever. A config file accumulated keys from older layouts, and BepInEx faithfully wrote them back on every save. One test profile carried 36 of them across nine sections, sitting next to the live settings under near-identical names — so editing the file by hand was a coin flip between changing something and changing nothing.
The migration system now asks the file what nothing binds, rather than keeping a list of names to delete. This is deliberately not a version step: it needs no changelog entry and no maintenance, and it cleans up layouts that predate the versioning scheme entirely.
1.9.9 — The Shadows Rewrite — internal
A near-total rewrite, and the direct ancestor of 2.0.0 above. The stealth model is the same one, ported formula for formula; the engine underneath it is new, and most of this list is about defects that had been present since 1.0 and were only found by rebuilding around them.
Never released, and never run in Valheim — which is how the three unwired subsystems and the publicizer fault listed under 2.0.0 survived a rewrite that was otherwise looking for exactly that kind of defect. Everything below was found by reading the code; everything under 2.0.0 was found by launching the game once.
Fixed — the ones you will actually notice
- Alerted creatures can no longer see through walls. Alertness used to make a creature sense you unconditionally, before any geometry was consulted — so once something noticed you, going indoors and shutting the door did nothing. It now re-checks line of sight on a bounded interval and loses you properly.
- The mod now works on dedicated servers. The whole engine opened with "find the local player, and if there isn't one, sleep for a second". On a dedicated server there is never a local player, so the mod did nothing at all there for the entire 1.x line.
- Multiplayer is genuinely multiplayer. Creatures now track each nearby player separately. A creature can be hunting one player while completely unaware of another crouched beside it — previously a creature had one awareness value shared between everybody.
- Your gem now shows how aware the world is of you. It used to show the highest alertness of any creature about anything within 64 m, so a wolf chasing another player, or a mob in a boar fight, turned your gem red while you were perfectly hidden.
- Alert state replicates again. Vanilla's alert flag was frozen off, which quietly broke the aggro roar, the alert animation, boss counting, the give-up timer, taming, Sneak XP, the enemy HUD icon agreeing between clients — and the backstab bonus, which is gated on the target not being alerted and so had become a free multiplier.
- Being hit registers. Both damage hooks were wrong: one ran on the attacker's machine at the
moment the packet was sent, before the hit was validated; the other targeted a method that
Humanoidoverrides without chaining, so it never fired for greydwarves, draugr, fulings, skeletons, dvergr or trolls — most of the game. SoM now subscribes where vanilla itself does. - Calling for help works. It never had. A reflection binding named the wrong declaring type,
threw into a swallowing
catchin a static constructor, and left ally-calling silently inert for the whole 1.x line. All reflection into vanilla is gone; these are ordinary compiled calls now. - Your memory survives your death. Creature memory was keyed to an id that changes every time you respawn, so every death orphaned every creature's memory of you. It is now keyed to your stable player id.
- The stealth HUD no longer breaks the game's mouse input. The mod created its own Unity
EventSystemduring startup — before Valheim had built its UI, so the "only if one doesn't already exist" guard always passed. When the game later created its own, Unity disabled one of them, and the mod's usually won. That is the swallowed-clicks bug. The HUD is now a child of the vanilla HUD and creates no canvas, scaler, raycaster or event system of its own. - The eye icon reflects hiding and camouflage. It was showing raw visibility, so crouching in a bush — the entire point of the mod — did not shrink it. A stray division also capped the icon at 95 % of its authored size, so "fully exposed" rendered smaller than the art.
- The mod no longer writes files into its own plugin folder. Loading the eye icon created directories and wrote a PNG next to the DLL, which failed on read-only installs and made the folder differ from what the mod manager put there.
- Non-
MonsterAIcreatures can attack again. The attack gate returned "blocked" to mean "no opinion", silently disarming every attacker the mod did not model. - Memory leaks closed. Creature records, awareness rows and a per-creature alert table were never cleared on world exit and accumulated for the life of the process.
Changed
- Configuration is server-synced properly. The admin lock entry was missing, which left the lock permanently disabled and allowed any client to broadcast its own settings world-wide.
- The TOML config now migrates across schema versions instead of being silently re-read under new
meanings. It backs up to
.cfg.bakfirst and only re-defaults keys whose meaning actually changed. - Armour data moved to a versioned
SoM_ArmorData.jsonwith hand-edited entries protected across rebuilds. - The HUD anchors to the bottom-left corner. It was anchored to the middle of the screen, so the default position put the eye on top of your crosshair. Your saved positions are kept and the widgets will move — drag them where you want them.
- Engaged is now a darker red than Alerted. Both rungs used to be identical red, distinguishable only by the pulse.
- Creatures are evaluated on a time budget, in distance tiers, from a single update — no coroutines anywhere in the mod.
- Detection now integrates over real elapsed time per creature-player pair, so a distant creature does not accumulate detection ten times slower than a near one.
- Sensing patches run at normal priority and honour other mods' decisions instead of forcing their
own answer with maximum priority and a second pass. The Harmony id is unchanged, so existing
HarmonyBefore/HarmonyAfterordering from other mods still resolves.
Added
SoMInterop— a supported, reflection-free way for other mods to read what SoM thinks about a creature, plus aSoM_Ackacknowledgement so a mod can verify SoM actually reached it.- Per-creature directives — other mods (or a spawner) can set sense-range multipliers, force alert, ignore line of sight, or apply a named AI profile, per creature, via ZDO keys.
- Replicated awareness — a creature's detection state now survives an ownership handover, so it does not forget who it was chasing when you walk across a zone boundary.
- A capability probe at startup that checks every vanilla member SoM depends on and logs a table. If Valheim changes underneath the mod, you get one clear line at startup and a clean fall-back to vanilla instead of an exception storm mid-raid.
- A read-only degraded mode. If the probe refuses, SoM loads, keeps its compatibility surfaces answering and its config live, and lets the game run vanilla perception.
Compatibility
- Mists of Avalor and Dvergr Allies need no changes. The
StealthExemptionhook, theAwarenessSystem/AwarenessDatasurface and the Harmony id are all unchanged and frozen. - Both can now optionally drop their reflection probing in favour of
SoMInterop. SeeMIGRATION-for-mod-authors.md. AnimalAI(passive wildlife) remains out of scope.
The Stealth Overmind Update — internal
Previously numbered 2.0.0. Renumbered because that version was never released and the number now belongs to the first public build above.
- Massive performance boost. AI stealth calculations decoupled from the main game loop and moved to a background engine, removing frame drops during large encounters.
- Dynamic AI reaction rates based on distance to the player — immediate up close, cheaper far away.
- ServerSync integration. Gameplay settings sync from host to clients.
StealthExemptionhook — a generic ZDO-based opt-out letting other mods exempt individual creatures, falling back to pure vanilla AI. Absolute-enforcement AI patching.- Architectural overhaul of the Stealth Brain into modular components: State, Senses, Combat, Movement, Fleeing.
- Stealth AI pathing fixes — suspicious slowdowns and alerted engagement wired into creature actions.
- Stealth UI decoupled from the debug system onto its own
EnableStealthUIsetting. - Event-driven memory safety replacing periodic cleanup; dead enemies purged immediately.
- Config consolidation into a single unified format.
- Fixed
eye.pngfailing to load due to Unity reflection changes, which made the gem vanish.
1.1.0 – 1.9.0 — the 1.x line
Grouped by theme. The project was not under version control during this period and these changes cannot honestly be attributed to individual releases.
The Stealth Brain
- Replaced the original single detection value with a ten-phase decision engine: detect, evaluate alertness, assess health, decide flight, find allies, plan movement, choose combat tactics, coordinate, pick an action, finalise.
- Split into single-responsibility evaluators —
StateEvaluator,SensingEvaluator,CombatEvaluator,MovementEvaluator,FleeEvaluator. - Added the four-rung alertness ladder — Unaware, Suspicious, Alerted, Engaged — with configurable thresholds and separate gain and decay rates.
Sensing
- Vision cones with configurable half-angle and range.
- Line-of-sight raycasting against the same layer mask vanilla uses.
- Light and shadow: standing in light raises visibility, shadow lowers it.
- Weather and fog reductions to both sight and hearing.
- Grass, bush and biome-based hiding and camouflage, sampled from real world vegetation.
- A noise model — movement, armour weight, crouching, weather masking.
- Armour classification driving both visibility and noise, with a generated catalogue covering modded armour.
Behaviour
- Search and investigate behaviour: creatures move to your last known position through vanilla's own pathfinder instead of beelining into walls.
- Search-pace slowdown so a searching creature does not sprint.
- Health-based fleeing with a strategic-retreat tier.
- Group coordination — a creature that spots you can alert nearby allies within a radius.
- Give-up and memory decay timers.
Multiplayer and compatibility
- Ownership checks so AI is only driven by the peer that owns the creature.
- The
StealthExemptionZDO hook and theAwarenessSystem/AwarenessDatapublic surface that Mists of Avalor and Dvergr Allies build against. - Compatibility work with Mists of Avalor's own AI patches.
Interface
- The stealth gem: an eye icon whose colour tracks alertness and whose size tracks visibility.
- The noise meter with a green-to-red fill.
- Draggable, position-persisting HUD elements.
- A debug overlay and per-system debug logging.
1.0.0
- Initial public release.
