HopperLimiter
Per-chunk hopper cap to eliminate lag Paper & Folia ready.
Hard Chunk Caps ┃
Full Folia Support ┃ ⚖ Weighted Counting ┃
Auto Overflow Removal ┃
Zero Config Required[/CENTER]
Built natively for Folia and Paper, every chunk operation runs on the correct region thread no unsafe main-thread access, no cross-region data races. Periodic validation re-scans live chunks and automatically removes overflow hoppers, meaning limits hold even if hoppers are duplicated or bypassed through external means.
Need help or have questions? Join our Discord server: Discord Support
Per-chunk hopper cap to eliminate lag Paper & Folia ready.
▌ Overview
HopperLimiter enforces a configurable cap on the number of hoppers allowed per chunk, preventing lag machines and accidental server overload caused by hopper spam. It tracks both block hoppers and hopper minecarts independently, and enforces limits in real time at the moment of placement.Built natively for Folia and Paper, every chunk operation runs on the correct region thread no unsafe main-thread access, no cross-region data races. Periodic validation re-scans live chunks and automatically removes overflow hoppers, meaning limits hold even if hoppers are duplicated or bypassed through external means.
▌ Features
Placement Enforcement
- Real-time block placement blocking cancels hopper placement the instant the limit is reached
- Hopper minecart blocking intercepts PlayerInteractEvent and EntitySpawnEvent to stop minecart hoppers too
- Per-placement chunk re-scan cache is verified against live tile entities before every decision, preventing drift
- Permission bypass configurable permission node lets trusted staff or donors place freely
- Denial message fully configurable message shown to blocked players with current count and limit
⚖ Three Counting Modes
- COMBINED block hoppers and hopper minecarts share a single pool (e.g. max 32 total)
- SEPARATE each type has its own independent cap (e.g. 24 block + 8 minecart)
- WEIGHTED each type carries a configurable weight against a shared budget (e.g. minecarts cost 2× a block hopper)
Periodic Validation & Overflow Removal
- Configurable validation interval re-scans all tracked chunks on a fixed schedule
- Batched processing chunks processed across ticks (chunks-per-tick) to avoid validation spikes
- Overflow removal automatically removes excess hoppers when a chunk exceeds its cap
- Three removal priority modes remove by distance from chunk centre, Y level, or age
- Block hopper actions BREAK (drops item) or REMOVE (silently deletes)
- Minecart hopper actions REMOVE (entity deleted immediately)
- Stale chunk cleanup unloaded chunks are automatically evicted from the cache
Folia Region-Safe Architecture
- Validation timer runs on GlobalRegionScheduler
- Each chunk's validation dispatched to its own RegionScheduler thread no cross-region access
- Entity removal backup uses EntityScheduler safe under Folia's per-entity threading
- Startup chunk scan dispatches every addChunk call to the correct region thread
- plugin.yml declares folia-supported: true
Chunk Tracking
- ConcurrentHashMap-backed cache thread-safe reads from any context
- Tracks chunks only when player-loaded (isEntitiesLoaded()) no waste on force-loaded farm chunks
- Cache populated on ChunkLoadEvent and cleared on ChunkUnloadEvent automatically
- Hot reload rescans all loaded chunks and rebuilds the cache from scratch
▌ Commands & Permissions
| Command | Description | Permission |
|---|---|---|
| /hopperlimiter (alias: /hl, /hopperlimit) | Show plugin version and usage | none |
| /hopperlimiter reload | Hot-reload config.yml and rebuild all services | hopperlimiter.reload |
Permission Nodes
- hopperlimiter.reload reload configuration (default: op)
- hopperlimiter.bypass place hoppers beyond the chunk limit (configurable node name)
▌ Configuration Highlights
YAML:
# Hopper Limiter Configuration
# Counting mode: COMBINED, SEPARATE, or WEIGHTED
counting-mode: COMBINED
# Limits for different modes
limits:
combined: 50 # Used in COMBINED mode
block-hoppers: 30 # Used in SEPARATE mode
hopper-minecarts: 20 # Used in SEPARATE mode
# Weights for WEIGHTED mode
weights:
block-hopper: 1
hopper-minecart: 2
max-weight: 50 # Used in WEIGHTED mode
# Validation interval in seconds (30-120 recommended)
validation-interval: 60
# Chunks processed per tick during validation (prevents lag spikes)
# Lower values = smoother but slower validation
# Higher values = faster but may cause lag
# Recommended: 3-10 chunks per tick
chunks-per-tick: 5
# Overflow handling actions
overflow-handling:
block-hoppers: BREAK # BREAK or REMOVE
hopper-minecarts: REMOVE # REMOVE only
# Removal priority: distance, y-level, or age
removal-priority: distance
# Permission system
enable-permission-bypass: true
permission-node: hopperlimiter.bypass
# Player notification messages
messages:
enabled: true
block-hopper-denied: "&cCannot place hopper! Chunk limit reached (&e{current}/{limit}&c)"
hopper-minecart-denied: "&cCannot place hopper minecart! Chunk limit reached (&e{current}/{limit}&c)"
▌ Technical Details
- Server software: Paper 1.20.1+ and Folia fully region-safe
- Java version: Java 17+
- Hard dependencies: None
- Soft dependencies: None
- Thread model: Validation timer → GlobalRegionScheduler · Per-chunk work → RegionScheduler · Entity removal → EntityScheduler
- Cache: ConcurrentHashMap keyed by world + chunk coordinates safe for concurrent reads
- Hot reload: /hl reload unregisters listeners, rebuilds all services, and rescans live chunks
- Performance: Only scans tile entities and entities within tracked player-loaded chunks no world iteration overhead
Support
Need help or have questions? Join our Discord server: Discord SupportHopperLimiter is provided as-is. Feature requests and bug reports are welcome.
