Smart mob AI optimization mod
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.
Async Entity Tracking
asyncTracker.updateInterval, cacheDuration, and maxTrackingDistance.Regional/Chunk-based TPS Manager (R‑TPS)
regionalTPS.regionSize = 4 chunks per side) and continuously measures load per region.normal=1, warning=2, critical=4).regionalTPS.hysteresisPct, default 0.15) prevents flip‑flops when load hovers near thresholds.Distance-based AI Bucketing (DAB)
Proximity Snapshot Service
Pathfinding Optimizations
Auto-Tuning (PID)
Optional AI Culling (Conservative)
Optional Visibility Culling (Conservative)
Metrics and Command
/wmb stats.pathfinding.minRecalcInterval to steer the server towards tuning.targetTickMs.[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)
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.
tickNanos → EMA → window(avg)
│
▼
Controller (PID or Simple)
│
┌───────┴─────────────────────────────┐
│ │
pathfinding.minRecalcInterval += step trackerIntervalAddend = clamp(-step)
│ │
cooldown ticks prevent rapid toggling additive scheduling shift for tracker
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.
[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
/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
mods/ folder.wmb.toml config with inline comments.Config location by loader:
.minecraft/config/wmb.toml<instance>/config/wmb.toml/wmb regions here
/wmb regions top [n]
/wmb heatmap [radius]
/wmb reload
wmb.toml from disk and applies runtime values./wmb metrics on|off
/wmb tuning on|off
/wmb preset <vanilla|balanced|aggressive>
/wmb reload to revert to file values./wmb stats
/wmb trackerstats
/wmb debug entity
/wmb debug chunk
Heatmap: H (default)
/wmb heatmap first./wmb profile start|stop
/wmb stresstest start <entity> [count] [radius] [duration] [pathEvery] [waypoints]
status, report, and stop to manage.All options are documented inline in the generated wmb.toml. Below is a structured overview.
dab.enabled (bool)
dab.d0, dab.d1, dab.d2 (double, blocks)
dab.multipliers.near|mid|far|distant (int)
1 means every tick (no throttle), higher means less frequent AI updates.dab.hysteresisBlocks (double, blocks)
dab.perEntity["namespace:id"]
exempt (bool), highPriority (bool), near, mid, far, distant (ints).exempt or highPriority is true, DAB is disabled for that entity type.dab.perDimension["namespace:dimension"]
d0/d1/d2 and nested multipliers.near|mid|far|distant.Notes:
proximity.updateIntervalTicks (int)
pathfinding.enabled (bool)
pathfinding.minRecalcInterval (int, ticks)
pathfinding.groupWindowTicks (int, ticks)
pathfinding.cacheTtlTicks (int, ticks)
pathfinding.experimentalShareEnabled (bool)
pathfinding.shareTtlTicks (int, ticks)
tuning.enabled (bool)
pathfinding.minRecalcInterval towards a target tick duration.tuning.targetTickMs (double, ms)
tuning.windowTicks (int)
tuning.cooldownTicks (int)
tuning.minRecalcMin / tuning.minRecalcMax (int)
tuning.kp, tuning.ki, tuning.kd (double)
tuning.maxStepPerWindow (int)
tuning.integralMaxAbs (double)
checks.suffocationInterval (int, ticks)
asyncSpawn.enabled (bool)
asyncSpawn.threadPoolSize (int)
asyncTracker.enabled (bool)
asyncTracker.threadPoolSize (int)
perDimensionPools = false.asyncTracker.updateInterval (int, ticks)
asyncTracker.cacheDuration (int, ticks)
asyncTracker.perDimensionPools (bool)
asyncTracker.threadPoolSizePerDim (int)
perDimensionPools = true.asyncTracker.maxTrackingDistance (double, blocks)
culling.enabled (bool)
culling.minDistance (double, blocks)
culling.requireNoTarget / requireNoPath / requireLowMotion (bool)
culling.lowMotionSpeed (double, blocks/tick)
requireLowMotion.culling.allowEveryNTicks (int, ticks)
culling.exemptNamed|Leashed|Owned|Persistent (bool)
visibility.enabled (bool)
visibility.playerChunkRange (int, chunks)
visibility.requireNoTarget / requireNoPath / requireLowMotion (bool)
visibility.lowMotionSpeed (double, blocks/tick)
requireLowMotion.visibility.allowEveryNTicks (int, ticks)
visibility.exemptNamed|Leashed|Owned|Persistent (bool)
regionalTPS.enabled (bool)
regionalTPS.regionSize (int, chunks)
regionalTPS.windowTicks (int, ticks)
regionalTPS.thresholds.maxTickMs (double, ms)
regionalTPS.thresholds.maxEntities (int)
regionalTPS.thresholds.maxBlockEntities (int)
regionalTPS.hysteresisPct (double, 0.0–0.45)
regionalTPS.scaling.levels.<name> (int)
normal=1, warning=2, critical=4.regionalTPS.staticRegions["dim:rx,rz"] = "levelName"
configVersion. As of v1.2‑SNAPSHOT, the schema version is 5.configVersion forward.wmb.toml includes inline comments for every option.tuning.enabled = false. Observe baseline with /wmb stats.tuning.targetTickMs for your hardware and modpack. 50.0 ms is 20 TPS; aim slightly below your typical average load.kp > 0, ki = 0, kd = 0. Suggested: kp = 0.25.ki (e.g., 0.01–0.05).kd (e.g., 0.05–0.2).maxStepPerWindow small (1–2) for smoothness. Clamp integral via integralMaxAbs.minRecalcMin/minRecalcMax.asyncTracker.updateInterval moderate and let the tuner smooth load.Does DAB change combat behavior near the player?
near bucket usually uses a multiplier of 1, keeping AI behavior responsive up close.Does async tracking cause entity pop‑in or desync?
What if my server has multiple heavy dimensions?
asyncTracker.perDimensionPools to isolate tracker load by dimension and size threadPoolSizePerDim accordingly.Will auto-tuning fight my manual settings?
pathfinding.minRecalcInterval. Everything else remains exactly as configured.What if I don’t want any culling?
Is this a magic TPS booster?
New — Regional/Chunk-based TPS Manager (R‑TPS)
regionalTPS.hysteresisPct (default 0.15) to stabilize level transitions.New — Heatmap UI for Regional TPS
/wmb heatmap [radius]; reopen last heatmap with the H key.Improvements — Global TPS measurement and safety
Improvements — Regional decisions and sampling
levelIndex to track transitions.level.getMinBuildHeight() + 1.Networking & Client
setHeatmap) without reopening; remembers last heatmap for the H key.Fixes
Config
regionalTPS.* keys including hysteresisPct.wmb.toml.Migration Notes
configVersion safely. Review regionalTPS.thresholds and regionalTPS.scaling.levels for your pack.See LICENSE.txt in the repository.
Conversation