Compatibility
Minecraft: Java Edition
Platforms
Supported environments
Links
Creators
Details
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 = 4
chunks 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.minRecalcInterval
to 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.toml
config 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.toml
from 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 reload
to 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 heatmap
first.
- 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
, andstop
to 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.
1
means 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
exempt
orhighPriority
is true, DAB is disabled for that entity type.
-
dab.perDimension["namespace:dimension"]
- Per-dimension overrides for
d0/d1/d2
and 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.minRecalcInterval
towards 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
configVersion
forward. - Existing user values are preserved. Keys are not removed automatically.
- The generated
wmb.toml
includes inline comments for every option.
Tuning Guide
- Start with
tuning.enabled = false
. Observe baseline with/wmb stats
. - Set a realistic
tuning.targetTickMs
for 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
maxStepPerWindow
small (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.updateInterval
moderate 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
near
bucket 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.perDimensionPools
to isolate tracker load by dimension and sizethreadPoolSizePerDim
accordingly.
- 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 theH
key. - 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
levelIndex
to 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 theH
key.
-
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
configVersion
safely. ReviewregionalTPS.thresholds
andregionalTPS.scaling.levels
for your pack.
- Existing configs auto‑merge new keys and bump
License
See LICENSE.txt
in the repository.