
Where's my Brain (WMB)
Smart mob AI optimization mod
About this Mod
WHERE'S MY BRAIN (WMB)
A lightweight, loader-agnostic Minecraft 1.20.1 optimization mod focused on smarter mob AI scheduling, distance-aware throttling, and adaptive auto-tuning. Keep gameplay feel near players while cutting wasted CPU on far-away or idle mobs.
Works on both Forge and Fabric via Architectury.
Features
Async Entity Tracking
- Off-thread per-player entity visibility/tracking decisions to reduce main thread work.
- Global or per-dimension thread pools with adaptive backpressure (queue-aware scheduling).
- Respects
asyncTracker.updateInterval,cacheDuration, andmaxTrackingDistance. - Integrates with AutoTuner to adjust scheduling under load.
- Timeouts and graceful fallbacks keep the main thread safe.
Regional/Chunk-based TPS Manager (R‑TPS)
- Divides each dimension into square regions (default:
regionalTPS.regionSize = 4chunks per side) and continuously measures load per region. - Tracks per-region metrics: average AI time (ms), average memory (MB), player presence, redstone updates, BE/scheduled tick counts, and activity recency.
- Applies scalable tick multipliers per region using named levels (e.g.,
normal=1,warning=2,critical=4). - Hysteresis (
regionalTPS.hysteresisPct, default 0.15) prevents flip‑flops when load hovers near thresholds. - Static overrides let you pin specific regions to a level.
- Safety: global TPS is computed over a sliding window and emergency triggers are gated by warm‑up and cooldown to avoid false alarms.
- Gating integrates with chunk random/scheduled ticks to cut work in stressed regions while remaining invisible near players.
- Divides each dimension into square regions (default:
Distance-based AI Bucketing (DAB)
- Dynamically throttles AI ticks based on each mob’s nearest-player distance.
- Per-dimension and per-entity overrides.
- Hysteresis deadband to prevent thrashing near thresholds.
- Sensible exemptions (leashed, named, owned/tamed, persistent, and configurable boss exemptions).
Proximity Snapshot Service
- Centralizes nearest-player computations to a periodic snapshot, reducing redundant work.
- Mob-side cache reduced to 2 ticks for responsive DAB updates with minimal overhead.
Pathfinding Optimizations
- Minimum per-mob path recalculation interval and grouping window.
- Optional experimental path sharing.
- Caching with TTL to avoid repeated path solves.
Auto-Tuning (PID)
- Targets a desired average tick time (ms) and gently adjusts pathfinding recalc interval.
- PID controller (kp/ki/kd) with integral clamping and step-limits for smooth convergence.
- Transparently falls back to a simple step controller if PID gains are zero.
Optional AI Culling (Conservative)
- Skip AI processing for far, idle, and unengaged mobs behind multiple safety gates.
Optional Visibility Culling (Conservative)
- Skip AI for mobs far outside any player’s chunk range, with the same safety gates.
Metrics and Command
- Lightweight internal counters for
/wmb stats. - See DAB thresholds, proximity settings, pathfinding parameters, and tuner state.
- Lightweight internal counters for
How It Works
- DAB continuously places each mob into a distance bucket (near/mid/far/distant) relative to the nearest player and assigns a tick interval multiplier per bucket.
- Async Entity Tracking computes per-player tracked entity sets off-thread and applies updates post-tick; intervals adapt via tuner and backpressure.
- The proximity service snapshots player positions every N ticks (configurable) to amortize distance queries.
- Pathfinding and AI recalculations are rate-limited with per-mob minimum intervals and optional grouping.
- The Auto Tuner reads average tick time over a window and adjusts
pathfinding.minRecalcIntervalto steer the server towardstuning.targetTickMs. - Culling and visibility features add optional, conservative gates to skip AI when it’s safe to do so.
Diagrams
Async Entity Tracking: Flow
[Server Tick]
├─ PreTick
│ ├─ shouldSchedulePlayer?(interval + tuner + backpressure)
│ ├─ Snapshot(Player)
│ ├─ CollectEntitySnapshots (AABB around player)
│ └─ Submit Task → Executor
│ └─ [Off-thread]
│ ├─ Filter by distance ≤ maxTrackingDistance (2D)
│ ├─ Diff with current tracked set → {toAdd, toRemove}
│ └─ Enqueue TrackingResult
└─ PostTick
├─ Drain completed results (batched)
├─ Apply adds/removes to tracking sets
├─ Update metrics (durations, queue size, counts)
└─ Periodic maintenance (cleanup/disconnects)
Threading Model: Global vs Per-Dimension Pools
Option A: Global Pool
[AsyncTracker Executor (N threads)]
↑ tasks from all dimensions
Option B: Per-Dimension Pools
[Overworld Executor (M)] [Nether Executor (M)] [End Executor (M)]
↑ OW tasks ↑ Nether tasks ↑ End tasks
Backpressure: bounded queues + CallerRunsPolicy; scheduling slows when queues grow.
Auto‑Tuner: Control Loop
tickNanos → EMA → window(avg)
│
▼
Controller (PID or Simple)
│
┌───────┴─────────────────────────────┐
│ │
pathfinding.minRecalcInterval += step trackerIntervalAddend = clamp(-step)
│ │
cooldown ticks prevent rapid toggling additive scheduling shift for tracker
DAB Bucketing and Hysteresis
distance (blocks) → 0 ── d0 ── d1 ── d2 ──▶
bucket NEAR MID FAR DISTANT
multiplier x1 x2 x4 x8 (defaults; configurable)
hysteresisBlocks (±h) creates a deadband around d0/d1/d2 to reduce bucket flipping.
Regional TPS: Decision Pipeline
[Server Tick]
├─ PreTick
│ ├─ Global TPS sample ← steady after 5+ samples; clamped [0..20]; warm‑up (≥200 ticks) before emergency checks
│ └─ Update player→region mapping
├─ PostTick (per region)
│ ├─ Accumulate AI nanos, BE & scheduled ticks, redstone updates, memory, players
│ ├─ Windowed averages (regionalTPS.windowTicks)
│ ├─ Decide target level using thresholds + hysteresis
│ ├─ Smoothly adjust region multiplier toward target (±1 per tick)
│ └─ Apply gating hooks (e.g., chunk random/scheduled ticks)
└─ Global
├─ Emergency trigger if: warm‑up passed ∧ samples≥20 ∧ TPS<15 with cooldown
└─ Periodic logging & eviction of stale regions
Heatmap: Client Flow & Interactions
/wmb heatmap [radius] → server builds window around player
↓
send Heatmap to client
↓
HeatmapScreen (press H to reopen last)
↓
Interactions:
- Mouse wheel: zoom
- Right‑drag: pan
- Left‑click on header: toggle Mode (AI ms, Mem MB, Players, Priority)
- Click LOD: toggle merged vs per‑region view
- Hover: tooltips (merged + region details)
- Sidebar: detailed panel (emergency, target multiplier, good/bad streaks, etc.)
- Global TPS shown in header
Installation
- Minecraft: 1.20.1
- Loaders: Fabric or Forge (Architectury)
- Drop the mod jar into your
mods/folder. - Start the game once to generate the
wmb.tomlconfig with inline comments.
Config location by loader:
- Fabric:
.minecraft/config/wmb.toml - Forge:
<instance>/config/wmb.toml
Commands
/wmb regions here- Prints the current region’s coordinates, level, and summary.
/wmb regions top [n]- Lists the top N heaviest regions by average AI ms.
/wmb heatmap [radius]- Generates a heatmap around your position (default radius 8 regions) and sends it to your client.
/wmb reload- Reloads
wmb.tomlfrom disk and applies runtime values.
- Reloads
/wmb metrics on|off- Toggle internal metrics collection used by stats commands.
/wmb tuning on|off- Enable/disable the AutoTuner at runtime.
/wmb preset <vanilla|balanced|aggressive>- Apply a runtime preset of conservative to stronger optimizations. Use
/wmb reloadto revert to file values.
- Apply a runtime preset of conservative to stronger optimizations. Use
/wmb stats- Shows DAB thresholds & multipliers, proximity snapshot interval, async spawn/tracker thread settings, pathfinding and tuner parameters, and metrics (if enabled).
/wmb trackerstats- Prints tracker status and queue/task metrics.
/wmb debug entity- Inspect the nearest mob’s effective DAB interval near the player.
/wmb debug chunk- Summarize average DAB interval for mobs in your current chunk.
Keybinds
Heatmap:
H(default)- Opens the last received heatmap on the client. If you haven’t requested one yet, use
/wmb heatmapfirst.
- Opens the last received heatmap on the client. If you haven’t requested one yet, use
/wmb profile start|stop- Lightweight profiler for AI step timing; prints a summary when stopped.
/wmb stresstest start <entity> [count] [radius] [duration] [pathEvery] [waypoints]- Spawns a controlled scenario for stress testing. Use
status,report, andstopto manage.
- Spawns a controlled scenario for stress testing. Use
Configuration Reference
All options are documented inline in the generated wmb.toml. Below is a structured overview.
Distance-based AI Bucketing (DAB)
dab.enabled(bool)- Turn distance-aware AI throttling on/off globally.
dab.d0,dab.d1,dab.d2(double, blocks)- Distance thresholds separating near/mid/far/distant buckets.
dab.multipliers.near|mid|far|distant(int)- AI tick interval per bucket.
1means every tick (no throttle), higher means less frequent AI updates.
- AI tick interval per bucket.
dab.hysteresisBlocks(double, blocks)- Deadband around the thresholds to avoid rapid bucket flipping near the boundary.
dab.perEntity["namespace:id"]- Per-entity overrides and exemptions.
- Keys:
exempt(bool),highPriority(bool),near,mid,far,distant(ints). - If
exemptorhighPriorityis true, DAB is disabled for that entity type.
dab.perDimension["namespace:dimension"]- Per-dimension overrides for
d0/d1/d2and nestedmultipliers.near|mid|far|distant.
- Per-dimension overrides for
Notes:
- Some high-importance entities (e.g., bosses) can be exempted from DAB by default in code or via per-entity overrides.
- Leashed, named, owned/tamed, and persistent entities are not throttled.
Proximity
proximity.updateIntervalTicks(int)- How often player positions are snapshotted. Larger = less CPU, slower DAB responsiveness. Typical: 3–10.
Pathfinding
pathfinding.enabled(bool)- Enable optimizations around path recalculations and caching.
pathfinding.minRecalcInterval(int, ticks)- Minimum ticks between recalculations per mob. This is the actuator adjusted by the tuner.
pathfinding.groupWindowTicks(int, ticks)- Group/stagger recalcs within a small window to spread CPU spikes.
pathfinding.cacheTtlTicks(int, ticks)- Keep solved paths for this long before expiring.
pathfinding.experimentalShareEnabled(bool)- Experimental: allow similar mobs to share path results.
pathfinding.shareTtlTicks(int, ticks)- TTL for shared path entries if sharing is enabled.
Auto Tuning
tuning.enabled(bool)- Enable closed-loop tuning of
pathfinding.minRecalcIntervaltowards a target tick duration.
- Enable closed-loop tuning of
tuning.targetTickMs(double, ms)- Desired average tick duration (50.0 ms = 20 TPS).
tuning.windowTicks(int)- Number of ticks per averaging window.
tuning.cooldownTicks(int)- Minimum ticks between successive adjustments.
tuning.minRecalcMin/tuning.minRecalcMax(int)- Clamp the actuator (min recalc interval) within this range.
tuning.kp,tuning.ki,tuning.kd(double)- PID gains. If all are zero, the tuner falls back to a simple, step-based controller.
tuning.maxStepPerWindow(int)- Maximum absolute change to the actuator per window.
tuning.integralMaxAbs(double)- Absolute clamp for integral term to avoid windup.
Checks
checks.suffocationInterval(int, ticks)- Tuning of vanilla suffocation checks. Higher = less CPU, slightly slower detection.
Async Spawn
asyncSpawn.enabled(bool)- Enable off-thread spawn preparation work.
asyncSpawn.threadPoolSize(int)- Worker threads to use for async spawn tasks. Recommended: 1–4.
Async Entity Tracker
asyncTracker.enabled(bool)- Enable asynchronous per-player entity tracking.
asyncTracker.threadPoolSize(int)- Worker threads for the global tracker executor when
perDimensionPools = false.
- Worker threads for the global tracker executor when
asyncTracker.updateInterval(int, ticks)- Minimum ticks between recalculations per player before cache reuse.
asyncTracker.cacheDuration(int, ticks)- How long to reuse the last visibility result before forcing a recalculation.
asyncTracker.perDimensionPools(bool)- If true, use one executor per dimension to isolate load.
asyncTracker.threadPoolSizePerDim(int)- Core threads for each per-dimension executor when
perDimensionPools = true.
- Core threads for each per-dimension executor when
asyncTracker.maxTrackingDistance(double, blocks)- Maximum 2D horizontal distance from the player for an entity to be considered tracked.
Culling (Optional)
culling.enabled(bool)- Conservative AI skipping for far, idle mobs with multiple safety gates.
culling.minDistance(double, blocks)- Only consider mobs at least this far from the nearest player.
culling.requireNoTarget/requireNoPath/requireLowMotion(bool)- Safety gates to ensure we skip AI only for idle, unengaged mobs.
culling.lowMotionSpeed(double, blocks/tick)- Threshold used by
requireLowMotion.
- Threshold used by
culling.allowEveryNTicks(int, ticks)- Even when eligible, allow full AI every N ticks to avoid starvation.
culling.exemptNamed|Leashed|Owned|Persistent(bool)- Protective exemptions to never skip important mobs.
Visibility (Optional)
visibility.enabled(bool)- Apply similar skipping rules to mobs far outside any player’s chunk range.
visibility.playerChunkRange(int, chunks)- Chebyshev chunk distance around players considered "active". Outside this range, mobs may be skipped subject to gates.
visibility.requireNoTarget/requireNoPath/requireLowMotion(bool)- Same safety gates as culling.
visibility.lowMotionSpeed(double, blocks/tick)- Threshold used by
requireLowMotion.
- Threshold used by
visibility.allowEveryNTicks(int, ticks)- Even when eligible, allow full AI every N ticks to avoid starvation.
visibility.exemptNamed|Leashed|Owned|Persistent(bool)- Protective exemptions to never skip important mobs.
Regional TPS
regionalTPS.enabled(bool)- Master switch for the chunk‑based TPS system.
regionalTPS.regionSize(int, chunks)- Side length of a square region in chunks. Default: 4.
regionalTPS.windowTicks(int, ticks)- Averaging window for per‑region metrics and decisions.
regionalTPS.thresholds.maxTickMs(double, ms)- Soft ceiling for average AI time in a region before increasing level.
regionalTPS.thresholds.maxEntities(int)- Heuristic cap for entity counts within the region window.
regionalTPS.thresholds.maxBlockEntities(int)- Heuristic cap for block entities within the region window.
regionalTPS.hysteresisPct(double, 0.0–0.45)- Percentage deadband applied around thresholds to prevent rapid level flip‑flopping. Default: 0.15 (15%).
regionalTPS.scaling.levels.<name>(int)- Map of named levels to tick multipliers, e.g.,
normal=1,warning=2,critical=4.
- Map of named levels to tick multipliers, e.g.,
regionalTPS.staticRegions["dim:rx,rz"] = "levelName"- Pin specific regions (by dimension and region coords) to a chosen level.
Config Versioning and Auto‑Merge
- The config file includes
configVersion. As of v1.2‑SNAPSHOT, the schema version is 5. - On load, WMB auto‑merges any missing keys with safe defaults and bumps
configVersionforward. - Existing user values are preserved. Keys are not removed automatically.
- The generated
wmb.tomlincludes inline comments for every option.
Tuning Guide
- Start with
tuning.enabled = false. Observe baseline with/wmb stats. - Set a realistic
tuning.targetTickMsfor your hardware and modpack. 50.0 ms is 20 TPS; aim slightly below your typical average load. - Begin with a simple controller:
kp > 0,ki = 0,kd = 0. Suggested:kp = 0.25. - If you see steady-state error, gently introduce
ki(e.g.,0.01–0.05). - If you overshoot or oscillate, add
kd(e.g.,0.05–0.2). - Keep
maxStepPerWindowsmall (1–2) for smoothness. Clamp integral viaintegralMaxAbs. - Always bound the actuator with
minRecalcMin/minRecalcMax. - Tracker integration: the tuner also adjusts tracker scheduling additively; leave
asyncTracker.updateIntervalmoderate and let the tuner smooth load.
Compatibility
- Designed to be conservative and safe around gameplay-critical AI.
- Bosses, named, leashed, owned/tamed, and persistent mobs are protected by default.
- Should be broadly compatible; experimental features (like path sharing) are opt-in.
FAQ
Does DAB change combat behavior near the player?
- No. The
nearbucket usually uses a multiplier of1, keeping AI behavior responsive up close.
- No. The
Does async tracking cause entity pop‑in or desync?
- No. Tracking sets are computed off‑thread but applied safely on the main thread each tick. Timeouts fall back gracefully.
What if my server has multiple heavy dimensions?
- Enable
asyncTracker.perDimensionPoolsto isolate tracker load by dimension and sizethreadPoolSizePerDimaccordingly.
- Enable
Will auto-tuning fight my manual settings?
- The tuner only adjusts
pathfinding.minRecalcInterval. Everything else remains exactly as configured.
- The tuner only adjusts
What if I don’t want any culling?
- Both culling systems are disabled by default. They’re strictly opt-in and conservative.
Is this a magic TPS booster?
- No. It’s a set of intelligent trade-offs to save CPU in situations where it doesn’t affect gameplay feel.
Changelog
1.2 (2025-09-04)
New — Regional/Chunk-based TPS Manager (R‑TPS)
- Per‑region load tracking (avg AI ms, memory MB, players, redstone updates, BE/scheduled ticks, activity).
- Named scaling levels (e.g., normal=1, warning=2, critical=4) applied as tick multipliers per region.
- Hysteresis via
regionalTPS.hysteresisPct(default 0.15) to stabilize level transitions. - Static region overrides to pin hotspots to specific levels.
- Integrates with chunk random/scheduled tick gating; invisible near players.
New — Heatmap UI for Regional TPS
- Request with
/wmb heatmap [radius]; reopen last heatmap with theHkey. - Mouse wheel zoom; right‑click drag to pan; live window requests while panning/zooming.
- Modes: AI ms, Mem MB, Players, Priority; LOD toggle (merged vs per‑region tiles).
- Tooltips and a detailed side panel (emergency state, target multiplier, consecutive good/bad ticks, histories).
- Global TPS display in the header.
- Request with
Improvements — Global TPS measurement and safety
- Lazy‑init tick timing; compute TPS only after 5+ samples; clamp to [0..20].
- Gate emergency triggers until warm‑up (≥200 ticks) and require ≥20 samples; add cooldown to avoid log spam.
Improvements — Regional decisions and sampling
- Applied hysteresis to regional scaling decisions; introduced
levelIndexto track transitions. - Normalized Y sampling for region gating to
level.getMinBuildHeight() + 1.
- Applied hysteresis to regional scaling decisions; introduced
Networking & Client
- Updated heatmap/detail serialization to include memory, player counts, priority, global TPS, target multiplier, and histories.
- Client can refresh the existing screen (
setHeatmap) without reopening; remembers last heatmap for theHkey.
Fixes
- Heatmap tooltip compile error fixed by initializing local variables.
- Eliminated false global TPS emergencies at startup or sporadic spikes; reduced warning spam.
Config
- Config schema bumped to 5; added
regionalTPS.*keys includinghysteresisPct. - Defaults and inline comments updated in
wmb.toml.
- Config schema bumped to 5; added
Migration Notes
- Existing configs auto‑merge new keys and bump
configVersionsafely. ReviewregionalTPS.thresholdsandregionalTPS.scaling.levelsfor your pack.
- Existing configs auto‑merge new keys and bump
License
See LICENSE.txt in the repository.
Available Versions
How to Install Where's my Brain (WMB) on Your Server
Order Server
Order a Minecraft Java server with at least 3 GB RAM (4 GB recommended).
Set fabric Loader
In the panel under "Egg", select the fabric loader and matching Minecraft version (1.21.8).
Install Mod
Open the mod browser in the dashboard and search for "Where's my Brain (WMB)". Click "Install" – done! Alternatively, upload the .jar via SFTP to the /mods folder.
Compatibility
Mod Loaders
Minecraft Versions
1.21.8, 1.21.7, 1.21.6 (+12 more)
Server-side
~ OptionalRecommended RAM
4 GB(min. 3 GB)Frequently Asked Questions
Where's my Brain (WMB) server crashes on startup – what to do?
Most common cause: wrong fabric version or insufficient RAM. Check the server log (latest.log) for "OutOfMemoryError" or "Mixin" errors. With Mado Hosting: ensure at least 3 GB RAM is allocated and the loader matches the mod version (1.21.8). You can switch loaders with one click in the panel.
Is Where's my Brain (WMB) compatible with fabric and forge?
Where's my Brain (WMB) officially supports fabric, forge for Minecraft 1.21.8, 1.21.7, 1.21.6. Note: Forge and Fabric mods are NOT cross-compatible – pick one loader and stick with it. The Mado dashboard automatically detects incompatible loader combinations.
Server lagging with Where's my Brain (WMB) – how to optimize performance?
Recommended RAM: 4 GB (per 8 players). Use /spark profiler to check if Where's my Brain (WMB) consumes the most tick time. Common fixes: reduce server view-distance to 8-10, install "performant" or "starlight" as supplementary mods on Forge. With Mado Hosting, your server runs on NVMe SSDs with dedicated CPU cores for minimal latency.
Rent Modded Server
Install Where's my Brain (WMB) with just one click on your server.