Server & Plugins
๐ฅ๏ธ Server & Plugins#
Software Hierarchy#
| Rank | Software | Description |
|---|---|---|
| ๐ | Purpur | Paper + extra config switches + permissions |
| ๐ฅ | Paper | Modern baseline, best docs/support |
| ๐ฅ | Spigot | Legacy baseline, lower perf ceiling |
| ๐ | Vanilla | Just don’t |
Rule: Start from Paper/Purpur, not Spigot, unless you have a specific compatibility constraint.
JVM Arguments (Aikar’s Flags)#
java -Xms10G -Xmx10G \
-XX:+UseG1GC -XX:+ParallelRefProcEnabled \
-XX:MaxGCPauseMillis=200 \
-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 \
-XX:G1HeapRegionSize=8M \
-XX:InitiatingHeapOccupancyPercent=15 \
-XX:SurvivorRatio=32 -XX:MaxTenuringThreshold=1 \
-XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch \
-jar purpur.jar nogui
Tips:
- Always set
-Xms=-Xmx(prevents resizing lag) - Leave 1-2GB RAM for the OS
Configuration Tweaks#
server.properties#
| Setting | Value | Why |
|---|---|---|
simulation-distance |
4 |
Ticks entities only nearby โ CPU saver |
view-distance |
10 |
Visuals remain high |
network-compression-threshold |
256 |
Good bandwidth/CPU balance |
enforce-secure-profile |
false |
Required for offline-mode bots |
bukkit.yml#
| Setting | Value | Why |
|---|---|---|
spawn-limits.monsters |
50 |
Default 70 is overkill per player |
ticks-per.monster-spawns |
4 |
Less frequent spawns |
chunk-gc.period-in-ticks |
400 |
Unloads empty chunks faster |
spigot.yml#
| Setting | Value | Why |
|---|---|---|
entity-activation-range |
An:16, Mo:24 |
Mobs stop ticking sooner โ huge gain |
entity-tracking-range |
Pl:48, An:48 |
Lowers network packet spam |
merge-radius.item |
4.0 |
Stacks items aggressively |
save-user-cache-on-stop-only |
true |
Reduces disk I/O |
paper-global.yml#
| Setting | Value | Why |
|---|---|---|
max-entity-collisions |
2 |
Prevents cramming lag |
grass-spread-tick-rate |
4 |
Slower grass spread |
container-update-tick-rate |
3 |
Less frequent inventory checks |
optimize-explosions |
true |
Efficient TNT math |
prevent-moving-into-unloaded-chunks |
true |
Prevents glitchy lag spikes |
Purpur โ Extra Config#
Purpur adds purpur.yml on top of all Paper config:
| Setting | Purpose |
|---|---|
use-alternate-keepalive |
Reduce false timeout kicks |
tps-catchup |
Catch-up behavior after lag |
startup-commands |
Console commands on startup |
lagging-threshold |
Threshold for lag-aware behavior |
register-minecraft-debug-commands |
Expose hidden commands (admin-only) |
Useful built-in commands: /purpur reload ยท /purpur version ยท /ping ยท /uptime ยท /tpsbar ยท /compass
Purpur Installation#
Requires Java 21+:
# Latest build for a version
curl -fsSL "https://api.purpurmc.org/v2/purpur/1.21.5/latest/download" -o purpur.jar
java -Xms4G -Xmx4G -jar purpur.jar --nogui
Spark Profiling#
Paper 1.21+ bundles Spark:
/spark profiler start --timeout 600
Inspect hot paths (plugins, entities, tasks). Tune root cause, not random knobs.
World Pregeneration (Chunky)#
#1 Lag Killer โ generate chunks before players explore:
chunky radius 5000
chunky start
chunky progress # check status
chunky pause # pause if needed
chunky continue
Nether: chunky world world_nether && chunky start
โ Common Anti-Patterns#
- Enabling many gameplay toggles at once
- Treating config packs as universal truths
- Skipping pregen and blaming plugins for chunk lag
- Giving broad wildcard perms to regular players
- Running updates without rollback artifacts
โ Production Checklist#
- Java 21+, startup script with sane memory headroom
- Configs tracked in git
- Spark baseline report captured
- Chunky pregen done for active worlds
- Purpur feature toggles documented by intent
- Permission model audited
- Rollback JAR + config snapshot ready
Dynmap Optimization#
Map Plugin Comparison#
| Dynmap ๐ฆ | BlueMap ๐ง | Pl3xMap โก | |
|---|---|---|---|
| View | 2D + 3D Iso | Full 3D WebGL | 2D Top-down |
| Performance | Heavy | Medium (async) | Ultra-light |
| Storage | Massive | Large | Tiny |
Dynmap Tuning#
# Quality vs speed (vlowres = 16x faster than hires)
deftemplatesuffix: vlowres
# Image format (JPG > PNG for storage)
image-format: jpg
image-quality: 80
# Disable lag factories
render-triggers:
- chunkgenerated
# - playermove โ DISABLE
# - blockplaced โ DISABLE
- join
- quit
# Throttle
renderinterval: 1.0
tiles-rendered-at-once: 1
External Webserver (Critical)#
NEVER use the internal webserver for public servers:
disable-webserver: true
json-file: true
webpath: /var/www/html/dynmap
Serve via Nginx with tile caching (expires 7d).
Dynmap Commands#
/dynmap pause allโ before heavy server activity/dynmap purgequeueโ clear backed-up queue/dynmap fullrender worldโ run overnight inscreen
Plugin Architecture Best Practices#
Project Layout#
src/main/java/com/example/myplugin/
MyPlugin.java
bootstrap/
command/
listener/
service/
domain/
infra/
config/
Gradle (Kotlin DSL) Baseline#
repositories {
maven("https://repo.papermc.io/repository/maven-public/")
}
dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT")
testImplementation("org.junit.jupiter:junit-jupiter:5.11.4")
testImplementation("com.github.seeseemelk:MockBukkit-v1.21:4.63.0")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}
Lifecycle Discipline#
onLoad: Minimal setup only, avoid Bukkit APIonEnable: Register listeners/commands, init services, validate configonDisable: Cancel tasks, flush state, close DB/HTTP resources- Never rely on
/reloadโ full restart is the only supported path
Threading Rules#
- World/entity/block mutations: main thread (Paper) or correct context (Folia)
- DB/HTTP/files: async
- Never:
Thread.sleep()on main thread, blocking I/O on sync tasks - Always: async-to-sync pattern for DB โ UI updates
Folia Support#
# paper-plugin.yml
folia-supported: true
Only enable after real validation. Use entity scheduler for entity-bound work, region scheduler for location-bound work.
PDC (PersistentDataContainer)#
NamespacedKey key = new NamespacedKey(plugin, "custom-tier");
item.editPersistentDataContainer(pdc -> pdc.set(key, PersistentDataType.INTEGER, 3));
- Reuse
NamespacedKeyobjects - Use
getOrDefaultfor null-safe reads - PDC is NOT auto-copied between holders
Security Checklist#
- Validate command args strictly
- Cooldowns for heavy commands
- Per-player/IP rate limits
- HTTP timeouts + retries with jitter
- Secrets in env vars, never hardcoded