Описание
# 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.
[](https://discord.gg/QM5beZpkYT)
---
## 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`, and `maxTrackingDistance`.
- 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.
- 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.
---
## 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 towards `tuning.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 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 via `integralMaxAbs`.
- 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 of `1`, keeping AI behavior responsive up close.
- 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 size `threadPoolSizePerDim` accordingly.
- Will auto-tuning fight my manual settings?
- The tuner only adjusts `pathfinding.minRecalcInterval`. Everything else remains exactly as configured.
- 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 the `H` 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.
- 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`.
- 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 the `H` 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 including `hysteresisPct`.
- Defaults and inline comments updated in `wmb.toml`.
- Migration Notes
- Existing configs auto‑merge new keys and bump `configVersion` safely. Review `regionalTPS.thresholds` and `regionalTPS.scaling.levels` for your pack.
---
## License
See `LICENSE.txt` in the repository.