|
Build Papyrus / Build Papyrus (${{ matrix.mc }}) (21, 1.21.10, papyrus/1.21.10) (push) Failing after 2m44s
Details
Build Papyrus / Build Papyrus (${{ matrix.mc }}) (21, 1.21.11, papyrus/1.21.11) (push) Failing after 1s
Details
Build Papyrus / Build Papyrus (${{ matrix.mc }}) (21, 1.21.4, papyrus/1.21.4) (push) Failing after 1s
Details
Build Papyrus / Build Papyrus (${{ matrix.mc }}) (21, 1.21.8, papyrus/1.21.8) (push) Failing after 2s
Details
Build Papyrus / Build Papyrus (${{ matrix.mc }}) (25, 26.1.2, main) (push) Failing after 2s
Details
Build Papyrus / release (push) Has been skipped
Details
Use CraftNamespacedKey for registry and plugin channel lookups so backports with ResourceLocation compile alongside main's Identifier mappings. Keep applyPatches and build as separate Gradle invocations to satisfy task ordering. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| .github | ||
| build-data | ||
| gradle/wrapper | ||
| licenses | ||
| papyrus-api | ||
| papyrus-generator | ||
| papyrus-server | ||
| scripts | ||
| test-plugin | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| CONTRIBUTING.md | ||
| LICENSE.md | ||
| README.md | ||
| SECURITY.md | ||
| SUPPORTED_VERSIONS.txt | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| paper-server | ||
| settings.gradle.kts | ||
README.md
Papyrus
Papyrus is a Minecraft server software fork of Paper. It keeps full compatibility with the Paper plugin ecosystem (io.papermc.paper API, Paper plugins, and existing configs) while adding first-class options for vanilla parity and performance tuning.
Repository: github.com/codingsushi79/Papyrus
Documentation: docs.sushii.dev/papyrus
Table of contents
- What Papyrus adds
- Requirements
- Quick start
- Running in production
- Configuration
- Papyrus-specific options
- Integrated anticheat
- Performance tuning
- Vanilla compatibility preset
- Redstone presets
- Building from source
- Project structure
- Plugin development
- Continuous integration
- Contributing
- License
- Credits
- FAQ
What Papyrus adds
Paper optimizes Minecraft in ways that sometimes diverge from vanilla behavior. Papyrus makes those trade-offs explicit and configurable instead of fixed.
| Area | Paper behavior | Papyrus change |
|---|---|---|
| Entity RNG | Shared random source across all entities (faster) | Configurable: SHARED or VANILLA per-entity RNG |
| Redstone | Vanilla by default; optional fast engines | Same engines, documented presets for vanilla vs tech servers |
| Experience orbs | Paper defaults | Configurable despawn, pickup radius, merge radius, and merge disable |
| Performance defaults | Paper defaults | Tuned defaults for chunk I/O, explosions, hoppers, idle worlds, JVM/Netty |
| Update checker | Checks PaperMC | Disabled by default (fork-specific builds) |
| Anticheat | External plugins (GrimAC, etc.) | Built-in configurable engine (x-ray heuristics, reach, rates) |
Everything else — Moonrise chunk system, incremental saves, hopper optimizations, plugin API, and the patch-based build — comes from upstream Paper unchanged.
Requirements
Running a server
- Java 21+ to run the server jar (Java 25 recommended)
- 2 GB RAM minimum for small servers; 8 GB+ recommended for production
- A machine capable of running a Paper-based server (same as Paper)
Building from source
- Git — you must clone the repository; zip downloads will not build
- Java 25 JDK to compile (Gradle can auto-provision this via toolchains if you only have JRE 21+)
- ~4 GB RAM for Gradle during compilation
Current Minecraft version: 26.1.2 (see gradle.properties).
Quick start
1. Get the jar
From releases: Download Papyrus-<mcVersion>.jar (e.g. Papyrus-26.1.2.jar) from GitHub Releases or see Documentation → Download.
From CI: Download the papyrus-server artifact from the latest successful GitHub Actions build.
From source:
git clone https://github.com/codingsushi79/Papyrus.git
cd Papyrus
./gradlew applyPatches createPaperclipJar syncPapyrusPaperclipJar
The runnable jar is at:
papyrus-server/build/distributions/papyrus-paperclip-<version>.jar
2. First run
mkdir papyrus-server && cd papyrus-server
cp ../Papyrus/papyrus-server/build/distributions/papyrus-paperclip-*.jar .
java -jar papyrus-paperclip-*.jar
Accept the EULA by editing eula.txt, then start again. Papyrus generates configs on first boot:
config/
paper-global.yml # Global server settings
paper-world-defaults.yml # Defaults for all worlds
world/
paper-world.yml # Per-world overrides (optional)
spigot.yml # Spigot settings (activation ranges, etc.)
bukkit.yml
server.properties
Running in production
Start script
Papyrus includes a production start script with recommended G1GC flags:
# Copy the jar into your server directory first
cp /path/to/papyrus-paperclip-*.jar ./papyrus-paperclip.jar
# From the repo (or copy scripts/start.sh into your server dir)
JAR=papyrus-paperclip.jar ./scripts/start.sh
Environment variables:
| Variable | Default | Purpose |
|---|---|---|
JAVA |
java |
Path to Java binary |
JAR |
papyrus-paperclip.jar |
Server jar filename |
Edit -Xms8G -Xmx8G in the script to match your host. Always set -Xms equal to -Xmx to avoid heap resize pauses during gameplay.
Manual JVM flags
If you prefer not to use the script:
java -Xms8G -Xmx8G \
-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 \
-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch \
-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 \
-XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 \
-XX:InitiatingHeapOccupancyPercent=15 -XX:MaxTenuringThreshold=1 \
-jar papyrus-paperclip.jar nogui
Paper's Aikar flags documentation remains a good reference for tuning beyond these defaults.
Moonrise system properties
Optional JVM flags for advanced tuning:
| Property | Example | Effect |
|---|---|---|
Papyrus.WorkerThreadCount |
-DPapyrus.WorkerThreadCount=4 |
Override Moonrise worker thread count |
Papyrus.NumaScheduling |
-DPapyrus.NumaScheduling=true |
NUMA-aware threading on multi-socket hosts |
Papyrus.MaxViewDistance |
-DPapyrus.MaxViewDistance=32 |
Hard cap on view distance |
Configuration
Papyrus uses Paper's layered config system. Files are YAML; keys use kebab-case.
| File | Scope |
|---|---|
config/paper-global.yml |
Server-wide settings |
config/paper-world-defaults.yml |
Defaults applied to every world |
<world>/paper-world.yml |
Overrides for a specific world |
spigot.yml |
Entity activation/tracking ranges, hopper rates, Netty threads |
bukkit.yml |
Spawn limits, chunk settings |
server.properties |
Port, gamemode, difficulty, etc. |
After editing configs, restart the server or use /paper reload where supported (some settings require a full restart).
For Papyrus-specific options and presets, see docs.sushii.dev/papyrus. For the full Paper config reference, see docs.papermc.io. The sections below cover Papyrus-specific behavior and recommended values.
Papyrus-specific options
Entity random source
File: config/paper-global.yml
performance:
entity-random-source: SHARED # or VANILLA
apply-runtime-jvm-defaults: true # Netty buffer caps, JNA nosys
netty-threads: -1 # -1 = auto (4–8 based on CPU)
| Value | Behavior | Use when |
|---|---|---|
SHARED |
All entities share one random source (Paper default, faster) | Performance matters; enchantment seed manipulation is not needed |
VANILLA |
Each entity gets RandomSource.create() like vanilla |
Speedrunners, enchantment seed manipulation, or any vanilla-like RNG dependency |
Experience orbs
File: config/paper-world-defaults.yml or <world>/paper-world.yml
environment:
experience-orb-despawn-rate: 6000 # ticks (vanilla: 6000)
experience-orb-pickup-radius: 8.0 # blocks (vanilla: 8)
entities:
spawning:
experience-orb-merge-radius: 1.0 # merge search radius in blocks
behavior:
disable-experience-orb-merge: false
Lower experience-orb-pickup-radius to reduce orb lag on grinder servers. Set disable-experience-orb-merge: true if you want orbs to stay separate.
Lower experience-orb-pickup-radius to reduce orb lag on grinder servers. Set disable-experience-orb-merge: true if you want orbs to stay separate.
Redstone implementation
File: config/paper-world-defaults.yml or <world>/paper-world.yml
misc:
redstone-implementation: VANILLA # VANILLA | EIGENCRAFT | ALTERNATE_CURRENT
alternate-current-update-order: HORIZONTAL_FIRST_OUTWARD # only for ALTERNATE_CURRENT
| Engine | Speed | Vanilla parity |
|---|---|---|
VANILLA |
Baseline | Full — same update order as Minecraft |
EIGENCRAFT |
~95% fewer wire updates on depower | Different update order; fixes MC-11193 |
ALTERNATE_CURRENT |
Fastest in most benchmarks | Different update order; configurable direction |
Default is VANILLA. Switch to EIGENCRAFT or ALTERNATE_CURRENT only on redstone-heavy technical servers where speed matters more than vanilla timing.
Chunk system I/O threads
File: config/paper-global.yml
chunk-system:
io-threads: -1 # auto-detect from CPU count (recommended)
worker-threads: -1 # auto-detect from CPU count (recommended)
Papyrus auto-scales I/O threads to min(4, max(1, cpu_cores / 4)) when set to -1 or 0. Paper previously pinned this to a single I/O thread.
Integrated anticheat
Papyrus ships a built-in anticheat engine under config/paper-global.yml. It runs at packet level (before actions apply) and does not require a plugin. Disable external anticheat plugins if you use this to avoid duplicate kicks.
anticheat:
engine:
enabled: true
alerts:
console: true
notify-ops: false
punishments:
kick-enabled: true
kick-violation-level: 40
violation-decay-per-second: 2.0
checks:
xray:
enabled: true
window-seconds: 300
suspicious-ore-count: 14
tracked-ores:
- minecraft:diamond_ore
- minecraft:deepslate_diamond_ore
fast-place:
max-per-second: 12
cancel-action: true
fast-break:
max-per-second: 8
inventory:
max-clicks-per-second: 25
hand-swap:
max-swaps-per-second: 8
reach:
block-extra-distance: 0.35
movement:
max-horizontal-blocks-per-tick: 0.85
setback: true
timer:
max-packets-per-second: 140
| Check | What it detects |
|---|---|
| xray | Valuable ores mined unusually fast or with suspicious ore-to-stone ratios |
| fast-place / fast-break | Block place/break rates above human limits |
| inventory / hand-swap | Inventory click and offhand swap spam (autoclickers, quick swap macros) |
| reach | Block interactions beyond vanilla interaction range |
| movement | Horizontal/vertical movement per tick above configured limits |
| timer | Incoming packet rate spikes |
Bypass permission: papyrus.anticheat.bypass
Plugin hook: PlayerAnticheatViolationEvent — cancel the event to ignore a flag.
Item component obfuscation (anticheat.obfuscation) and per-world Anti-Xray (anticheat.anti-xray in world config) remain separate features and complement the engine.
Performance tuning
Papyrus performance defaults
These defaults apply to new config files. Existing servers keep their saved values until you change them manually.
Global (config/paper-global.yml)
| Key | Papyrus default | Effect |
|---|---|---|
chunk-system.io-threads |
auto | Scales chunk load/save throughput with CPU |
performance.entity-random-source |
SHARED |
Fast entity RNG |
performance.apply-runtime-jvm-defaults |
true |
Sets Netty buffer caps and jna.nosys at startup |
performance.netty-threads |
-1 (auto) |
Scales Netty event-loop threads (4–8) when not set in spigot.yml |
spark.enabled |
false |
No Spark profiler overhead |
misc.region-file-cache-size |
512 |
Larger region file cache (uses more RAM) |
update-checker.enabled |
false |
No PaperMC update checks |
World (config/paper-world-defaults.yml)
| Key | Papyrus default | Effect |
|---|---|---|
misc.update-pathfinding-on-block-update |
false |
Mobs don't repath on every nearby block change |
environment.optimize-explosions |
true |
Faster TNT/creeper blast processing |
environment.experience-orb-despawn-rate |
6000 |
Ticks until XP orbs despawn (vanilla: 6000) |
environment.experience-orb-pickup-radius |
8.0 |
Player pickup range in blocks |
entities.spawning.experience-orb-merge-radius |
1.0 |
Radius for orb merge search |
entities.behavior.disable-experience-orb-merge |
false |
When true, orbs never merge |
unsupported-settings.disable-world-ticking-when-empty |
true |
Worlds with no players stop ticking |
hopper.ignore-occluding-blocks |
true |
Hoppers skip entity scans under solid blocks |
entities.armor-stands.tick |
false |
Armor stands don't tick (display/map servers) |
entities.markers.tick |
false |
Marker entities don't tick |
scoreboards.allow-non-player-entities-on-scoreboards |
false |
Skips scoreboard team lookups for non-players |
chunks.entity-per-chunk-save-limit.* |
capped | Limits arrow/orb/pearl buildup per chunk |
Spigot (spigot.yml)
| Key | Papyrus default | Effect |
|---|---|---|
commands.log |
false |
No disk I/O logging every command |
settings.netty-threads |
auto | Scales Netty I/O threads with CPU when unset |
Spigot entity ranges (manual tuning)
For mob-heavy servers, lower tracking and activation ranges in spigot.yml:
world-settings:
default:
entity-tracking-range:
animals: 48
monsters: 48
misc: 32
entity-activation-range:
animals: 24
monsters: 24
water: 8
villagers: 16
Tracking controls network packets; activation controls server-side AI ticks. Lower both before touching game rules.
Vanilla compatibility preset
Use this when vanilla behavior matters more than peak performance (speedrunning, strict survival, enchantment seed work):
# config/paper-global.yml
performance:
entity-random-source: VANILLA
# config/paper-world-defaults.yml
misc:
redstone-implementation: VANILLA
update-pathfinding-on-block-update: true # restore Paper-like mob repathing
environment:
optimize-explosions: false
entities:
armor-stands:
tick: true
markers:
tick: true
Also set entity-random-source: VANILLA if players use enchantment table seed manipulation — this is the setting that restores per-entity RNG.
Redstone presets
Vanilla survival (default)
misc:
redstone-implementation: VANILLA
Technical / farm server
misc:
redstone-implementation: EIGENCRAFT
Maximum wire performance
misc:
redstone-implementation: ALTERNATE_CURRENT
alternate-current-update-order: HORIZONTAL_FIRST_OUTWARD
Test contraptions after switching engines. Timing and update order will differ from vanilla.
Building from source
git clone https://github.com/codingsushi79/Papyrus.git
cd Papyrus
# Apply Minecraft patches and compile
./gradlew applyPatches build
# Create the runnable paperclip jar (copied to papyrus-paperclip-*.jar)
./gradlew createPaperclipJar syncPapyrusPaperclipJar
Common Gradle tasks:
| Task | Purpose |
|---|---|
./gradlew applyPatches |
Apply all Minecraft source patches |
./gradlew build |
Compile and run tests |
./gradlew createPaperclipJar |
Build the downloadable server jar |
./gradlew syncPapyrusPaperclipJar |
Copy paperclip output to papyrus-paperclip-*.jar |
./gradlew rebuildPatches |
Regenerate patch files after editing papyrus-server/src/minecraft |
./gradlew fixupSourcePatches |
Fix patch context after manual edits |
Windows: use gradlew instead of ./gradlew.
Development requires cloning with Git — the build system applies patches against a generated git tree inside papyrus-server/src/minecraft. Downloading a zip from GitHub will not work.
See CONTRIBUTING.md for patch workflow details (inherited from Paper).
Project structure
Papyrus/
├── papyrus-api/ Public Bukkit/Paper plugin API (Gradle project :paper-api)
├── papyrus-server/ Server implementation (Gradle project :paper-server)
├── paper-server/ Symlink → papyrus-server (required by Paperweight patch tooling)
│ ├── patches/ Minecraft source patches (sources/, features/, resources/)
│ └── src/main/java/ Papyrus/Paper Java code (io.papermc.paper.*)
├── build-data/ Access wideners and mapping data
├── scripts/
│ └── start.sh Production JVM start script
├── gradle.properties MC version, apiVersion, Maven group
└── .github/workflows/ CI build, tests, and release uploads
Gradle project names stay :paper-api and :paper-server so upstream Paperweight and plugin examples keep working. Physical directories use the papyrus-* prefix.
Maven coordinates remain io.papermc.paper:paper-api for plugin compatibility. The API jar embeds apiVersioning.json (from apiVersion in gradle.properties) for runtime version checks.
Plugin development
Papyrus is API-compatible with Paper plugins. Use the same dependency and plugin metadata format.
Dependencies
Gradle (Kotlin DSL):
repositories {
maven("https://repo.papermc.io/repository/maven-public/")
}
dependencies {
compileOnly("io.papermc.paper:paper-api:26.1.2-R0.1-SNAPSHOT")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}
Maven:
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>26.1.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
Replace the version with the current apiVersion from gradle.properties. Papyrus does not publish its own Maven repository; the API matches Paper's published artifact.
paper-plugin.yml
name: MyPlugin
version: 1.0.0
main: com.example.myplugin.MyPlugin
api-version: '26.1.2' # must match gradle.properties apiVersion
Use api-version matching gradle.properties. Paper plugins use paper-plugin.yml; legacy Bukkit plugins use plugin.yml instead.
Detecting Papyrus at runtime
import io.papermc.paper.ServerBuildInfo;
import net.kyori.adventure.key.Key;
ServerBuildInfo info = ServerBuildInfo.buildInfo();
if (info.brandId().equals(ServerBuildInfo.BRAND_PAPYRUS_ID)) {
// Running on Papyrus (sushimc:papyrus)
}
if (info.isBrandCompatible(ServerBuildInfo.BRAND_PAPER_ID)) {
// true on both Paper and Papyrus — use for generic Paper-targeted plugins
}
Local development against this repo
dependencies {
compileOnly(project(":paper-api"))
}
Run ./gradlew publishToMavenLocal to install paper-api locally, then add mavenLocal() above the PaperMC repository in your plugin project. See CONTRIBUTING.md for running the included test-plugin module.
More plugin guides: docs.sushii.dev/papyrus and docs.papermc.io/paper/dev.
Continuous integration
GitHub Actions builds on every push and pull request to main:
- Apply Minecraft patches
- Compile and run tests
- Build the paperclip jar
- Upload CI artifacts (
papyrus-serverjar + test results)
Releases: Pushing a version tag (e.g. v1.0.1) creates a GitHub Release with Papyrus-<mcVersion>.jar attached automatically. No external secrets are required.
Download CI builds from the Actions tab on github.com/codingsushi79/Papyrus.
Contributing
Papyrus inherits Paper's patch-based development workflow. To contribute:
- Fork codingsushi79/Papyrus
- Clone your fork and create a feature branch from
main - Make changes — Java code in
papyrus-server/src/main/java/directly, Minecraft changes via the patch system - Run
./gradlew buildto verify - Open a pull request against
main
See CONTRIBUTING.md for the full patch workflow. SECURITY.md covers vulnerability reporting.
License
Papyrus inherits licensing from Paper, Spigot, and CraftBukkit. See LICENSE.md for details.
Credits
- Paper by PaperMC — upstream server software
- Spigot / CraftBukkit — original Bukkit implementation
FAQ
Is Papyrus compatible with Paper plugins?
Yes. Same API package (io.papermc.paper), same Maven artifact (io.papermc.paper:paper-api), same config file names, same paper-plugin.yml format. Gradle modules are named :paper-api / :paper-server but live in papyrus-* directories. Use ServerBuildInfo.BRAND_PAPYRUS_ID only if you need Papyrus-specific behavior.
What's the difference between performance.netty-threads and spigot.yml Netty settings?
performance.netty-threads in paper-global.yml sets io.netty.eventLoopThreads when spigot.yml does not override Netty thread count. Set either one, not both, unless you know you need different values.
Will my existing Paper config work?
Yes. Drop in your existing config/, spigot.yml, and worlds. Papyrus-specific defaults only apply to keys that aren't already set.
How do I restore enchantment seed manipulation?
Set performance.entity-random-source: VANILLA in config/paper-global.yml and restart.
How do I get vanilla redstone behavior?
Set misc.redstone-implementation: VANILLA in your world config. This is already the default.
Why is the jar named papyrus-paperclip?
The bootstrap tool (paperclip) comes from upstream Paper. Papyrus copies the build output to papyrus-paperclip-*.jar.
Can I use GrimAC or another anticheat plugin alongside Papyrus?
You can, but Papyrus includes a built-in engine (anticheat.engine in paper-global.yml). Running both may cause duplicate flags — disable one or set anticheat.engine.enabled: false if you prefer an external plugin.
Where do I report bugs?
Open an issue at github.com/codingsushi79/Papyrus/issues. Specify whether the bug exists in upstream Paper or is Papyrus-specific.
Can I redistribute the built jar?
Yes, under the terms of the GPL/MIT licenses described in LICENSE.md.