Gale is a drop-in replacement for Paper that improves performance reliably and without changing game mechanics.
- Download the latest dev build from GitHub Actions
- Replace the Paper server
.jarfile with the Gale.jarfile
-
High reliability
All features are reviewed with care, verified line-by-line and tested in production. -
No changes to game mechanics
Gale improves performance without changing behavior (by default).
Editing the configuration is optional.
Pull requests are welcomed! Don't be afraid to submit a pull request that you may feel is just for yourself. All ideas are welcome. If submitted pull requests do not meet our standards, we can work together to improve them.
- Clone the project
- Run
./gradlew applyAllPatches - Run
./gradlew :gale-server:createPaperclipJar
Of course, this fork would not exist without the years-long work of all the contributors to Paper.
Additional thanks goes out to the contributors to Spigot and Bukkit, and to the contributors to other Minecraft server software.
Gale includes only strongly verified performance improvements. If you need even more performance, you can try Leaf, which comes with more features.
Paperweight files are licensed under MIT. Patch files and binaries are licensed under GPL-3.0.
All included features are listed below.
Features originating from other projects are carefully verified and updated as part of Gale.
-
Branding
Server identifies as Gale, with appropriate branding in console, watchdog, and version output.
-
Configuration
Gale configuration files.
-
Allocate zero or one block destruction packets (original by vytskalt)
Leaf: Reduce-block-destruction-packet-allocations.patch
-
Cache Identifier toString and hashCode (original by OverwriteMC)
Lazily cache Identifier toString() and hashCode().
Leaf: Cache-identifier-toString-and-hash.patch
-
Cache world generator sea level (original by jaskarth)
This method is potentially called for every block in the chunk,
so this will save a lot of registry lookups.
Leaf: Cache-world-generator-sea-level.patch
-
Check targeting range before getting visibility (original by PaulBGD)
Check targeting range before computing visibility distance,
because the latter is more expensive.
Leaf: Check-targeting-range-before-getting-visibility.patch
-
Delay canSee check in entity collisions
Perform other checks before canSee,
because the latter is more expensive.
Leaf: Reduce-canSee-work.patch
-
Don't iterate over empty tick effect collections ((original by hayanesuru)
Leaf: part of optimize-tickEffects.patch
-
Inline player UUID comparison
-
Initialize sensing with low capacity
Most mobs only ever target at most 1 entity (typically a nearby player or a mob farm bait entity)
so we create their sensing cache with an initial capacity of 2 instead of 16.
Leaf: Initialize-line-of-sight-cache-with-low-capacity.patch
-
Minimize size of packed dirty synched entity data item list (original by hayanesuru)
Leaf: Optimize-SynchedEntityData-packDirty.patch
-
Only update frozen ticks if changed (original by hayanesuru)
Leaf: Only-update-frozen-ticks-if-changed.patch
-
Optimize entity data serializer list
Make EntityDataSerializers#SERIALIZERS a simple list
and store the index in each EntityDataSerializer directly.
-
Optimize global block state palette
Store the index in Block#BLOCK_STATE_REGISTRY in each BlockState directly.
-
Optimize matching item checks
Leaf: Optimize-matching-item-checks.patch
-
Optimize pushable selector (original by OverwriteMC)
Avoid duplicated Bukkit#isPushable check, already checked inside the Bukkit#canCollideWithBukkit.
Leaf: Optimize-pushable-selector.patch
-
Optimize registry values
Optimize registry value to id conversion, and optimize maps that use registry values as keys.
-
Optimize tag checks
Store the tags for each registry value in an efficient data structure.
-
Pre-compute biome fiddle table (original by hayanesuru)
Leaf: part of cache-biome-for-mob-spawning-and-advancements.patch
-
Pre-compute block state predicates (original by hayanesuru)
Pre-computes some commonly tested predicates on BlockBehaviour.
Leaf:
- part of
Cache-block-state-tags.patch
optimize-canHoldAnyFluid.patch
- part of
optimize-getOnPos.patch
optimize-isStateClimbable.patch
-
Reduce RandomSource instances (original by foss-mc)
Re-use RandomSource instances where it doesn't affect game mechanics.
Leaf: Reduce-RandomSource-instances.patch
-
Replace division by multiplication (original by 2No2Name)
Multiplication is faster than division in every environment.
Leaf: Replace-division-by-multiplication-in-CubePointRange.patch
-
Skip Bukkit callEvent early if no listeners (original by lilingfengdev)
Leaf: Skip-event-if-no-listeners.patch
-
Skip cloning advancement criteria (original by etil2jz)
Leaf: Skip-cloning-advancement-criteria.patch
-
Skip enderman teleport if requires main thread chunk load (original by PaulBGD)
Leaf: Reduce-enderman-teleport-chunk-lookups.patch
-
Skip entity move if movement is zero (original by ishland)
Run a simplified version of Entity#move() if the movement delta is zero.
Leaf: Skip-entity-move-if-movement-is-zero.patch
-
Skip negligible planar movement multiplication
Skip calling Entity#getBlockSpeedFactor() from Entity#move()
when planar delta movement is negligible (within 1.0E-6 threshold).
Leaf: Skip-negligible-planar-movement-multiplication.patch
-
Skip PlayerCommandSendEvent if no listeners (original by BillyGalbreath)
Leaf: Skip-PlayerCommandSendEvent-if-there-are-no-listener.patch
-
Skip canSee self check for chunk map player update (original by MrPowerGamerBR)
Skip the self check in CraftPlayer#canSee if called from ChunkMap#updatePlayer,
as it is checked already at that point.
Leaf: SparklyPaper-Optimize-canSee-checks.patch
-
Sort tryAddFrost checks (original by 2No2Name)
Sort the checks in LivingEntity#tryAddFrost()
in ascending order of cost.
Leaf: Check-frozen-ticks-before-landing-block.patch
-
Store canSee in a fast-access format
Complement the map that backs canSee
by a packed boolean array for fast operations.
-
Store despawn ranges in enum map (original by hayanesuru)
Leaf: part of optimize-despawn.patch
-
Store mob counts in an array (original by ishland)
Leaf: Store-mob-counts-in-an-array.patch
-
Store seenBy in a fast-access format
Replace the seenBy set by a list (for fast iteration)
and packed boolean array (for fast contains checks).
-
Update boss bar within tick (original by jellysquid3)
Performs boss bar update code at most once per tick during tick(),
instead of every time updateBossbar() is called.
Leaf: Update-boss-bar-within-tick.patch
-
Use fastutil collections
Use it.unimi.dsi.fastutil collections
instead of other (such as java.util) collections.
Leaf: Replace-throttle-tracker-map-with-optimized-collecti.patch
-
Use linked collections
Use linked data structures for collections that are frequently iterated over.
Leaf: Use-linked-map-for-entity-trackers.patch
Server identifies as Gale, with appropriate branding in console, watchdog, and version output.
Gale configuration files.
Leaf:
Reduce-block-destruction-packet-allocations.patch
Lazily cache
Identifier toString() and hashCode().Leaf:
Cache-identifier-toString-and-hash.patch
This method is potentially called for every block in the chunk, so this will save a lot of registry lookups.
Leaf:
Cache-world-generator-sea-level.patch
Check targeting range before computing visibility distance, because the latter is more expensive.
Leaf:
Check-targeting-range-before-getting-visibility.patch
Perform other checks before
canSee,
because the latter is more expensive.Leaf:
Reduce-canSee-work.patch
Leaf: part of
optimize-tickEffects.patch
Most mobs only ever target at most 1 entity (typically a nearby player or a mob farm bait entity)
so we create their sensing cache with an initial capacity of 2 instead of 16.
Leaf:
Initialize-line-of-sight-cache-with-low-capacity.patch
Leaf:
Optimize-SynchedEntityData-packDirty.patch
Leaf:
Only-update-frozen-ticks-if-changed.patch
Make
EntityDataSerializers#SERIALIZERS a simple list
and store the index in each EntityDataSerializer directly.
Store the index in
Block#BLOCK_STATE_REGISTRY in each BlockState directly.
Leaf:
Optimize-matching-item-checks.patch
Avoid duplicated
Bukkit#isPushable check, already checked inside the Bukkit#canCollideWithBukkit.Leaf:
Optimize-pushable-selector.patch
Optimize registry value to id conversion, and optimize maps that use registry values as keys.
Store the tags for each registry value in an efficient data structure.
Leaf: part of
cache-biome-for-mob-spawning-and-advancements.patch
Pre-computes some commonly tested predicates on
BlockBehaviour.Leaf:
- part of
Cache-block-state-tags.patch optimize-canHoldAnyFluid.patch- part of
optimize-getOnPos.patch optimize-isStateClimbable.patch
Re-use
RandomSource instances where it doesn't affect game mechanics.Leaf:
Reduce-RandomSource-instances.patch
Multiplication is faster than division in every environment.
Leaf:
Replace-division-by-multiplication-in-CubePointRange.patch
Leaf:
Skip-event-if-no-listeners.patch
Leaf:
Skip-cloning-advancement-criteria.patch
Leaf:
Reduce-enderman-teleport-chunk-lookups.patch
Run a simplified version of
Entity#move() if the movement delta is zero.Leaf:
Skip-entity-move-if-movement-is-zero.patch
Skip calling
Entity#getBlockSpeedFactor() from Entity#move()
when planar delta movement is negligible (within 1.0E-6 threshold).Leaf:
Skip-negligible-planar-movement-multiplication.patch
Leaf:
Skip-PlayerCommandSendEvent-if-there-are-no-listener.patch
Skip the self check in
CraftPlayer#canSee if called from ChunkMap#updatePlayer,
as it is checked already at that point.Leaf:
SparklyPaper-Optimize-canSee-checks.patch
Sort the checks in
LivingEntity#tryAddFrost()
in ascending order of cost.Leaf:
Check-frozen-ticks-before-landing-block.patch
Complement the map that backs
canSee
by a packed boolean array for fast operations.
Leaf: part of
optimize-despawn.patch
Leaf:
Store-mob-counts-in-an-array.patch
Replace the
seenBy set by a list (for fast iteration)
and packed boolean array (for fast contains checks).
Performs boss bar update code at most once per tick during
tick(),
instead of every time updateBossbar() is called.
Leaf:
Update-boss-bar-within-tick.patch
Use
it.unimi.dsi.fastutil collections
instead of other (such as java.util) collections.Leaf:
Replace-throttle-tracker-map-with-optimized-collecti.patch
Use linked data structures for collections that are frequently iterated over.
Leaf:
Use-linked-map-for-entity-trackers.patch
