COWMODSКаталог модов

PathWeaver

Mob pathfinding runs on the server thread and causes tick spikes. PathWeaver moves it to spare CPU cores: mean tick roughly halved with 1024 mobs, worst-1% ticks down 55-61%. Server-side, clients need nothing. Read the warning before installing.

Автор: CasualZ1,4 тыс.8обновлён 13 окт. 2026 г.
ОптимизацияУтилиты

Описание

PathWeaver

Minecraft works out mob paths on the same thread that runs everything else. This moves that work off it.

Every time a mob decides where to walk, the server thread stops and does the maths. A few hundred mobs deciding at once is a few hundred searches the tick waits for, and that wait is what you feel.

PathWeaver runs those searches on spare cores instead. The mob gets the path it would have got, with a few exceptions listed further down; the tick just stops waiting for it.

What that is worth, measured rather than asserted: about 4 to 12% of server tick time with hundreds to thousands of zombies chasing a player, and a great deal more if your mobs repath constantly. Pathfinding is a few percent of a loaded server's tick, and this moves about three quarters of it off the main thread. The runs behind those figures are linked below.

That is a real saving and it is not a rescue. If your server is at 200 ms a tick, this will not save it, and the page tells you how to find out what your own number is before you install anything.

Free, and it does not change what paths your mobs take.

It needs Fabric API and nothing else. Cloth Config is optional and only draws the settings screen; without it the mod reads and writes the same config/pathweaver.json and behaves the same. A dedicated server never shows a settings screen, so it should never have had to install one.

Why a 6% mod is worth installing

Tick time you get back is budget you can spend. The point of taking a fixed cost off the main thread is not the percentage on its own, it is that the work no longer has to be cheap: once path searches are not blocking the tick, a server can afford more mobs, or more expensive pathfinding, than it could before.

This is the first of a planned set of mods that each take one fixed cost off the tick the same way, measured the same way, so the savings compound instead of competing. Where a thing cannot be moved off the tick safely, we say so rather than shipping it anyway.


Getting started

Install onThe server, or your singleplayer world. Clients need nothing
NeedsFabric, Minecraft 26.1.1 / 26.1.2 / 26.2 / 26.3, Java 25 or newer
Also needsFabric API. Nothing else
OptionalCloth Config and ModMenu, for the in-game settings screen
ThenPlay. Run /pathweaver status to see what it is doing

Most hosts still default to Java 21, so check yours before you file a bug.

Worth ten minutes before you install: is pathfinding actually your bottleneck? This mod only helps a server whose tick time is going into mob path searches, and plenty of struggling servers are slow for some other reason.

It ships with its compatibility checking turned off, which means it runs other mods' pathfinding code on worker threads. Back up worlds you care about, and read Compatibility before you commit a world to it.


What you get

Mob farms and crowdsStutters cut roughly in half
Server threadRoughly half the sampled pathfinding work
VillagesVillager pathing comes off the tick too
Mob behaviourSame routes in ordinary play. Villagers set off a tick later, and route sharing can hand one mob a route another computed
Quiet serverNo difference. This does nothing until mobs are actually pathing

This is spike reduction, not free TPS. A server sitting at "20 TPS" still stutters when one tick in a hundred takes 80 ms, and that is the number this moves. Average throughput only rises when pathfinding alone is already blowing the 50 ms tick budget and you have spare cores.

On a machine with two cores or fewer, PathWeaver tells you at world start to leave it off. At four or fewer it warns the gain will be small. It never switches itself off.


The numbers

Two scenarios, because the honest answer is that it depends on how much pathfinding your server is actually doing, and quoting only the flattering one is how this page used to oversell itself.

A busy server: 4 to 12% of tick time

Zombies chasing a player who is teleported every 11 seconds, so the whole crowd has to find a new route at once, on a 219-mod server, measured on the jar you download. Median tick, the middle of three runs each way:

zombieswithoutwithgain
50010.1 ms8.9 ms12%
100018.2 ms16.7 ms8%
250045.8 ms43.3 ms5.5%
5000106.9 ms102.7 ms4%
10000258 ms246 ms4.5%

The run-to-run spread is wider than the gain, because the test machine itself sped up partway through the series, for both arms alike. Compared back to back instead, each run with the mod against the run without it next to it, PathWeaver was faster in every pair from 2500 zombies up.

Why it is that size: in a profile at 5000 zombies, pathfinding was about 6% of server tick time, and PathWeaver moved about three quarters of it off the tick (6.12% to 1.55%). The gain follows from that and could not be much larger. That profile was taken in September, with the zombies wandering rather than chasing.

Mobs that repath constantly: much larger

1024 zombies in a walled maze with the target moving every 6 ticks, so every mob recomputes almost continuously:

OffOn
Mean tick88.5 to 96.6 ms50.0 to 50.3 ms
Worst 1% of ticks832 to 958 ms367 to 383 ms
Main-thread cost per search480 to 500 us195 to 202 us

This is a deliberately pathfinding-heavy case. It is what a mob farm or a large hostile group tracking a moving player looks like, and if that is your server the first table understates what you get. It is not what an average server looks like, and earlier versions of this page presented it as though it were.

What decides which end you land on

The share of your tick that is pathfinding, and nothing else. docs/IS-IT-YOUR-BOTTLENECK.md is a ten-minute check with spark that tells you your own number before you install anything. If pathfinding is 1% of your tick, this mod can win you at most 1%.

Two things that could make your result differ from ours

Cores. These were measured on a 32-core machine with cores to spare. PathWeaver does not delete work, it moves it: the searches still happen, on worker threads, and the tick stops waiting for them. That trade needs somewhere for the work to go. On a host with 2 to 4 cores and everything else already competing for them, the gain will be smaller than ours, and we have not measured that case. On a machine with more spare cores than ours, it could be larger.

Your mods. Our measurement ran on a 219-mod server, so the denominator includes everything that pack does. A lighter server spends a larger share of its tick on mobs, which moves the percentage up.

Method, settings, controls and the raw rows are in the repository under docs/evidence/perf-2026-10/, with the rules for reading them written down before the first run. If the numbers look wrong, the working is there to check.


What changes about your mobs

Villagers and other brain-driven mobs set off one tick later than they used to. On the tick their search is dispatched their behaviour is told "no path yet", and the route arrives on the next one. Nothing else differs.

That is a real behaviour change, which is why it is a setting rather than something you get regardless. brainSinkAsync=false turns it off. The warden is not covered either way, because its navigation builds a custom pathfinder.

Everything else keeps the path it would have had, with three exceptions. A mob whose target moved by a block or less keeps the path it already has instead of getting a new one: repathToleranceBlocks, 1 by default, and 0 turns it off. Earlier versions of this page left that one out. A shared route is used when route sharing is switched on. And the search runs against the world as it was a tick or two earlier rather than at the instant the mob asks. The first can leave a mob heading for a spot one block from where it was sent; the other two do not change where it is trying to go.

Redoing distant path searches less often

New in 0.9.0, and off by default. When a block changes on the route a mob is walking, the game redoes that mob's whole path search. It already refuses to do this more than once a second for any one mob. But in a place where terrain keeps changing, every mob whose route crosses the change pays that cost, whether or not anyone is near enough to see the result.

lodEnabled widens the limit for mobs beyond 64 blocks from every player: one search every 40 ticks instead of the game's once a second. Both numbers are settings, and anything at or below 21 ticks does nothing at all, because that is the game's own floor.

It ships off because it is the only thing here that keeps a mob walking a route after the ground under it has changed. A throttled mob keeps walking that out-of-date route for longer. Worth turning on for mob farms, penned herds near redstone, or a high simulation distance.

The only number for it is a best case. In a test built to favour it, 400 zombies at least 70 blocks from the player with terrain changing among them all the time, it cut the path searches PathWeaver started by 13 to 19% and did not measurably change tick time. What it saves on your server depends on how much terrain changes around mobs nobody is standing near, and for a mob in quiet surroundings it saves nothing, because the game never redoes its search at all.

Route sharing

One mob can reuse a route another mob already computed, but only when every input to the search is identical: same starting position, same target, same size, same terrain costs, same movement flags. A stored route is dropped when a block changes along it while the cache is running.

One honest limit remains: a block changed away from the route can open a shorter way through that a reused route will not take, which vanilla does not notice either.

The other one is fixed here. In 0.8.0 and 0.8.1, switching route sharing or the master switch off and on again inside a route's two-second lifetime could keep a route across changes made while it was off, because PathWeaver stops watching for block changes with the feature while stored routes lived until the server stopped. Both switches now discard what was learned under the old settings, including searches still in flight.

It ships measuring rather than serving. How often mobs repeat a search depends on your world, not on this mod. On the default setting PathWeaver fills the cache, counts what sharing would have saved, and hands out nothing, so /pathweaver status tells you what it is worth on your server before you spend it. Set resultCacheMode to SERVE when the number justifies it. Takes effect immediately.

On the benchmark the hit rate was 12 to 16%. What that is worth is unresolved, and this page previously said otherwise. The measured difference against the cache switched off was about 3% of sampled pathfinding with the run ranges overlapping, on an arena whose arms did not run identical populations and whose arm order was fixed rather than counterbalanced. That is not enough to establish a saving. The test arena was also 200 mobs walking corridors without stopping, close to the worst case for this feature; mobs that stand still and re-ask are what it helps, and that is not what got measured.

This is the reason it ships measuring rather than serving. /pathweaver status counts what serving would have found on YOUR world, which is a better number than anything here.


Compatibility

The default runs other mods' uninspected pathfinding code on worker threads.

That is deliberate. The checked tier, compatibilityTier=AUDITED, only trusts mods whose bytecode has been audited, and on a real modpack it denies everything and the mod does nothing. Measured on a 221-jar pack: 0 of 187 mob types eligible at that tier, against 184 of 187 at the default. Shipping the safe-looking tier by default would ship something indistinguishable from broken.

What has actually happened so far: this has run on packs of 200 to 371 mods through hundreds of thousands of searches, with no corruption or crash traced to it. That is an absence of reported problems rather than a proof, and it is also what you would see if the failure were rare or quiet. Try it on a world you can throw away.

If something does look wrong, switch to compatibilityTier=AUDITED and report it. Be clear about what that does on a heavy pack: it turns the speed-up off entirely. That is the tier working as designed, not failing. trustedMods is the middle option, naming specific mods you have decided about while the scan keeps checking the rest.

The checked tier depends on which download you have

Each audit is pinned to the exact bytes of the mod and the vanilla classes its proof reads, so a build for one Minecraft version cannot vouch for another. There are three downloads and they differ here:

  • The 26.1.2 download, on 26.1.1 or 26.1.2: all seven audits verify.
  • The 26.2 download, on 26.2: all seven audits verify, after Lithium and Diagonal Blocks were re-derived against the builds that ship for 26.2.
  • The 26.3 download, on 26.3: every audit verifies except Lithium. Lithium's 26.3 build changed code the audit covers, and it is not certified until that change has been checked. With Lithium installed and AUDITED on, PathWeaver stands down rather than run it unchecked.

Install the download that matches your Minecraft version. Install one on a different version and the pins refuse, which turns the speed-up off rather than running anything unchecked.

Either way this only matters if you have opted into AUDITED. The shipped default consults none of it.

Whatever version you are on, mods that modify pathfinding are named at world start, with what PathWeaver decided about each.


Settings

SettingDefaultWhat it does
enabledonMaster switch
compatibilityTierUNSAFEWhether to check other mods before running their code off-threadrestart
brainSinkAsynconVillager-type pathing off the tick, at one tick of delay
resultCacheModeSHADOWRoute sharing. SHADOW measures, SERVE spends it
repathToleranceBlocks1Reuse a mob's current path when its target moved less than this
poolThreadsautoWorker threads. Auto is a quarter of your CPU threads, minimum tworestart
lodEnabledoffRedo distant mobs' path searches less often
lodMinDistanceBlocks64How far from a player that starts
lodIntervalTicks40Ticks between searches for a throttled mob. Below 21 does nothing

All of them live in config/pathweaver.json. Install ModMenu and Cloth Config if you want to edit them in game instead; neither is required and a server needs neither. The two marked restart are read once at startup; the rest take effect as soon as you save.


Checking it is doing something

/pathweaver status reports what is dispatching, what is landing, and what route sharing would save. /pathweaver mobs lists which of your mob types are eligible.

Route sharing is reported as two numbers rather than one. Searches skipped is searches that did not run, which is the whole saving. Hits that saved nothing is real cache hits with no stored route behind them, which is what you get while the cache is measuring. Before 0.9.0 those were added together under the first label, so the figure you would have used to decide about SERVE was too large.

Eligible means nothing blocks dispatch for that mob, not that every movement it makes goes off-thread. On a 221-jar pack at the shipped default it is 184 of 187; the three held back navigate with a custom pathfinder rather than the stock one.

How many dispatched searches get used depends on load. Roughly 99% on a quiet server, 96% under normal play, about 82% in the saturated 1024-mob benchmark, where the mod deliberately refuses requests rather than queue ones that would land too late to be worth having.


Corrections

Published claims should not quietly change, so here is what was wrong. The raw benchmark artifacts they came from are unchanged in the repository.

Route sharing could keep a route across a settings toggle. Switching it or the master switch off and on again inside a route's lifetime could hand out a route computed before terrain changed while nothing was watching. In 0.8.0 and 0.8.1, reachable from the settings screen with no restart. Fixed in 0.9.0. Only affects you if you turned route sharing on; the shipped default measures rather than serves.

"Searches skipped" was two numbers added together. Cache hits with no stored route behind them skip nothing, and they were counted in the same figure as searches that really did not run. If you read that line in 0.7.0, 0.8.0 or 0.8.1 to decide whether route sharing was worth switching on, the number was larger than the saving. It is now two lines and only the first is a saving.

A setting screen inside the 0.8.x jars says a reused route "is never a stale one". A page edit cannot reach text compiled into a release. 0.9.0 changes it to what holds: a route is dropped when a block changes along it, and a change away from the route is not noticed, as in vanilla.

A permission check that was described but never existed. /pathweaver mobs builds one of every registered mob type to report which are eligible, which takes about a fifth of a second on a large pack, on the server thread. It was meant to need operator level: the source comment said so and the 0.7.0 notes said so. It did not, so any player on any server could run it repeatedly. Fixed in 0.8.1. /pathweaver status stays open to everyone, since that is the one the docs tell you to run. If you host a multiplayer server on 0.7.0 or 0.8.0, this is the reason to update.

"CPU" and "A*". The profiler samples thread stacks every 4 ms and counts how often something is on the stack, waiting included. It does not measure CPU time, and the classifier covers navigation and pathfinding broadly rather than the A* search alone. Figures once labelled "total CPU" and "server-thread A*" are sampled broad pathfinding, relabelled above. The direction and rough size of the villager result survive the relabelling. The words did not.

The route-sharing saving. An earlier version of this page presented about 3% as a measured gain. It is not established. The two arms did not run identical mob populations and the arm order was fixed rather than counterbalanced, so a small difference with overlapping ranges cannot be pinned on the feature. The 12 to 16% hit rate is real; what serving those hits is worth is unknown.

The busy-server benchmark had no player in it. The table on this page used to say "zombies chasing a player", but in those September runs another mod on the test server removed the test player a second after it joined, so the zombies were wandering. The benchmark was re-run on 2026-10-13 with the player staying put and the zombies really chasing, and the table above is that run. The gain is about the same at 500 to 1000 zombies and smaller at 2500 and up: 4 to 5.5% where the old table said 5 to 9%.

What did not change, because it was checked rather than assumed: the mob-eligibility counts, the audit and compatibility behaviour, the tick-interval benchmark, and the fact that every run with the mod on beat every run with it off on that benchmark.


Known limits

The checked tier does not cover Lithium on 26.3, above. Path quality while blocks are being changed underneath mobs is not measured. Behaviour at a thousand mobs or more is not measured.

Full detail, including what was tried and thrown away, is on GitHub: the README, the changelog and the roadmap.

Последние версии

Все версии →
beta

0.9.0 - Correctness, Cloth optional, distance LOD (26.3)

0.9.0+26.3
13 окт. 2026 г.188Minecraft: 26.3fabric
Скачать
Что нового
Minecraft **26.3** build of 0.9.0. Everything the 26.1.2 changelog describes applies here, with one exception that matters on a performance pack, and one change to the navigation hook that 26.3 forced. ### The hook moved, because vanilla moved 26.3 added `PathNavigation.moveTo(Entity, int, double)`. The old `moveTo(Entity, double)` now does nothing but delegate to it, and `MeleeAttackGoal`, which is what a hostile mob chasing a player runs, calls the new overload directly. PathWeaver's three hooks for entity-target movement therefore sit on the inner overload on this branch: the speed capture, the deferred-acceptance return, and the wrapper around `createPath`. On 26.1.2 and 26.2 they sit on the two-argument method. Nothing about which path a mob gets changes. The request is claimed one level further down the same call, and the delegate returns the inner result unchanged. Left alone, the wrapper would have had no call site to bind to on 26.3. It is declared `require = 1`, so that is a refusal to load rather than a mod that runs with a hole in it. ### `AUDITED` does not cover Lithium on 26.3 Lithium 0.26.2 is the build a 26.3 pack installs, and this release does not audit it. Five of the eight audited classes are byte-identical to the 0.25.3 build audited for 26.2. Three are not: two gained a field writer, and one differs only because 26.3's Mixin declares an injection point as an array. The exemption allows field writes only in constructors, static initializers and one named initializer per class, and the two new writers are not in that set, so certifying 0.26.2 needs an argument about when they run and whether a worker can reach them. Nobody has written that argument. The audit is a statement about exact bytes, so it refuses 0.26.2 by version and says so in the log rather than being re-pinned on a proof nobody ran. What this means in practice. At `compatibilityTier=AUDITED` on 26.3, any pack containing Lithium has every movement family denied, so PathWeaver does nothing. The shipped default is `UNSAFE`, which reads none of this and is unaffected. `LithiumPathfindingCompatibility` states what a 26.3 re-pin has to prove, for whoever picks it up. Diagonal Blocks 26.3.0, ServerCore 1.5.20+26.3, rabbit-pathfinding-fix 1.5.0 and both Fabric API modules are audited on 26.3, all re-derived against the artifacts a 26.3 install resolves. ### Verified on 26.3 - 69 suites, 515 unit tests, 0 failures - 9 of 9 game-test harnesses, one attempt each and no reruns, every row checked against the manifest it actually consumed and the providers on its classpath at launch: 21 tests (`docs/evidence/port-26.3/HARNESS-26.3.txt`) - a real 26.3 client with an integrated server: searches dispatch and install, and the settings screen draws (`docs/evidence/port-26.3/CLIENT-26.3.txt`) - a clean 26.3 server without Cloth Config starts with PathWeaver active, and a control build with the old Cloth dependency put back fails to start (`docs/evidence/port-26.3/no-cloth/`) - all 36 of the 0.9.0 four-state witnesses re-run here, each fix reverted and its test seen to fail for the expected reason (`docs/evidence/port-26.3/WITNESS-26.3.txt`), plus two more for the two things 26.3 broke: the navigation hook and the manifest range - the jar was built from a fresh clone, and its declared versions were read back out of the built jar (`docs/evidence/port-26.3/RELEASE-JAR.txt`) ### Also worth knowing 26.3's Mixin declares `@Redirect.at()` as an `At[]` rather than a single `At`. That is invisible in production code and broke three of our own annotation readers, which now reject a redirect declaring more than one injection point instead of reading the first of several. Two dependency traps, in case they bite you too. ServerCore publishes `1.5.20+26.3` twice on Modrinth, once for Fabric and once for NeoForge, and a Maven coordinate on the version number can resolve the NeoForge jar: it carries the same mixin class and no `fabric.mod.json`. And both Fabric API modules this mod audits now differ byte-for-byte between the standalone artifact and the copy nested inside the aggregate `fabric-api` jar, so the audit accepts either packaging and pins the mixin bytes exactly. If you run ServerCore, make sure it is the 26.3 Fabric build. --- # Everything in 0.9.0 Correctness and honesty, a per-search cost removed from searches that stay on the server thread, and two changes you will notice: Cloth Config is no longer required, and there is a new optional setting for distant mobs. ## Searches PathWeaver leaves on the server thread no longer pay for it Some path searches stay on the server thread: villagers looking for a bed or a workplace, which use the answer straight away, and any mob PathWeaver decides not to take. Those searches were slower than with no PathWeaver at all. Two checks ran once for every node of every search, on every thread, including the ones they had nothing to say about: a thread-local lookup, and a hook that created a small object on every call. Both are in 0.8.0 too; only the 0.9.0 build was measured. Both are gone. In a 317-mod client with a village, villager point-of-interest searches took 24 to 30% of the server tick in every run with the old build, 20 to 24% with no PathWeaver, and 23 to 26% with this one. It is a few percent of tick, not a lag spike, but it was a cost on exactly the searches this mod cannot move off the thread. **The lag report that led here was not PathWeaver.** In that pack, Enhanced Cats sends every villager within 10 blocks of a cat towards it, every tick, on the client as well as the server, and the game lagged with PathWeaver removed too. If your game lags when cats are near villagers, try without that mod before blaming this one. ## Route sharing survives a settings change Switching route sharing or the master switch off and on again could leave a stored route in play across changes made while it was off. PathWeaver stops watching for block changes when either switch is off, but stored routes were only discarded when the server stopped, so a route could be handed out after terrain nobody had been watching moved underneath it. Both switches now discard what was learned under the previous settings, including searches that were already in flight when you changed them. This was reachable from the settings screen in 0.8.0 and 0.8.1 with no restart, and it is the reason to update if you had turned route sharing on. ## Villager paths at the age limit are no longer thrown away A finished search that arrived at exactly the configured age limit was accepted by one part of the mod and rejected by another, so the work was done and discarded and the mob ran its own search anyway. At `maxResultAgeTicks=1`, which the settings allow, that was every result except the ones that finished within the same tick they were dispatched. Default settings were affected far less than that, but the wasted searches were real. ## A villager path from the future If server time moved backwards, on a world reload or a rollback, a finished path already set aside for a villager could still be handed to it, answering a question asked before the search was dispatched. The check that refuses a result from the future ran when the result arrived and not when it was collected, and those are the same rule at two different moments. ## `/pathweaver status` stops overstating route sharing The line reporting how many searches route sharing skipped was adding together searches that really did not run and cache hits that saved nothing. Hits recorded while the cache was measuring have no stored route to hand out, so they skip nothing. They are now on their own line, and only the first number is a saving. The cache capacity shown was the one in your settings file rather than the one in use. Capacity is fixed when the server starts, so if you changed it since, the screen now says the change is waiting for a restart. **If you decided against `SERVE` on the old number, the honest one is smaller.** If you decided for it, look again. ## The route sharing tooltip was too strong The settings screen said a reused route "is never a stale one". It now says what actually holds: a route is dropped when a block changes along it, and a change away from the route is not noticed, exactly as vanilla does not notice it either. The old wording is in the 0.8.0 and 0.8.1 jars where no page edit could reach it. ## Settings files are checked properly `resultCacheMode`, `resultCacheMaxAgeTicks` and `resultCacheMaxEntries` were not type-checked when the config was read, so a hand-edited mistake in one of them was quietly coerced instead of reported. Every persisted setting is now checked, and the check is derived from the settings themselves rather than a list that had already fallen behind three times. ## Compatibility checking The Lithium audit now pins the vanilla pathfinding class it inspects by hash, like the other audits do. It previously inspected whatever was loaded, on the argument that re-deriving the check each time was stronger than pinning it. It is not: that check reads one class and does not follow what that class calls, so on a changed class it would have reported nothing while proving less than it looked like it proved. No compatibility outcome changes as a result, on any version. Both downloads verify all seven audits on the Minecraft version they are built for; see the project page for what happens if you install the wrong one. ## New: is pathfinding even your problem? [A ten-minute check](https://github.com/zimdin12/PathWeaver/blob/master/docs/IS-IT-YOUR-BOTTLENECK.md) you can run before installing this mod, using spark. PathWeaver only helps a server whose tick time is going into mob path searches, and plenty of struggling servers are slow for some other reason. It also says how to read the profile without the two mistakes that are easy to make with it. ## Cloth Config is no longer required PathWeaver needed Fabric API and Cloth Config. Cloth Config draws the settings screen, which a dedicated server never shows, so every server owner was installing a GUI library to run a server-side mod. It now needs Fabric API and nothing else. Install Cloth Config if you want the settings screen; without it the mod reads and writes the same `config/pathweaver.json` and behaves identically. Nothing about your existing config file changes and no setting is lost. ## New, and off by default: redo distant path searches less often When a block changes on the route a mob is walking, the game redoes that mob's whole path search. It will not do it more often than once a second for any one mob, but in a place where terrain keeps changing, every mob whose route crosses the change pays for it, whether anyone is near enough to see it or not. `lodEnabled` widens that limit for mobs beyond 64 blocks from every player: one search every 40 ticks instead of the game's once a second. Both numbers are settings. A mob picking a new destination is never affected; this only delays redoing a route the mob already has. **It ships off, and that is deliberate.** It is the only setting in this mod that keeps a mob walking a route after the ground under it has changed. (An earlier version of this changelog said everything else gives a mob the path it would have had anyway. That was too strong: by default a mob whose target moved by a block or less keeps its current path, `repathToleranceBlocks=1`.) This lets a distant mob keep walking an out-of-date route for longer after the ground under it changes. That is bounded and remote, but it is a real difference, so it is offered rather than taken. Worth turning on for mob farms, penned herds near redstone, or a high simulation distance. It does nothing at all for mobs whose surroundings are not changing, because the game never redoes their search in the first place. ## Not in this release No change to the mod's core numbers. This exact jar was put back through the benchmark against 0.8.0 and against no mod: it is no slower than 0.8.0. Re-measured on 2026-10-13 with the zombies really chasing a player (the September runs had lost their test player), it saves 4 to 5.5% of tick time at 2500 to 10000 zombies and 8 to 12% at 500 to 1000. This line used to say 5 to 9%. For LOD there is only a best case. In a test built to favour it, 400 zombies at least 70 blocks from the player with terrain changing among them all the time, turning it on cut the path searches PathWeaver started by 13 to 19% and did not measurably change tick time. What it saves on your server depends on how much terrain changes around mobs nobody is standing near, and in a world where it does not change, it saves nothing.
beta

0.9.0 - Correctness, Cloth optional, distance LOD (26.2)

0.9.0+26.2
14 сент. 2026 г.270Minecraft: 26.2fabric
Скачать
Что нового
Correctness and honesty, a per-search cost removed from searches that stay on the server thread, and two changes you will notice: Cloth Config is no longer required, and there is a new optional setting for distant mobs. ## Searches PathWeaver leaves on the server thread no longer pay for it Some path searches stay on the server thread: villagers looking for a bed or a workplace, which use the answer straight away, and any mob PathWeaver decides not to take. Those searches were slower than with no PathWeaver at all. Two checks ran once for every node of every search, on every thread, including the ones they had nothing to say about: a thread-local lookup, and a hook that created a small object on every call. Both are in 0.8.0 too; only the 0.9.0 build was measured. Both are gone. In a 317-mod client with a village, villager point-of-interest searches took 24 to 30% of the server tick in every run with the old build, 20 to 24% with no PathWeaver, and 23 to 26% with this one. It is a few percent of tick, not a lag spike, but it was a cost on exactly the searches this mod cannot move off the thread. **The lag report that led here was not PathWeaver.** In that pack, Enhanced Cats sends every villager within 10 blocks of a cat towards it, every tick, on the client as well as the server, and the game lagged with PathWeaver removed too. If your game lags when cats are near villagers, try without that mod before blaming this one. ## Route sharing survives a settings change Switching route sharing or the master switch off and on again could leave a stored route in play across changes made while it was off. PathWeaver stops watching for block changes when either switch is off, but stored routes were only discarded when the server stopped, so a route could be handed out after terrain nobody had been watching moved underneath it. Both switches now discard what was learned under the previous settings, including searches that were already in flight when you changed them. This was reachable from the settings screen in 0.8.0 and 0.8.1 with no restart, and it is the reason to update if you had turned route sharing on. ## Villager paths at the age limit are no longer thrown away A finished search that arrived at exactly the configured age limit was accepted by one part of the mod and rejected by another, so the work was done and discarded and the mob ran its own search anyway. At `maxResultAgeTicks=1`, which the settings allow, that was every result except the ones that finished within the same tick they were dispatched. Default settings were affected far less than that, but the wasted searches were real. ## A villager path from the future If server time moved backwards, on a world reload or a rollback, a finished path already set aside for a villager could still be handed to it, answering a question asked before the search was dispatched. The check that refuses a result from the future ran when the result arrived and not when it was collected, and those are the same rule at two different moments. ## `/pathweaver status` stops overstating route sharing The line reporting how many searches route sharing skipped was adding together searches that really did not run and cache hits that saved nothing. Hits recorded while the cache was measuring have no stored route to hand out, so they skip nothing. They are now on their own line, and only the first number is a saving. The cache capacity shown was the one in your settings file rather than the one in use. Capacity is fixed when the server starts, so if you changed it since, the screen now says the change is waiting for a restart. **If you decided against `SERVE` on the old number, the honest one is smaller.** If you decided for it, look again. ## The route sharing tooltip was too strong The settings screen said a reused route "is never a stale one". It now says what actually holds: a route is dropped when a block changes along it, and a change away from the route is not noticed, exactly as vanilla does not notice it either. The old wording is in the 0.8.0 and 0.8.1 jars where no page edit could reach it. ## Settings files are checked properly `resultCacheMode`, `resultCacheMaxAgeTicks` and `resultCacheMaxEntries` were not type-checked when the config was read, so a hand-edited mistake in one of them was quietly coerced instead of reported. Every persisted setting is now checked, and the check is derived from the settings themselves rather than a list that had already fallen behind three times. ## Compatibility checking The Lithium audit now pins the vanilla pathfinding class it inspects by hash, like the other audits do. It previously inspected whatever was loaded, on the argument that re-deriving the check each time was stronger than pinning it. It is not: that check reads one class and does not follow what that class calls, so on a changed class it would have reported nothing while proving less than it looked like it proved. No compatibility outcome changes as a result, on any version. Both downloads verify all seven audits on the Minecraft version they are built for; see the project page for what happens if you install the wrong one. ## New: is pathfinding even your problem? [A ten-minute check](https://github.com/zimdin12/PathWeaver/blob/master/docs/IS-IT-YOUR-BOTTLENECK.md) you can run before installing this mod, using spark. PathWeaver only helps a server whose tick time is going into mob path searches, and plenty of struggling servers are slow for some other reason. It also says how to read the profile without the two mistakes that are easy to make with it. ## Cloth Config is no longer required PathWeaver needed Fabric API and Cloth Config. Cloth Config draws the settings screen, which a dedicated server never shows, so every server owner was installing a GUI library to run a server-side mod. It now needs Fabric API and nothing else. Install Cloth Config if you want the settings screen; without it the mod reads and writes the same `config/pathweaver.json` and behaves identically. Nothing about your existing config file changes and no setting is lost. ## New, and off by default: redo distant path searches less often When a block changes on the route a mob is walking, the game redoes that mob's whole path search. It will not do it more often than once a second for any one mob, but in a place where terrain keeps changing, every mob whose route crosses the change pays for it, whether anyone is near enough to see it or not. `lodEnabled` widens that limit for mobs beyond 64 blocks from every player: one search every 40 ticks instead of the game's once a second. Both numbers are settings. A mob picking a new destination is never affected; this only delays redoing a route the mob already has. **It ships off, and that is deliberate.** It is the only setting in this mod that keeps a mob walking a route after the ground under it has changed. (An earlier version of this changelog said everything else gives a mob the path it would have had anyway. That was too strong: by default a mob whose target moved by a block or less keeps its current path, `repathToleranceBlocks=1`.) This lets a distant mob keep walking an out-of-date route for longer after the ground under it changes. That is bounded and remote, but it is a real difference, so it is offered rather than taken. Worth turning on for mob farms, penned herds near redstone, or a high simulation distance. It does nothing at all for mobs whose surroundings are not changing, because the game never redoes their search in the first place. ## Not in this release No change to the mod's core numbers. This exact jar was put back through the benchmark against 0.8.0 and against no mod: it is no slower than 0.8.0. Re-measured on 2026-10-13 with the zombies really chasing a player (the September runs had lost their test player), it saves 4 to 5.5% of tick time at 2500 to 10000 zombies and 8 to 12% at 500 to 1000. This line used to say 5 to 9%. For LOD there is only a best case. In a test built to favour it, 400 zombies at least 70 blocks from the player with terrain changing among them all the time, turning it on cut the path searches PathWeaver started by 13 to 19% and did not measurably change tick time. What it saves on your server depends on how much terrain changes around mobs nobody is standing near, and in a world where it does not change, it saves nothing.
beta

0.9.0 - Correctness, Cloth optional, distance LOD (26.1.2)

0.9.0+26.1.2
14 сент. 2026 г.77Minecraft: 26.1.1, 26.1.2fabric
Скачать
Что нового
Correctness and honesty, a per-search cost removed from searches that stay on the server thread, and two changes you will notice: Cloth Config is no longer required, and there is a new optional setting for distant mobs. ## Searches PathWeaver leaves on the server thread no longer pay for it Some path searches stay on the server thread: villagers looking for a bed or a workplace, which use the answer straight away, and any mob PathWeaver decides not to take. Those searches were slower than with no PathWeaver at all. Two checks ran once for every node of every search, on every thread, including the ones they had nothing to say about: a thread-local lookup, and a hook that created a small object on every call. Both are in 0.8.0 too; only the 0.9.0 build was measured. Both are gone. In a 317-mod client with a village, villager point-of-interest searches took 24 to 30% of the server tick in every run with the old build, 20 to 24% with no PathWeaver, and 23 to 26% with this one. It is a few percent of tick, not a lag spike, but it was a cost on exactly the searches this mod cannot move off the thread. **The lag report that led here was not PathWeaver.** In that pack, Enhanced Cats sends every villager within 10 blocks of a cat towards it, every tick, on the client as well as the server, and the game lagged with PathWeaver removed too. If your game lags when cats are near villagers, try without that mod before blaming this one. ## Route sharing survives a settings change Switching route sharing or the master switch off and on again could leave a stored route in play across changes made while it was off. PathWeaver stops watching for block changes when either switch is off, but stored routes were only discarded when the server stopped, so a route could be handed out after terrain nobody had been watching moved underneath it. Both switches now discard what was learned under the previous settings, including searches that were already in flight when you changed them. This was reachable from the settings screen in 0.8.0 and 0.8.1 with no restart, and it is the reason to update if you had turned route sharing on. ## Villager paths at the age limit are no longer thrown away A finished search that arrived at exactly the configured age limit was accepted by one part of the mod and rejected by another, so the work was done and discarded and the mob ran its own search anyway. At `maxResultAgeTicks=1`, which the settings allow, that was every result except the ones that finished within the same tick they were dispatched. Default settings were affected far less than that, but the wasted searches were real. ## A villager path from the future If server time moved backwards, on a world reload or a rollback, a finished path already set aside for a villager could still be handed to it, answering a question asked before the search was dispatched. The check that refuses a result from the future ran when the result arrived and not when it was collected, and those are the same rule at two different moments. ## `/pathweaver status` stops overstating route sharing The line reporting how many searches route sharing skipped was adding together searches that really did not run and cache hits that saved nothing. Hits recorded while the cache was measuring have no stored route to hand out, so they skip nothing. They are now on their own line, and only the first number is a saving. The cache capacity shown was the one in your settings file rather than the one in use. Capacity is fixed when the server starts, so if you changed it since, the screen now says the change is waiting for a restart. **If you decided against `SERVE` on the old number, the honest one is smaller.** If you decided for it, look again. ## The route sharing tooltip was too strong The settings screen said a reused route "is never a stale one". It now says what actually holds: a route is dropped when a block changes along it, and a change away from the route is not noticed, exactly as vanilla does not notice it either. The old wording is in the 0.8.0 and 0.8.1 jars where no page edit could reach it. ## Settings files are checked properly `resultCacheMode`, `resultCacheMaxAgeTicks` and `resultCacheMaxEntries` were not type-checked when the config was read, so a hand-edited mistake in one of them was quietly coerced instead of reported. Every persisted setting is now checked, and the check is derived from the settings themselves rather than a list that had already fallen behind three times. ## Compatibility checking The Lithium audit now pins the vanilla pathfinding class it inspects by hash, like the other audits do. It previously inspected whatever was loaded, on the argument that re-deriving the check each time was stronger than pinning it. It is not: that check reads one class and does not follow what that class calls, so on a changed class it would have reported nothing while proving less than it looked like it proved. No compatibility outcome changes as a result, on any version. Both downloads verify all seven audits on the Minecraft version they are built for; see the project page for what happens if you install the wrong one. ## New: is pathfinding even your problem? [A ten-minute check](https://github.com/zimdin12/PathWeaver/blob/master/docs/IS-IT-YOUR-BOTTLENECK.md) you can run before installing this mod, using spark. PathWeaver only helps a server whose tick time is going into mob path searches, and plenty of struggling servers are slow for some other reason. It also says how to read the profile without the two mistakes that are easy to make with it. ## Cloth Config is no longer required PathWeaver needed Fabric API and Cloth Config. Cloth Config draws the settings screen, which a dedicated server never shows, so every server owner was installing a GUI library to run a server-side mod. It now needs Fabric API and nothing else. Install Cloth Config if you want the settings screen; without it the mod reads and writes the same `config/pathweaver.json` and behaves identically. Nothing about your existing config file changes and no setting is lost. ## New, and off by default: redo distant path searches less often When a block changes on the route a mob is walking, the game redoes that mob's whole path search. It will not do it more often than once a second for any one mob, but in a place where terrain keeps changing, every mob whose route crosses the change pays for it, whether anyone is near enough to see it or not. `lodEnabled` widens that limit for mobs beyond 64 blocks from every player: one search every 40 ticks instead of the game's once a second. Both numbers are settings. A mob picking a new destination is never affected; this only delays redoing a route the mob already has. **It ships off, and that is deliberate.** It is the only setting in this mod that keeps a mob walking a route after the ground under it has changed. (An earlier version of this changelog said everything else gives a mob the path it would have had anyway. That was too strong: by default a mob whose target moved by a block or less keeps its current path, `repathToleranceBlocks=1`.) This lets a distant mob keep walking an out-of-date route for longer after the ground under it changes. That is bounded and remote, but it is a real difference, so it is offered rather than taken. Worth turning on for mob farms, penned herds near redstone, or a high simulation distance. It does nothing at all for mobs whose surroundings are not changing, because the game never redoes their search in the first place. ## Not in this release No change to the mod's core numbers. This exact jar was put back through the benchmark against 0.8.0 and against no mod: it is no slower than 0.8.0. Re-measured on 2026-10-13 with the zombies really chasing a player (the September runs had lost their test player), it saves 4 to 5.5% of tick time at 2500 to 10000 zombies and 8 to 12% at 500 to 1000. This line used to say 5 to 9%. For LOD there is only a best case. In a test built to favour it, 400 zombies at least 70 blocks from the player with terrain changing among them all the time, turning it on cut the path searches PathWeaver started by 13 to 19% and did not measurably change tick time. What it saves on your server depends on how much terrain changes around mobs nobody is standing near, and in a world where it does not change, it saves nothing.
beta

0.8.0 - Villagers off the tick, routes worth reusing (26.2)

0.8.0+26.2
6 сент. 2026 г.126Minecraft: 26.2fabric
Скачать
Что нового
Villagers now path off the tick, mobs can reuse each other's routes, and two settings that were switched off by accident are switched on. ## Villagers path off-thread Villagers, piglins, axolotls, frogs, allays, camels and about twenty other brain-driven mobs never called the method PathWeaver was watching. Every route they walked went through a different one, so the mod could not see them at all. They were not being refused; they were invisible. `brainSinkAsync` covers that route and is on by default. **It costs one tick.** A brain mob sets off one tick after it otherwise would, because on the tick its search is dispatched its behaviour is told "no path yet". Nothing else differs. That is why it is a setting: `brainSinkAsync=false` turns it off. Measured on a 231-jar server with 200 mobs, three rounds each way. Server-thread pathfinding went from `4244, 3536, 7328 ms` to `2160, 1984, 2140`, and tick time from `9.05, 6.86, 15.83 ms` to `6.82, 5.68, 6.62`. Every run with it on beat every run without. The spread is the point: without it the arena ran between 6.9 and 15.8 ms per tick, with it between 5.7 and 6.8. The warden is not covered. Its navigation builds a custom pathfinder, and PathWeaver only dispatches for the stock one. ## Mobs can reuse each other's routes When two searches agree on every input they produce the same route, so the second one is repetition. A finished route is now kept and an identical later request is answered from it. Identical is strict. Same starting position, same target, same mob size, same terrain costs, same movement flags. A stored route is dropped the moment a block changes along it. What a mob gets back is what its own search would have returned. **It ships measuring rather than serving.** How often mobs repeat a search depends on your world, so the default counts what sharing would have saved and hands out nothing. Read `/pathweaver status`, then set `resultCacheMode` to Serve if the number justifies it. No restart. On the benchmark the hit rate was 12 to 16%, and sharing dispatched 11% fewer searches. Against not having the mod installed at all, sharing gives 46% less server-thread pathfinding and 10% lower tick time, at 6% more total CPU across every thread. Against the cache being switched off rather than absent it bought about 3%, and those run ranges overlapped. The test arena was 200 mobs walking corridors without stopping, which is close to the worst case for it. ## Two settings that were off by accident **Path reuse was never running.** `repathToleranceBlocks` shipped at 0 and 0 means the reuse never fires. It is 1 now. Upgrading migrates an existing config rather than leaving the fix for new installs, because a saved settings file wins over a default. Any value other than 0 is left alone, and the migration says what it did in the log. **Automatic worker sizing could produce one worker.** A quarter of your CPU threads is a single worker on a four-thread machine, and one worker serialises every search behind the one in front. The floor is two. ## Compatibility `compatibilityTier=AUDITED` did nothing at all on 26.2 before this release, because every audit was pinned to 26.1.2 builds. Four are re-derived and five of the seven now verify there. **Lithium and Diagonal Blocks do not.** On 26.2 they are different builds from the ones the audits were derived from. Lithium alone puts all six movement families back on the server thread, and most performance packs ship Lithium, so treat the checked tier as unusable on 26.2 for now. The shipped default is unaffected, and the world-start report names the mods responsible. ## Also `/pathweaver status` now reports what route sharing is finding. Startup is quieter on a healthy install: the scan used to warn about movement families it then waived a moment later, which was never a real warning.
beta

0.8.0 - Villagers off the tick, routes worth reusing (26.1.2)

0.8.0+26.1.2
6 сент. 2026 г.34Minecraft: 26.1.1, 26.1.2fabric
Скачать
Что нового
Villagers now path off the tick, mobs can reuse each other's routes, and two settings that were switched off by accident are switched on. ## Villagers path off-thread Villagers, piglins, axolotls, frogs, allays, camels and about twenty other brain-driven mobs never called the method PathWeaver was watching. Every route they walked went through a different one, so the mod could not see them at all. They were not being refused; they were invisible. `brainSinkAsync` covers that route and is on by default. **It costs one tick.** A brain mob sets off one tick after it otherwise would, because on the tick its search is dispatched its behaviour is told "no path yet". Nothing else differs. That is why it is a setting: `brainSinkAsync=false` turns it off. Measured on a 231-jar server with 200 mobs, three rounds each way. Server-thread pathfinding went from `4244, 3536, 7328 ms` to `2160, 1984, 2140`, and tick time from `9.05, 6.86, 15.83 ms` to `6.82, 5.68, 6.62`. Every run with it on beat every run without. The spread is the point: without it the arena ran between 6.9 and 15.8 ms per tick, with it between 5.7 and 6.8. The warden is not covered. Its navigation builds a custom pathfinder, and PathWeaver only dispatches for the stock one. ## Mobs can reuse each other's routes When two searches agree on every input they produce the same route, so the second one is repetition. A finished route is now kept and an identical later request is answered from it. Identical is strict. Same starting position, same target, same mob size, same terrain costs, same movement flags. A stored route is dropped the moment a block changes along it. What a mob gets back is what its own search would have returned. **It ships measuring rather than serving.** How often mobs repeat a search depends on your world, so the default counts what sharing would have saved and hands out nothing. Read `/pathweaver status`, then set `resultCacheMode` to Serve if the number justifies it. No restart. On the benchmark the hit rate was 12 to 16%, and sharing dispatched 11% fewer searches. Against not having the mod installed at all, sharing gives 46% less server-thread pathfinding and 10% lower tick time, at 6% more total CPU across every thread. Against the cache being switched off rather than absent it bought about 3%, and those run ranges overlapped. The test arena was 200 mobs walking corridors without stopping, which is close to the worst case for it. ## Two settings that were off by accident **Path reuse was never running.** `repathToleranceBlocks` shipped at 0 and 0 means the reuse never fires. It is 1 now. Upgrading migrates an existing config rather than leaving the fix for new installs, because a saved settings file wins over a default. Any value other than 0 is left alone, and the migration says what it did in the log. **Automatic worker sizing could produce one worker.** A quarter of your CPU threads is a single worker on a four-thread machine, and one worker serialises every search behind the one in front. The floor is two. ## Compatibility `compatibilityTier=AUDITED` did nothing at all on 26.2 before this release, because every audit was pinned to 26.1.2 builds. Four are re-derived and five of the seven now verify there. **Lithium and Diagonal Blocks do not.** On 26.2 they are different builds from the ones the audits were derived from. Lithium alone puts all six movement families back on the server thread, and most performance packs ship Lithium, so treat the checked tier as unusable on 26.2 for now. The shipped default is unaffected, and the world-start report names the mods responsible. ## Also `/pathweaver status` now reports what route sharing is finding. Startup is quieter on a healthy install: the scan used to warn about movement families it then waived a moment later, which was never a real warning.
beta

0.7.0 - Fewer wrong answers, fewer hiding places (26.2)

0.7.0+26.2
31 авг. 2026 г.66Minecraft: 26.2fabric
Скачать
Что нового
Mostly defects. Around twenty of them, found by four parallel read-only hunts over the async, mixin, gate and config packages, then by an adversarial review of the whole diff. ## Player-visible - **Mobs no longer freeze for up to a second after the world changes under them.** Vanilla nulls a mob's path and asks for a new one. Because the answer arrived a tick later, it recorded a recompute that never produced a path, and both of its retry routes then stayed shut for twenty ticks on a mob standing still. Control goes back to vanilla now. - **A goal can no longer be told a mob is reachable using a route to somewhere it abandoned.** While a search is in flight, `path` and `targetPos` name different destinations, and vanilla's own path-reuse check treats them as a pair. Direct queries got the stale route. - **`AUDITED` works on 26.1.1**, not only 26.1.2. The audits now gate on the bytes they pinned rather than on a version label. The pinned vanilla classes are byte-identical on 26.1.1, and different on 26.2, so 26.2 still refuses. - **Workers skip searches nobody wants any more**, instead of computing them and throwing the result away. ## Six ways it could fail open, all live in 0.6.1 - A negative `workerFailureLimit` landed on the documented "never switch anything off" value. That disabled the family-shutdown safety net while the settings screen showed something legal. - A config written before the tier setting existed inherited today's permissive default, moving an operator from "scan armed" to "waive everything" with no log line. - The denial set in `SafetyGate` was public and mutable, so any class on the classpath could clear every scan denial, including the ones a failed scan installs that no tier is allowed to waive. - A mixin config registered after startup was invisible to the scan, because pathfinding classes are not transformed until a world starts. That was the one place where absent evidence produced ALLOW. - One third-party jar with unusual capitalisation in its manifest could make the mod permanently inert, through a scan failure no tier can waive. - Setting `trustedMods` to null made the settings screen unopenable, with no message. ## Reporting `/pathweaver mobs` called a mob eligible when dispatch would have refused it. The status line said breaker-stopped families were "running anyway", contradicting a line three rows above it. Both reporting sites printed the raw denial set size, showing `1` while five of six families were refused. A trimmed path counted as a successful install and cleared the failure cooldown with no route in place. Requests left over from a previous session were divided into this session's dispatch total. ## Testing 375 unit tests, four game-test harnesses, and roughly thirty mutations compiled and observed to fail. Three of those survived their first defence, including two tests of mine that passed for the wrong reason. This release is correctness work. No performance change was measured for it, and none is claimed.
beta

0.7.0 - Fewer wrong answers, fewer hiding places (26.1.2)

0.7.0+26.1.2
31 авг. 2026 г.45Minecraft: 26.1.1, 26.1.2fabric
Скачать
Что нового
Mostly defects. Around twenty of them, found by four parallel read-only hunts over the async, mixin, gate and config packages, then by an adversarial review of the whole diff. ## Player-visible - **Mobs no longer freeze for up to a second after the world changes under them.** Vanilla nulls a mob's path and asks for a new one. Because the answer arrived a tick later, it recorded a recompute that never produced a path, and both of its retry routes then stayed shut for twenty ticks on a mob standing still. Control goes back to vanilla now. - **A goal can no longer be told a mob is reachable using a route to somewhere it abandoned.** While a search is in flight, `path` and `targetPos` name different destinations, and vanilla's own path-reuse check treats them as a pair. Direct queries got the stale route. - **`AUDITED` works on 26.1.1**, not only 26.1.2. The audits now gate on the bytes they pinned rather than on a version label. The pinned vanilla classes are byte-identical on 26.1.1, and different on 26.2, so 26.2 still refuses. - **Workers skip searches nobody wants any more**, instead of computing them and throwing the result away. ## Six ways it could fail open, all live in 0.6.1 - A negative `workerFailureLimit` landed on the documented "never switch anything off" value. That disabled the family-shutdown safety net while the settings screen showed something legal. - A config written before the tier setting existed inherited today's permissive default, moving an operator from "scan armed" to "waive everything" with no log line. - The denial set in `SafetyGate` was public and mutable, so any class on the classpath could clear every scan denial, including the ones a failed scan installs that no tier is allowed to waive. - A mixin config registered after startup was invisible to the scan, because pathfinding classes are not transformed until a world starts. That was the one place where absent evidence produced ALLOW. - One third-party jar with unusual capitalisation in its manifest could make the mod permanently inert, through a scan failure no tier can waive. - Setting `trustedMods` to null made the settings screen unopenable, with no message. ## Reporting `/pathweaver mobs` called a mob eligible when dispatch would have refused it. The status line said breaker-stopped families were "running anyway", contradicting a line three rows above it. Both reporting sites printed the raw denial set size, showing `1` while five of six families were refused. A trimmed path counted as a successful install and cleared the failure cooldown with no route in place. Requests left over from a previous session were divided into this session's dispatch total. ## Testing 375 unit tests, four game-test harnesses, and roughly thirty mutations compiled and observed to fail. Three of those survived their first defence, including two tests of mine that passed for the wrong reason. This release is correctness work. No performance change was measured for it, and none is claimed.
beta

0.6.1 for 26.2

0.6.1+26.2
19 авг. 2026 г.158Minecraft: 26.2fabric
Скачать
Что нового
Minecraft **26.2** build of 0.6.1. Same mod, same code — no behaviour differs from the 26.1.2 release. ### Read this if you use the checked tier `compatibilityTier=AUDITED` **denies every movement family on 26.2**, so the mod does nothing at that setting. That is the gate working, not a bug: every per-mod exemption is pinned to the exact bytes it was derived from, and 26.2 changed vanilla — `WalkNodeEvaluator`, `PathNavigation` and `BlockBehaviour$BlockStateBase` are all different files — so the evidence no longer applies. Re-pinning the hashes without redoing the bytecode analysis would be a safety claim nobody had checked, so the audits refuse instead. Re-auditing for 26.2 is on the roadmap. The shipped default is `UNSAFE`, which performs no such check, so **this affects you only if you deliberately switched to AUDITED**. ### Verified on 26.2 - `PathWeaver is ACTIVE: all 6 movement families can path off-thread` - Server game tests at the shipped default: 2/2, dispatched=1 installed=1 discarded=0 - Client harness: real singleplayer world, 3 dispatched / 3 installed / 0 discarded, settings screen renders - 357 of 360 unit tests. The 3 failures are the version-pinned audit bundles described above, and nothing else. ### For the curious: what 26.2 changed Nothing in the mod. The port is a version bump plus a manifest range. Two vanilla changes did break the *test* sources: `EntityType` lost about 170 constants (`EntityType.ZOMBIE` is now an `EntityTypeIds` resource key resolved through the registry, and `ResourceLocation` was renamed to `Identifier`), and `Minecraft.screen` no longer exists — the current screen moved to `Gui.screen`, private. Both are worked around in a way that still compiles against 26.1.2, so one source tree serves both. If you run ServerCore, make sure it is the 26.2 build; the 26.1.2 one fails at mixin apply on 26.2 regardless of this mod.
beta

0.6.1 — Notice, instead of predicting

0.6.1+26.1.2
19 авг. 2026 г.55Minecraft: 26.1.1, 26.1.2fabric
Скачать
Что нового
PathWeaver had two modes: one that did nothing, and one that checked nothing. The checked tier, `AUDITED`, asks *"did any mod touch this class?"* On a real modpack the answer is always yes — 20 mods on the reference pack claim a watched pathfinding target — so it has left **0 of 187 mob types eligible since 0.3.0** on that pack with `trustedMods` empty, across five releases, and the shipped default is `UNSAFE`, which performs no check at all. (On a lean pack the tier admits everything on its own; that is the configuration this project's headline benchmark runs in. The problem is not that it never works, it is that it never works on the packs the mod is for.) That tier is now **frozen**: it stays as a conservative escape hatch, and it is no longer the answer. The reasoning, and the four independent ways the one attempt to fix it was wrong, are in [ROADMAP.md](ROADMAP.md). This release replaces prediction with detection. ### Added - **A worker failure breaker.** A search that throws on a worker is counted against the movement family whose code ran. Past a windowed threshold that family stops dispatching for the rest of the session, and every mob in it paths on the server thread exactly as it would without this mod installed. Falling back to vanilla is the safe direction by construction, so the breaker cannot destabilise anything it fires on. - **Failure attribution, which is the half that pays on every install.** The breaker may never fire — the reference pack ran 753 dispatches with zero search failures. The attribution fires on the *first* failure, needs no threshold, and turns a single rate-limited `WARN` into a block naming the family, the exception and, where it can, the mod. The honest limit is stated in the log itself: a mixin handler is merged into the class it targets, so an `@Overwrite` or an inlined `@Redirect` leaves nothing to attribute, and the block says so rather than printing an empty list. - **Two settings**, `workerFailureLimit` (default 3) and `workerFailureWindowTicks` (default 1200, one minute). `workerFailureLimit=0` keeps dispatching no matter what and still counts and logs. **No `configVersion` bump**: the serializer throws on any version but 2, 1 or 0 and a load failure installs fail-closed defaults, so bumping it would have switched the mod off for every existing install. Both fields default in on an untouched config, verified on the real pack. - **`/pathweaver status` now shows failures before they trip anything**, because the log block told operators the running total was there and it was not. ### Why the threshold is windowed A counter that never decays converges on a certain trip given enough uptime, and this project's own Lithium audit describes a concurrent-resize exception as an expected, contained event on the most widely installed performance mod there is. Three of those over a fortnight is not an incompatibility; three in a minute is. **A false trip is not a free no-op** — being vanilla is the thing the user installed this mod to stop — so the window is what makes the mechanism affordable. A cumulative backstop still catches a genuine slow leak. ### What this is not A breaker sees **throws**. The corruption a user actually fears comes from a silent torn read that returns the wrong block and never throws, and nothing here catches that. It is a smoke detector: it does not stop the fire starting, it stops the house burning down and tells you which room it started in. ### Fixed, found by reviewing the running code - **A `workerFailureLimit` above 25 was silently capped.** The cumulative backstop was an unconditional `||` rather than a floor, so a setting that accepts up to 1000 tripped at 25 anyway, with nothing in the tooltip, the status line or the log admitting it. - **The trip block named the threshold that had not fired.** A backstop trip printed the *window* rule, and the cumulative count underneath it, sending an operator to raise a setting that changes nothing. - **A `VirtualMachineError` counted as evidence of an unsafe read.** On a 200-mod server an `OutOfMemoryError` is the likeliest throwable a worker will ever produce; three would have switched five families off and blamed whichever mods were on the frame. - **A trip could outlive its server.** `shutdownNow()` does not wait, so a straggler worker past the threshold check installed its verdict into the *next* world — an inert movement family in a fresh world with no log line, because the one-shot report had already fired in the world before. - **A cyclic cause chain spun a worker forever** during attribution. - The two new config keys skipped the type validation every other integer key gets. ### Also - `/pathweaver status` and `/pathweaver mobs` were `private static void (CommandSourceStack)` with no seam, so eight mutations inside them were invisible to every test. They now produce a `List<String>` the tests assert against. 358 unit tests (zero skipped), three game tests plus a dedicated end-to-end breaker harness, four server harnesses, the client harness, and verification on the real 221-jar server pack: 184 of 187 eligible, 753 dispatched / 746 installed / 7 discarded, all six evaluator families node-for-node identical to a synchronous oracle, and **no breaker output at all** — which is the correct result on a healthy pack and the honest measure of this feature. Benchmarked against published 0.6.0 over six interleaved runs on this exact jar: mean tick 50.003 ms vs 50.002 ms, p99 147.9 ms vs 144.9 ms. No regression. Twenty-two mutations were compiled and observed to fail during development. Eight of them survived their first defence, including both log blocks — the entire user-visible output of this feature was deletable without a test noticing. --- **Also runs on Minecraft 26.1.1** (added 15 August 2026). Every pathfinding and navigation class is byte-identical between 26.1.1 and 26.1.2 and the dependencies are the same builds, so this is the same file rather than a separate one. Verified by booting a 26.1.1 server: PathWeaver reports ACTIVE with all six movement families off-thread, and `/pathweaver mobs` reads 88 of 89. One caveat, the same one as the 26.2 build: `compatibilityTier=AUDITED` refuses on 26.1.1, because every per-mod exemption is pinned to the exact Minecraft version it was derived against. The shipped `UNSAFE` default is unaffected.
beta

0.6.0 — Spiders, and diagnostics that tell the truth

0.6.0+26.1.2
9 авг. 2026 г.44Minecraft: 26.1.2fabric
Скачать
Что нового
*The diagnostics work below was briefly numbered 0.5.4 and held back rather than published: on its own it added no capability, no coverage and no speed, and nobody should update a modpack for a release that only stops the mod misreporting itself. It ships as part of 0.6 instead.* ### Coverage - **Spiders path off-thread.** `WallClimberNavigation` overrides `moveTo(Entity, double)` without calling `super`, so the dispatch marker never ran for it and every spider chasing a player resolved its path on the server thread — while `/pathweaver mobs` counted spiders as eligible. Third instance of one mixin mistake; `NavigationOverrideCoverageTest` now derives the overriding navigation subclasses from Minecraft's own bytecode so a future one cannot silently opt out. ### The default now explains itself - **The startup log says WHY `UNSAFE` is the shipped default.** It already warned that the denial had been ignored and that searches run alongside unaudited code. What it never said is the reason, which is what turns that from "this mod ships recklessly" into a trade an operator can evaluate: the checked tier denies every family on an ordinary modded pack — measured at **0 of 187 eligible mob types** on a 221-jar server pack — so shipping it as the default would ship a mod that does nothing. It is now stated as a trade, explicitly not as a safety claim, and followed by what to actually do: run it on a copy of your world, keep the setting if nothing looks wrong after a few sessions, switch to `AUDITED` and report it if something does. ### Diagnostics that agree with the gates A cumulative review of everything since 0.5.0 and an adversarial concurrency bug hunt. The bug hunt found **no blocker and no high-severity defect**, and said so explicitly rather than padding — the epilogue pairing, the install-staleness checks, the evaluator clone, and the pool's generation isolation were all attacked and held. ### Fixed - **`/pathweaver mobs` called every land family eligible while dispatch refused all five.** Removing the command's early return so swim mobs stopped being under-reported had a cost nobody priced: the table is now printed in the one state where asking `SafetyGate.isAllowed` alone is wrong. Measured, not argued — `isAllowed(Walk)=true` against `canDispatch(Walk)=false`. The verdict consults the land registry, the command reads the live latch rather than a constant, and both halves are pinned by mutations that were compiled and observed to fail. - **`deniedFamilies` meant two different things in two places.** On the same server in the same second, the startup log said `deniedFamilies=0` and `/pathweaver status` said `deniedFamilies=6`. Both were right — the log counts what is *enforced*, status counted what the scan *found* before the tier waived it — and one label with two meanings is the class of defect this release exists to end. Status now prints `deniedByScan=` and `enforced=` separately; the log keeps the name the README teaches. - **A mob held back by its `PathFinder` was blamed on a mod, including when it was vanilla's.** The line named the class with `getSimpleName()`, which is empty for an anonymous class, so a real pack produced `navigates with , a mod-supplied PathFinder`. Naming it properly showed what it was: `Warden$1$1`, a `PathFinder` subclass **vanilla itself** constructs. It now falls back to the full name and says "a PathFinder subclass" rather than accusing a mod. - **The command told operators that wall-climber chases stay synchronous** — in the release whose headline is that they no longer do. - **The startup banner and `/pathweaver status` reported "ACTIVE, all six families" while five of the six were being refused every tick.** Dispatch consults Fabric's land path-type registry latch in addition to `SafetyGate`; the two reporting sites did not. On a pack where that verification fails, the mod announced itself fully active, `dispatched` rose only from squid and fish, and `/pathweaver mobs` said the opposite — the mod's own diagnostics contradicting each other on the first question an operator asks. All three reporting sites now answer through one predicate, `SafetyGate.canDispatch` — four, in fact: `/pathweaver mobs` was open-coding the same rule a fourth time. Precisely what is shared, because an earlier draft of this entry overstated it: dispatch does **not** call `canDispatch`. It evaluates `isAllowed`, then `requiresEmptyLandRegistry`, then the latch, as three separate steps. `canDispatch` is a *reconstruction* of that sequence for the reporting sites, and an unpinned reconstruction is exactly how this bug became re-introducible twice — `requiresEmptyLandRegistry` could be replaced with `return false` and `canDispatch` reduced to `isAllowed`, each leaving all 289 tests green. `SafetyGateDispatchParityTest` now asserts the reconstruction against the sequence over the whole input space rather than against itself, and the one-argument convenience wrapper that hid the call site is deleted rather than tested beside. The land-registry half covers all five land-derived families, not just the exact `Walk` class. This is the third time a diagnostic has been caught disagreeing with what the gates actually do. - **A setup failure before registration was swallowed entirely — no outcome, no counter, no log.** Everything from the attribute captures through the evaluator clone runs before the request reaches the sink, and the catch only recorded an outcome if it had. A deterministic failure there meant the mod did nothing, forever, while reporting itself as working. It is now counted whether or not registration happened — as `SETUP_FAILED` when the request had already been counted as dispatched and `SETUP_FAILED_PRE_DISPATCH` when it had not. The split is at `markDispatched`, not at registration — those are different events, and choosing on the wrong one left a single outcome that was simultaneously "wasted dispatched work" and "not part of dispatched". Logged once per server session. The reachable trigger is a third-party evaluator whose no-argument constructor throws when invoked outside its own construction path: `canClone` proves a constructor resolves, never that it runs. - **The coverage contract treated an omitted `require` as safe.** ASM only visits values that are present, so `require` arrived as null whenever it was left out — and null was read as fine. What makes omission safe is `injectors.defaultRequire: 1` in the shipped config, which the test read for the mixin list and never consulted for this. It now resolves `require` the way Mixin does. (That was verified by hand-mutating the config both ways during development; it is not pinned by a shipped test, and saying otherwise here would have been a claim the repo does not support.) - **That contract's declared side was gated on a literal `Mob` receiver.** Every entity call in all six evaluators does have owner `Mob` on 26.1.2 — verified — but a version emitting the same call with a `LivingEntity` static type would have emptied the declared side and left every assertion in the class passing over a live attribute race. - **Both worker `ThreadLocal` captures now happen inside the `try`.** Only an `OutOfMemoryError` could have separated them, but the residue is the exact failure both javadocs warn about: a step height left published on a pooled thread and inherited by the next mob scheduled onto it. - **The banner blamed the compatibility tier for refusals it did not cause.** A family failing only the clone check got the full "you opted into AUDITED" lecture and advice to edit `trustedMods`, neither of which would have changed anything. ### Documentation that was actively wrong - `DESIGN.md` §3 still said flying and amphibious evaluators were ineligible. They have been the default async path since 0.4.0. Anyone auditing the threading story from that file would have concluded axolotls, turtles, drowned, frogs and every flying mob were synchronous. - The recompute seam's javadoc claimed vanilla has two outcomes. It has four, and the whole table is now written out — including the exit where a claim **is** still dropped, which is recorded as roadmap 2g rather than papered over. That is not a regression (0.5.0 dropped it on all three branches) and re-applying it there is precisely the 0.5.1 bug, so it needs the request to carry its origin rather than a widened condition. - A javadoc describing `rollbackOptimisticTarget` was sitting above `abortFailedInstall`. Two more of the same: a javadoc in `RequestOutcome` and one in `PWNavigation` each sat directly above *another* javadoc, documenting nothing, and an `@param dispatchCounted` named a parameter that had been replaced by `stage`. - **The README's eligibility numbers were measured with the wrong instrument.** It quoted 187 of 187 at the shipped default, from a harness that never inspects the `PathFinder` a mob actually holds. `/pathweaver mobs` — the thing a user can run — says **184 of 187**, holding back the two spiders and the warden. Nothing regressed; the old number was optimistic. Every figure in that section has been re-measured on 0.6.0 and the claim that 0.4.0 dispatched the first third-party evaluator is withdrawn: it never dispatched, and direct measurement now says so. - **The release page claimed path equivalence for "all seven evaluator families".** There are six, and the seventh row in the harness output is a spider whose third-party `PathFinder` means it never dispatched — so its "IDENTICAL" compared a synchronous path with itself. The claim also read as a proof where the README says, correctly, that this is one static scenario per family and that flying equivalence is not guaranteed by the design at all. Corrected in the README, the changelog and the Modrinth page. (The underlying result is real and is new: until 0.6.0 only Walk and Swim had an oracle comparison, and all six now have one.) - **The `AUDITED` + all-nine-trusted row was quoted without the setting it was measured under.** `allowModdedMobAsync` defaults to false, and at that tier the origin gate then refuses 98 of the pack's 187 mob types. The honest pair is **86 of 187** at stock settings and 184 with the bypass on. The old row said 185, then 184, and never said which. - `tools/scan_pack.py` counted mixin configs rather than mods in its totals line, and counted **PathWeaver itself** among the mods claiming a pathfinding target — printing 22, then 21, where the README says 20. The documented figure was only reproducible on a directory with PathWeaver deleted from it, which is not a directory anyone has. It now counts distinct third-party mods. - `PLAN.md` was a 0.2.3 artifact sitting in the repo root, whose "Future boundary" section stated no engine work remained after 0.2.2 — beside a roadmap describing 0.6 through 1.0. Archived to `docs/PLAN-0.2-archive.md`. `DESIGN.md`'s product decision still said "hold publication", reversed at 0.3.0 and four releases ago. ### Added - **A worker-reachability analysis** (`src/test/java/dev/pathweaver/reach/`), the first step of the 0.6 plan to replace hand-written hazard lists with derivation. **It is a discovery aid, not evidence.** An earlier draft of this entry cited it as corroborating that no attribute hazard remains; a review showed it silently truncated in three places that contradicted its own stated guarantee. Those are fixed — it now resolves interface defaults, records every truncation instead of swallowing it, and no longer maps a receiver onto a type that does not implement it. The numbers moved from 1,735 reachable / 0 unresolved / 12 hazards to 2,060 / 168 / 45, which is what an honest version of the same walk looks like. Details in `docs/ROADMAP-0.6-archive.md` §6. It found no unknown bug. What building it taught is recorded there too: the naive version is useless rather than imprecise, reporting 1,220 hazards including the client renderer. - **`tools/scan_pack.py`**, which measured why `AUDITED` leaves nothing eligible: 20 mods in a real 221-jar server pack claim a watched target, any one of which denies everything, and 14 have no audit. Nine of those 14 touch only `BlockBehaviour$BlockStateBase` and are not pathfinding mods at all. The tool over-approximates on purpose — it reads mixin configs, not what the injected code reaches — so it flags five that PathWeaver's own scanner clears. The scanner names nine blockers on this pack; the nine that touch only `BlockStateBase` are a *different* nine, which is confusing enough to be worth saying out loud. - ASM is now an explicit test dependency instead of arriving through `fabric-loader`. 318 unit tests (zero skipped), three game tests, four server harnesses, the client harness, a benchmark showing no change against 0.5.3, and verification on a real 221-jar server pack in four configurations: `AUDITED` with nothing trusted (0 of 187 eligible, nine mods named); `AUDITED` with those nine trusted at stock settings (86 of 187 — the origin gate refuses 98 mod-added mob classes); the same with `allowModdedMobAsync=true` (184 of 187, nothing enforced, 732 searches installed); and the shipped `UNSAFE` default (184 of 187, 755 dispatched / 749 installed / 6 discarded on the shipping jar, with no PathWeaver exception in any run). With the world held still, all **six** evaluator families produced node-for-node identical routes to a synchronous oracle — one scenario each, which is evidence and not proof, and which for flying mobs the design does not guarantee (README, *What is unproven*).