#paper

33814 messages · Page 34 of 34 (latest)

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Expected behavior

When creating a VirtualComponent with a custom VirtualComponentRenderer, the component should be rendered by the Paper server as long as the renderer doesn't return null.

Observed/Actual behavior

The component isn't rendered anywhere

Steps/models to reproduce

  1. Create a custom virtual component
  2. Send it to your player
  3. Receive empty message

Plugin and Datapack List

Only my plugin

Paper version

This server is running Paper version 26.1.2-5-main@d61d8df (2026-04-11T14:20:55Z) (Implementing API version 26.1.2.build.5-alpha)

Other

This is an API issue, not a plugin or gameplay bug

rustic folioBOT
rustic folioBOT
#

Closes #13900

Features

  • Event Purpose: Allows plugins to monitor, modify, or cancel the disenchanting/repair action inside the grindstone.
  • Experience Control: Plugins can read and modify the amount of experience dropped from the action via getExperience() and setExperience().
  • Bulletproof Cancellation: The cancellation handling correctly covers standard clicks, Shift-clicks (via quickMoveStack), and dropping the item using the drop key (via ContainerInput.THROW), preventing any item duplication or ghost item bugs.
rustic folioBOT
#

Expected behavior

PlayerInventorySlotChangeEvent#getSlot() and PlayerInventorySlotChangeEvent#getRawSlot() should reliably identify the changed slot in the player's own inventory, especially for armor/offhand slots.

Observed/Actual behavior

When a player has another inventory view open, for example a chest, and an armor slot changes due to external causes, such as a zombie attacking the player and damaging armor durability, PlayerInventorySlotChangeEvent is fired, but the slot values appear incorrect or misleading.

In this case:

  • event.getRawSlot() does not behave as expected for the currently changed player inventory slot.
  • event.getSlot() appears to be converted using the currently open InventoryView.
  • Because the player is viewing a chest, event.getSlot() may map to a slot in the chest view instead of representing the actual armor slot that changed.

This makes it difficult or impossible for plugins to safely detect armor slot changes using this e...

rustic folioBOT
#

Expected behavior

Calling LimitedRegion#spawnEntity(Location, EntityType) from a BlockPopulator during chunk generation should spawn the entity (or, if the entity can't be
created, fail gracefully / return null) — regardless of the world's difficulty. This works on easy, normal, and hard.

Observed/Actual behavior

On a peaceful world, calling LimitedRegion#spawnEntity(...) with a monster type (e.g. ZOMBIE, DROWNED, GUARDIAN) during chunk generation throws an NPE inside Paper. Peaceful disallows hostile mobs, so the entity factory produces a null entity, and RegionAccessor#spawnEntity does not null-check it before calling entity.absSnapTo(...). The exception is raised on a chunk-system worker thread, so it escalates to unrecoverableChunkSystemFailure → "Chunk system crash" → the server shuts down.

It is difficulty-dependent: identical code/world spawns the same monster fine on easy/normal/hard, and crashes only on peaceful. Non-monster entities are unaf...

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

This PR resolve https://github.com/PaperMC/Paper/issues/13992 by making the request to spawn ignore the internal checks, most of them are already make in the API side, this make the behaviour of the spawn works like 26.1 where the method just not spawn the mob if cannot.

PD: Also add a few Nullable annotation for consider in the future the methods for createLiving use another where a null is expected in future...

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Stack trace

Both Vanilla and Paper have this issue when loading deep dark biomes.
See MC-307918.

This is not exactly a stacktrace or exception, is an error log that might get spammed without printing any stacktrace or interrupting the execution of any code.
Still it print a large wall of error logs that is hard to ignore.

Log in Paper:
https://pastes.dev/x7sueyL2oN

Plugin and Datapack List

Datapacks:
None

Plugins:
Worlds

Actions to reproduce (if known)

To re-create on Paper:

  1. Create a new server
  2. Install a world manager, in this case Worlds
  3. Generate a single-biome deep dark world using /world create test type single-biome minecraft:deep_dark
  4. When teleported, fly around for a bit
  5. Check the console

Seems to be related to the sculk propagating randomly, so it might take a couple of tries, although the single biome world should make it extremely co...

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Expected behavior

A plugin that resolves protobuf-java 4.34.0 (e.g. transitively through micrometer-registry-otlp or the OTLP exporter) should be able to use it at runtime. That satisfies protobuf's runtime >= gencode rule.

Observed/Actual behavior

Paper bundles mysql-connector-j, which pulls com.google.protobuf 4.29.x onto the shared classpath. Paper's bundled copy wins over the plugin's 4.34.0, so protobuf's runtime check blows up at class init:

com.google.protobuf.RuntimeVersion$ProtobufRuntimeVersionException:
... runtime 4.29.x. Runtime version cannot be older than the linked gencode version.

This was already reported in #13835 and closed as won't fix, with relocation suggested as the workaround. I'm opening this because relocation doesn't fully work for OpenTelemetry.

Relocating OTel isn't really viable: the Java agent relies on canonical class names (io.opentelemetry., io.grpc.) to instrument libraries, and context keys can't be relocated withou...

rustic folioBOT
rustic folioBOT
#

Expected behavior

Zombies with ShouldBurnInDay false shouldn't burn in Daylight

Observed/Actual behavior

Zombies still catching fire.

Steps/models to reproduce

Summon Zombie:
/summon zombie ~ ~ ~ {Paper.ShouldBurnInDay: 0b}

Check Data:
/data get entity @e[type=minecraft:zombie,sort=nearest,limit=1]

Plugin and Datapack List

[20:49:40 INFO]: ℹ Server Plugins (24):
[20:49:40 INFO]: Bukkit Plugins:
[20:49:40 INFO]: - CoreProtect, MEAdmin, MEBuild, MEchat, MEClans, MEconomy, MEHandler, MEitems, MEMarket, MEMounts
[20:49:40 INFO]: MEnpc, MEPets, MERoles, MESlots, MESpawner, MEStorage, MEVote, MEWars, MEWorlds, Plan
[20:49:40 INFO]: ProtocolLib, Spartan, Tebex, VotifierPlus

Paper version

[20:50:09 INFO]: This server is running Paper version 1.21.11-132-ver/1.21.11@c5eb079 (2026-05-11T11:43:09Z) (Implementing API version 1.21.11-R0.1-SNAPSHOT)

Other

[20:46:09] [Render thread/INFO]: [System] [CHAT] Zombie has the following entity data: {Paper.Spa...

rustic folioBOT
#
[PaperMC/Paper] branch deleted: feature/dc
rustic folioBOT
#
[PaperMC/Paper] branch deleted: dev/26.2
rustic folioBOT
#

Some random issues I have found so far while working on updating Newwind to 26.2:

  • EntitySpawnEvent is called twice for XP orbs.
  • Non-savable passengers can save even if miscSerialization isn't allowed because its checking the wrong entity.
  • CraftCreatureSpawner uses maxInclusive twice instead of minInclusive.
  • PaperWrittenBookContent.asBook() uses requireNonNull wrongly.
  • PaperConsumable data component toBuilder() doesn't include hasConsumeParticles.
  • BukkitBrigForwardingMap wrongly returns early (probably doesn't matter though)
  • SizeLimitedSet is off by one (basically inconsequential)
  • Vanilla world migration (probably?) doesn't clear legacy PDC properly because dynamics are immutable.
  • "changed" and "clicked" are swapped in PlayerBucketFillEvent (you might wanna keep this one as is incase it breaks existing plugins idk)
  • PlayerShearEntityEvent drops weren't actually immutable.
  • There are some typos and missing closing curly brackets/apostrophes.
rustic folioBOT
#

Summary

Adds a projectiles.uncertainty section to paper-global.yml that allows server owners to override the uncertainty parameter passed to Projectile#shoot on a per-entity-type basis.

  • Introduces ProjectileUncertainty.resolve(EntityType, float) to look up configured values from GlobalConfiguration
  • Configuration keys are Minecraft entity type ids (e.g. minecraft:arrow, minecraft:snowball)
  • Unconfigured types keep vanilla behavior; setting a value to 0 removes random spread for that projectile type
  • Per-entry default preserves the vanilla uncertainty for that call site

Configuration is applied at the call sites where uncertainty is originally passed (bow/crossbow shootProjectile, throwable items, mob ranged attacks, dispensers, and Bukkit API launch paths), not inside Projectile#shoot or the shared spawn helpers.

Configuration example

projectiles:
  uncertainty:
    minecraft:arrow: 0
    minecraft:snowball: 0
    mi...
#

Summary

Adds a projectiles.uncertainty section to paper-global.yml that allows server owners to override the uncertainty parameter passed to Projectile#shoot on a per-entity-type basis.

  • Introduces ProjectileUncertainty.resolve(EntityType, float) to look up configured values from GlobalConfiguration
  • Configuration keys are Minecraft entity type ids (e.g. minecraft:arrow, minecraft:snowball)
  • Unconfigured types keep vanilla behavior; setting a value to 0 removes random spread for that projectile type
  • Per-entry default preserves the vanilla uncertainty for that call site

Configuration is applied at the call sites where uncertainty is originally passed (bow/crossbow shootProjectile, throwable items, mob ranged attacks, dispensers, and Bukkit API launch paths), not inside Projectile#shoot or the shared spawn helpers.

Configuration example

projectiles:
  uncertainty:
    minecraft:arrow: 0
    minecraft:snowball: 0
    mi...
rustic folioBOT
#

Is your feature request related to a problem?

It is currently impossible to update a specific world clock using it's key (ex: "minecraft:overworld")

Describe the solution you'd like.

An api to update world clocks, maybe
In Player:
void setPlayerTime(Key clock, long time, boolean tickTime)
long getPlayerTime(Key clock)
in World:
void setTime(Key clock, long time)
long getTime(Key clock)
void setFullTime(Key clock, long time)
long getFullTime(Key clock)

Describe alternatives you've considered.

1/ Sending ClientboundSetTimePacket using the protocolib plugin, however the clockUpdates field of this packet does not yet have an api for it.
2/ Sending ClientboundSetTimePacket using NMS. haven't tried yet, but i should work.

Other

No response

rustic folioBOT
rustic folioBOT
#

Isn't it possible to recreate the world_gen_settings.dat, like done in createNewWorldData if missing? I don't think paper should fail this gracefully here, especially if this also happens when the server fails to fully create the world the first time it starts up (like when e.g. another server is running on the same port)

See an example of where this is a problem here: https://mclo.gs/rUXPi0V (This is not using your patch for world migration, but it should come to the same conclusion)

Sure, this can be easily fixed, although I think it shouldn't be a too difficult fix for something that will definetly happen to more people in the future

#

Isn't it possible to recreate the world_gen_settings.dat, like done in createNewWorldData if the overworld dimension missing? I don't think paper should fail this gracefully here, especially if this also happens when the server fails to fully create the world the first time it starts up (like when e.g. another server is running on the same port)

See an example of where this is a problem here: mclo.gs/rUXPi0V (This is not using your patch for world migration, but it should come to the same conclusion)

Sure, this can be easily fixed by users, although I think it shouldn't be a too difficult fix for something that will definitely happen to more people in the future

This require maybe not remove the gen file when migration its done for use when remove in vanilla (in vanilla you can force this error too but require more steps)... but this PR is for another thing, if you can open an issue related to this.

rustic folioBOT
#

A drawback of BlockDropItemEvent is that the list of drops provided covers all items produced during the entire neighbor update phase. As a result, if you break a block with a torch on top you get one BlockDropItemEvent with both the block's drop and the torch.

If you want to replace the dropped item, this usually wouldn't be an issue since most blocks only drop one item. If you wanted to replace what torches drop via a plugin you'd just replace all instances of Material.TORCH in all BlockDropItemsEvent.

The problem is if vanilla loot tables have been modified via a datapack. It may not be possible to look at the list of drops from the entire update chain and determine what blocks dropped items and which drops belong to which block.

BlockDropResourcesEvent is called from within Block.dropResources and so will capture the exact list of drops generated for each individual block being broken, whether it was broken directly by a player or indirectly. Without t...

rustic folioBOT
#

Can confirm an event like this would fill a huge gap in the existing API, I actually brought up making this exact kind of event in the paper discord (and made the changes locally) but I never opened the PR because I wasn't sure it would be accepted. (I didn't much of a response from the paper team in the discord server.)
See: [Original Conversation](#paper-dev message) & [Paper Team Question](#paper-dev message) for context on other reasons you might need an event like this.

rustic folioBOT
#

Problem

The connection throttle cleanup in ServerHandshakePacketListenerImpl wipes the entire throttleTracker every ~200 connections. The cleanup predicate compares a stored timestamp against the throttle duration:

throttleTracker.values().removeIf(time -> time > connectionThrottle);

time is an epoch-millisecond timestamp (~1.7e12); connectionThrottle is a duration (default 4000ms). So time > connectionThrottle is always true and every entry is removed. The check a few lines above already does it correctly:

currentTime - throttleTracker.get(address) < connectionThrottle

Within a cleanup cycle the per-IP throttle works, but every 200th connection clears the map, so a client can time reconnects around the cleanup and slip past the throttle.

Fix

Compare elapsed time, reusing the currentTime already computed in the same block:

throttleTracker.values().removeIf(time -> currentTime - time > connectionThrottle);

This is...

rustic folioBOT
rustic folioBOT
#

Expected behavior

org.bukkit.block.Block#applyBoneMeal(BlockFace) returns true when bone meal is successfully applied (e.g. a crop advances a growth stage).

Observed/Actual behavior

It returns false even when the application succeeds and the block visibly grows. The growth happens - only the boolean is wrong. This breaks any plugin that branches on the return value (e.g. to consume an item / count successes).

CraftBlock#applyBoneMeal(BlockFace) checks the result against InteractionResult.SUCCESS:

return result == InteractionResult.SUCCESS && (event == null || !event.isCancelled());

But since the 1.21.2 InteractionResult refactor, BoneMealItem.applyBonemeal(...)`` returns InteractionResult.SUCCESS_SERVER, not SUCCESS`:

// net/minecraft/world/item/BoneMealItem.java (Paper-extracted applyBonemeal)
if (growCrop(boneMealStack, level, pos)) {
    if (!level.isClientSide()) {
        ...
        return InteractionResult.SUCCESS_SERVER;   //````...
rustic folioBOT
#

Expected behavior

Keep inventory works for all dimensions

Observed/Actual behavior

Only enables it for the overworld

Steps/models to reproduce

Enable keep inventory

Plugin and Datapack List

/plugins
i
[18:07:22 INFO]: Server Plugins (18): [18:07:22 INFO]: Paper Plugins (2):
[18:07:22 INFO]: JEIRecipeBridge, Veinmine
r
[18:07:22 INFO]: Bukkit Plugins (16):
[18:07:22 INFO]: Essentials, EssentialsCha t, EssentialsGeoIP, floodgate, Geyser-Spigot, GriefPrevention, Invsee, LuckPerms, Orebfusc ator, ProtocolLib
[18:07:22 INFO]: ServerLinksZ, *Vault, ViaBa ckwards, ViaVersion, WorldEdit, WorldGuard

Paper version

/version
[18:11:29 INF0]: Checking version, please wai
t.
[18:11:29 INF0]: This server is running Paper
version 26.1.2-72-ver/26.1.2@1a6b910 (2026-0
6-19T13:08:47Z) (Implementing API version 26.
1.2.build.72-stable)
You are running the latest version

Other

No response

rustic folioBOT
rustic folioBOT
#

Is your feature request related to a problem?

Currently when trying to gate logic behind MC versions in plugins you need to implement some sort of a version matcher for MC versions or use protocol versions.

Describe the solution you'd like.

I would like to see the server’s latest supported API version exposed in the API along with an isCompatible() method to make version dependent plugin code cleaner.

A possible implementation could look similar to to ServerBuildInfo with the latest plugin API version supported by the server being exposed along with something like ApiVersionInfo#isCompatible(String version)

Describe alternatives you've considered.

mentioned above

Other

No response

rustic folioBOT
rustic folioBOT
#

Simply adds a method to Player which exposes the resetFlyingTicks method from ServerGamePacketListenerImpl.

This is particularly useful for preventing the "flying" kick without having event spam. While you could enable the "allow-flight" option in server.properties, I find that allowing developers to have a method to reset this counter themselves would be useful.

For example, my use case is for my PacketBlocks plugin where players standing on them would be kicked for flying. Currently I require you to enable"allow-flight" however understandbly some server owners may not want to do this.

rustic folioBOT
#

Is your feature request related to a problem?

Currently, paper-plugin.yml uses name as both the plugin’s identifier and its display name. This couples two different concepts:

  • a unique, stable plugin ID used for dependency resolution, lookup, and internal references
  • a human-readable display name used in logs, plugin lists, help output, and other user-facing contexts

This makes it harder for plugin authors to define a clean display name without also making that display name part of the plugin’s identity. It also means that renaming or rebranding a plugin can affect references that should ideally remain stable.

Describe the solution you'd like.

Add an optional id field to paper-plugin.yml.

The id field would act as the plugin’s unique identifier, while name would remain the plugin’s display name.

Example:

id: MyPlugin
name: My Plugin
version: '1.0.0'
main: com.example.myplugin.ExamplePlugin
api-version: '26.1.2'

The id does not nec...

rustic folioBOT
#

The name has long been treaded as the canonical referential ID for plugins and slowly expected to conform to specific things, fairly sure that there is already a mechanism for being able to sit in place of another plugin unless that was only added to plugin.yml, I wouldn't entirely be against a display name thing but tilting from the "name as the identifier" to a different id as the canonical thing would be a pretty large amount of code shift for something that would semantically make 0 difference for 99.9% of plugins

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Can you provide some examples where the current plugin name cannot possibly be human readable?
The issue is more that name is doing two jobs at the same time. It is both the plugin's technical identifier and the thing shown to users.

For example,
A plugin might already be known internally as WorldGuardExtraFlags, but the author may want it displayed as WorldGuard Extra Flags. The stable identifier stays the same, while the user-facing name can use spacing and nicer formatting.
Or a plugin might want a namespaced ID like "com.example.myplugin" while showing "Example Plugin" to users.
Rebrands, ownership transfers, forks, trademark issues, or just better branding can also happen.

How often does this happen?
I don't think the frequency is the main thing here. Even if it is not common, the impact can be annoying when it does happen, and the proposed change can be changed to be backwards compatible.

tilting from the "name as the identifier" to a different id a...

#

Frequency of this being a problem is an important thing for introducing a change in something as fundamental as plugin identification.

Your examples:

  • Dev wants spaces in the name.
    • Hasn't seemed to hurt anyone in the dozen years since spaces were disallowed. Users have been able to identify their plugins just fine.
  • Dev wants a namespaced ID.
    • Seems like the dev just wants to be special, doesn't seem worth catering to.
  • Rebrand / better branding
    • Plugins are neat tools for your server, not brand identities.
  • Ownership transfer
    • This isn't going to cause a rename.
  • Fork
    • This should cause a full rename, to avoid breakage.
  • Trademark issues.
    • A user who names their plugin Fortnite can pick up the pieces themselves.
rustic folioBOT
rustic folioBOT
#

Summary

This pull request adds modern Adventure Component support for dynamically setting inventory titles via InventoryView#title(Component).

Description

The existing InventoryView#setTitle(String) method has been deprecated since 1.21.1 due to poorly defined and broken behaviors. Currently, there is no proper way to update an open inventory's title using the modern Adventure API.

This PR addresses the issue by introducing:

  1. InventoryView#title(Component) to Paper-API.
  2. A proper packet-based implementation in Paper-Server (CraftInventoryView) that updates the client UI on the fly using ClientboundOpenScreenPacket.
  3. Throwing an UnsupportedOperationException if a title update is requested for an inventory context that does not support it (e.g., if the player inventory is active or the view is detached).
#

There is no proper way to do this because this is relying on client side state hackery which is

1. not garaunteed behavior we can promise for the next decade

2. has pretty jarring side-effects for clients when devs use this

What if we just expose it as an experimental API via @ApiStatus.Experimental with a heavy warning in the Javadoc? That way, devs stop hacking with raw packets, but Paper isn't bound to guarantee its behavior for the next decade.

rustic folioBOT
rustic folioBOT
#

Expected behavior

The player should rejoin at the exact logout location.
The player's inventory should remain in the chest after logging out.
World changes, including placed chests, should be saved consistently without rollback.

Observed/Actual behavior

Player location rolls back.
Player inventory rolls back, causing item duplication.
Repeating the process eventually causes some chests to disappear.

Steps/models to reproduce

I'm experiencing a player data rollback issue on Paper 26.2. Experimental Alpha

When I leave the server and rejoin, my player sometimes does not spawn at the location where I logged out. Instead, I appear at an earlier location.

If I place all of my inventory into a chest before logging out and then rejoin, my inventory is restored as if I never placed the items in the chest. The chest still contains all of the items as well, resulting in duplicated items.

If this process is repeated multiple times, some of the chests that were placed...

rustic folioBOT
#

Is your feature request related to a problem?

There's no API to change drops when Item Frame is destroyed, while also having access to the ItemFrame entity to e.g., read its PDC.

Describe the solution you'd like.

  • EntityDropItemEvent called for Item Frame and the item inside of it.
  • HangingBreakEvent#getItems or HangingBreakEvent#getDrops

Describe alternatives you've considered.

Marking frame location on HangingBreakEvent then retrieving it on ItemSpawnEvent and handling the rest of the logic.

Other

Let me know if there's a cleaner solution. Basically trying to apply item_model component to a dropped item frame if the entity was invisible.

rustic folioBOT
rustic folioBOT
#

Summary

Fixes #13678.

TypedKeyImpl is a record implementing Key, but it never overrides equals/hashCode, so Java generates them from both record components and only matches another TypedKeyImpl. Adventure's KeyImpl.equals compares any Key by namespace + value, so equality is one-directional:

Key key = Key.key("minecraft:stone");
TypedKey<ItemType> typedKey = TypedKey.create(RegistryKey.ITEM, key);
key.equals(typedKey);   // true
typedKey.equals(key);   // false

That breaks the symmetry clause of Object.equals, and the two hash differently, so a TypedKey can go missing in a HashSet<Key> built from plain keys, and contains/remove turn order dependent when both types are mixed.

This overrides equals/hashCode on TypedKeyImpl:

  • Against another TypedKey, compare underlying key and registry key (same as before, so keys from different registries stay distinct).
  • Against a plain Key, compare namespace + value to match adventure...
rustic folioBOT
#

Problem

PlayerLinksSendEvent is gated behind an isEmpty() check on the server's
global ServerLinks. This means the event is never fired when no global links
are configured, making it impossible for plugins to add per-player links from
scratch without a workaround.

Plugins that want to show player-specific links (e.g. localized links based on
client language) are currently forced to pre-populate the global ServerLinks
with dummy entries just to make the event trigger — even though those global
entries are irrelevant and must then be cleared inside the event handler.

Solution

Remove the isEmpty() guard before the event, and move it to after the event
has been processed. The event now always fires, and the packet is only sent if
the resulting ServerLinks is non-empty (either from global config or from
plugin modifications).

rustic folioBOT
#

Are you testing this on Windows by any chance?
With a Windows file system Files#isWritable, which checkAttributes mostly is, will resolve the full path, check per-file security settings, ACLs, read-only volumes. Additionally Windows Defender or other AVs can also intercept this and do their stuff unless the directory is excluded.
This will be rather slow.

On a Unix file system, it just checks the file writable bit, which would be a single syscall and pretty fast.

Though I am not entirely convinced that isWritable on every single file is really needed here, checking just the directory should be enough.

rustic folioBOT
#
  • name also determines the location/name of the plugin data folder. Introducing an unique, stable id but then not using it for this important area where uniqueness actually matters would be rather silly. Changing this would be a massive change. Also how would namespaces look here and what benefit would they even provide?
  • name is used for the creation of NamespacedKeys. Changing this to use id while also allowing id itself to be namespaced would not be possible, as double-namespaces (plugin-namespace:plugin:key) are disallowed by the underlying vanilla system.

A few things you brought up can also already be done today:

  • The log prefix can be configured in your plugin.yml by setting prefix: to some value.
  • org.bukkit.help allows full customization of the help system, including names displayed there.

Overall this essentially leaves "the way your plugin shows up in /plugins and /version". Which is a command often disabled on servers and not something...

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Expected behavior

Changelog on download page (now just sais No changes, lame!!).

Observed/Actual behavior

Newest releases missing changelog on download page, fix it now!!

<img width="1518" height="529" alt="Image" src="https://github.com/user-attachments/assets/6858071f-fbd9-439a-a906-d3e2544ef066" />

Steps/models to reproduce

Go here: https://papermc.io/downloads/paper

Plugin and Datapack List

NOPE

Paper version

26.2.x

Other

No response

rustic folioBOT
rustic folioBOT
#
[PaperMC/Paper] New branch created: fix/changelog
#
[PaperMC/Paper] branch deleted: fix/changelog
rustic folioBOT
#

Summary

Adds an opt-in feature that moves the expensive A* search in mob pathfinding
(PathFinder#findPath) off the main server thread onto a worker pool. Gated
per-world behind entities.behavior.async-pathfinding (default off).

How it works

  • The request is prepared on the main thread (validation, world-border
    check, EntityPathfindEvent, PathNavigationRegion snapshot).
  • Only the expensive A* search runs on a worker pool, using a
    thread-confined PathFinder created per call — the shared, mutable
    NodeEvaluator on this.pathFinder is never touched off-thread.
  • The finished Path is applied back on the main thread via the server
    executor, so the world mutation model is unchanged.
  • Only the create-and-apply moveTo(coords/entity, speed) overloads opt in;
    createPath(...) stays fully synchronous, so goals that inspect the path
    directly keep exact vanilla behaviour.

Safety / no-regression

  • Exceptions in the worker fall...
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Expected behavior

When compiling against Paper 26.1.2 (or before) using the BookMeta#pages setter methods should also work on a 26.2 server since it is api.

Observed/Actual behavior

[17:35:25 INFO]: TheosRee issued server command: /bookmetatest getter
[17:35:29 INFO]: TheosRee issued server command: /bookmetatest setterArray
[17:35:29 ERROR]: Command exception: /bookmetatest setterArray
java.lang.NoSuchMethodError: 'net.kyori.adventure.inventory.Book org.bukkit.inventory.meta.BookMeta.pages(net.kyori.adventure.text.Component[])'
at TR-Test.jar//de.ree.theos.Test$1.execute(TRBQAddon.java:69) ~[?:?]
at io.papermc.paper.command.brigadier.bukkit.BukkitCommandNode$BukkitBrigCommand.run(BukkitCommandNode.java:83) ~[paper-26.2.jar:26.2-20-2c0341f]
at com.mojang.brigadier.context.ContextChain.runExecutable(ContextChain.java:73) ~[brigadier-1.3.10.jar:?]
at net.minecraft.commands.execution.tasks.ExecuteCommand.execute(ExecuteCommand.java:30)...

rustic folioBOT
#

Agree with Lulu. It is a bit nasty, a typed key should be able to extend Key, it is identifying something via a namespace and value but the fact that a the plain key implementation considers any key with equal namespace and value equal means we should probably bite the bullet and make this keyed instead. A pretty meh equal impl of KeyImpl imo, idk if this is worth bringing up with adventure folks.

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Stack trace

https://mclo.gs/wJI0Zfx

Plugin and Datapack List

Paper Plugins (2):

  • HuskHomes, HuskSync
    Bukkit Plugins (45):
  • Bolt, Chunky, Citizens, CMI, CMILib, CoreProtect, CoreProtectFilter,
    dDiscordBot, Denizen, Depenizen
    dynmap, dynmapHider, EffectLib, FastAsyncWorldEdit,
    *ForcedGrammar, GuestMode, HeadDatabase, ImageDisplay,
    LibsDisguises, LiteBans
    LuckPerms, MapModCompanion, MapSync, MCCinema, Multiverse-Core,
    MyCommand, NoteBlockAPI, packetevents, PlaceholderAPI, ProtocolLib
    PvPToggle, RC_BetterSync, RC_BetterTreasure, RC_EntityCounter,
    Shopkeepers, SystemChat, Vault, ViaBackwards, ViaVersion, VoidGen
    Votifier, WorldBorder, WorldEditDisplay, WorldGuard,
    WorldGuardExtraFlags

Actions to reproduce (if known)

Paper version

paper #48

Other

No response

rustic folioBOT
#

When the servers data converter, either mojangs DFU or papers data converter, drops a block entity, plugins can loose valuable data they previously stored in the block entity via the persistent data container api.

To implement this, pass the level identifier to the data converter context via the __context tag vanilla already maintains. Both DFU and DC have implementations for the event to ensure the event is available even if the DC feature patch is not in.

rustic folioBOT
rustic folioBOT
#

Well feel expected.. in 26.1 the whole BookMeta has a mention for

Warning: in an upcoming version of Paper, this interface will no longer extend Adventure's net.kyori.adventure.inventory.Book

and that pages() method comes from the adventure Book, in 26.2 with the upgrade of Adventure a new method was added but that method return BookMeta and not Book like in the Adventure Book class... so not really sure if this is a thing can be fixed in a nice way because in that case you dont use the return value but in other cases this can happen and cause the same error...

rustic folioBOT
#

In the base game for Java Edition, there is a security flaw with the "/chase" command. By default, it is available to all players, even if they don't have operator privileges. This allows any player with malicious intentions to abuse the tool. I reported this to Mojang, but they refused to address the issue (https://imgur.com/a/chase-exploit-jXYUTD0).

This patch changes the required permission level to 3. This ensures that the command is restricted to operators, which significantly reduces the risk of it being abused. However, the "minecraft.command.chase" permission node can still be used if a server owner wishes to customise who has access to "/chase".

rustic folioBOT
#

From what I've seen, when Mojang closes an issue as "Won't Fix", that's a sign that they're probably not going to fix it for a long time. By patching the security flaw using a patch, you are preventing people from creating a vulnerability in their server. Even if "/chase" is a debug tool, it should still have a proper security configuration.

rustic folioBOT
#

in 26.1 the whole BookMeta has a mention for

The mention existed for too short amount of time for this level of breakage, such api changes must also be handled by bytecode rewrite (like commodore)

and that pages() method comes from the adventure Book

The signature as shown in the error is on book meta so it shouldn't be hard to swap with an internal static book meta + List -> Book method

rustic folioBOT
#

Expected behavior

The EntityUnleashEvent should only be called if the sulfur cube was actually leashed, like for other mobs on their death.

Observed/Actual behavior

The EntityUnleashEvent is triggered every single time any TNT sulfur cube explodes, regardless of leash status.

Some plugins assume that if an EntityUnleashEvent is triggered before the leash breaks, the entity is leashed, but since this now no longer the case, IllegalStateException can get thrown when getting the leash holder.

It should be fairly simple to add an isLeashed() check before throwing the event.

Steps/models to reproduce

  • Create a plugin that listens to EntityUnleashEvent.
  • Spawn a sulfur cube
  • Give it TNT
  • Ignite it and wait
  • Event will be triggered even tho the entity is not leashed

Plugin and Datapack List

Testing plugin

Paper version

Paper version: 26.2-48-main@87c4d42

Other

No response

rustic folioBOT
#

I've also read in the release of Adventure 5.0 that there should be no breaking changes and assumed with that it should also be the case for the platform implementations, even when the Book interface just got removed.

And well, the deprecation and removing was in just like 2 weeks, this is not really a huge timeframe ^^

Last to the chaining of methods, they can easily be changed to just not chain on older versions, so that is not really a problem.

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

I managed to reproduce this with the following code:

public final class TestPlugin extends JavaPlugin implements Listener {
    private Entity victim;

    @Override
    public void onEnable() {
        this.getServer().getPluginManager().registerEvents(this, this);
        this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(
            Commands.literal("tracker-crash")
                .executes(ctx -> {
                    if (!(ctx.getSource().getSender() instanceof Player player))
                        return Command.SINGLE_SUCCESS;
                    var base = player.getLocation();
                    this.victim = player.getWorld().spawn(base.clone().add(0.0, 0.0, 2.0), ArmorStand.class);
                    player.getScheduler().run(this, _ ->
                        player.setVelocity(player.getVelocity().add(new Vector(0.0, 0.01, 0.0))), null);
                    player.sendPlainMessage("waiting for```...
rustic folioBOT
#
[PaperMC/Paper] New branch created: feat/pr-review-status
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Expected behavior

Inventorys created via following Code work with the PrepareAnvilEvent
Inventory inventory = Bukkit.createInventory(this, InventoryType.ANVIL, title);

Observed/Actual behavior

Inventorys created via Bukkit.createInventory with a InventoryType of ANVIL do not call the PrepareAnvilEvent

Steps/models to reproduce

Create a InventoryHolder with a getInventory return of InventoryType.ANVIL
Inventory inventory = Bukkit.createInventory(this, InventoryType.ANVIL, title);

Create a Listener for the PrepareAnvilEvent

Observe

Plugin and Datapack List

The Plugin to test this Bug

Paper version

This server is running Paper version 26.2-53-main@3a3d1c0 (2026-07-06T18:15:12Z) (Implementing API version 26.2.build.53-alpha)
You are running the latest version
Previous version: 26.2-47-ad5d26a (MC: 26.2)

Other

No response

rustic folioBOT
#

Is your feature request related to a problem?

The PlayerItemFrameChangeEvent is scoped to player-related triggers only, and there is no general ItemFrameChangeEvent encompassing the other triggers for why an item frame's state might change.

Describe the solution you'd like.

I am curious if Paper would see value in a PR adding some kind of ItemFrameEjectItemEvent, which, unlike PlayerItemFrameChangeEvent, would listen for any item frame ejection, regardless of the entity that caused it.

Or, alternatively, some kind of general ItemFrameChangeEvent which would deprecate PlayerItemFrameChangeEvent, but this may be difficult as I don't see a clean way to handle the consequence of ItemFrameChangeAction's PLACE and ROTATE enumerators being unused in the case of all other entities (in other words, it is not possible afaik for any other entity to have any value for...

rustic folioBOT
rustic folioBOT
#

you're right that it's connector-j's call but protobuf has a runtime dependency only for the X Protocol path.
standard JDBC never touches mysqlx, which is all plugins use. So it's a real runtime dep for connector-j as a whole, just not one that plugins actually rely on.

the reason I hit this at all is OpenTelemetry, which is a CNCF/Linux Foundation project and pretty much the standard for observability these days. It'd be a shame if the classpath collision effectively made OTLP unusable for plugins, so I'd like to see it resolved one way or another. Would you be able to raise this with the team once more down the line?

rustic folioBOT
#

Thanks for taking the time to look at this. I understand the reasoning that
stop is meant to flush the full server state, that's a fair design stance.

That said, I'd have appreciated a chance to iterate before this was closed
outright. The objection isn't really with the goal - making an ephemeral main
world genuinely non-persistent across restarts, which is a common need for
minigame/lobby networks - but with how it was wired in, by overloading
ticks-per.autosave. That's a legitimate critique, and it's also easy to
address: decouple it into an explicit, dedicated option (e.g. a save-on-stop
world default) that keeps the current behaviour as the default. stop would
still save everything for everyone out of the box, and only operators who
deliberately opt out would see a change. That directly answers the "this has
nothing to do with the autosave setting" point rather than fighting it.

I'd genuinely rather land something clean upstream than carry yet a...

#

disabling saving entirely comes with a whole load of caveats and expectations around "don't mutate stuff on the disk ever" that we're just not really comfortable trying to promise. changing the promise of some other config option was an inherient no go, but I'm not really sure if this could ever take a shape we'd be happy with, especially with the desired configuration knobs people have asked for here

rustic folioBOT
#

An event for items ejected from item frames would close a gap in the current Bukkit event system. The item frame uses setItem() to receive items, and there is already PlayerTakeItemFrameItemEvent for players taking items out. But the frame ejecting an item due to redstone signal or explosion damage is currently only detectable via a EntityChangeBlockEvent listener that checks for item frames - which is unreliable because the event covers too broad a scope.

The new event should extend EntityEvent and expose the item frame and the dropped ItemStack. It should fire in ItemFrameEntity.updateArmorstandMetadata() or the equivalent tick method where the frame releases its held item. Paper already adds custom events for entity interactions that Minecraft doesn't natively expose as events (like PlayerItemFrameChangeItemEvent), so the pattern is established.

The event should also include the cause of the ejection: Cause enum with values like REDSTONE_LOST, EXPLOSI...

#

The unsafe terrain read during worldgen in 26.2 relates to chunk loading during world generation when another thread is concurrently accessing the same region. The error surfaces from the ChunkMap or ThreadedWorldGeneration code paths where a ConcurrentModificationException or null access occurs because the generator attempts to read a chunk section that has been unloaded or is mid-construction.

In 26.2, the worldgen parallelism changed with the new region-based chunk system. The Detected unsafe terrain read message is thrown by the debug assertion check in ChunkAccess.getBlockState() or similar accessor that validates thread safety. The assertion fires when the access pattern crosses thread boundaries without proper synchronization.

The fix options: either lower the assertion to a warning in production builds (since it doesn't guarantee corruption, just potential data race), or add the proper read lock acquisition in the worldgen paths that access foreign chunks....

rustic folioBOT
#

Expected behavior

BlockBreakEvent should be cancelled if block wasn't actually broken.

Observed/Actual behavior

BlockBreakEvent fires when player in adventure mode switches item in a last tick while breaking a block,

https://github.com/user-attachments/assets/8a6e9b28-c1aa-4dac-96e4-b162e6351314
look in the chat

Steps/models to reproduce

  1. Set gamemode in Adventure
  2. /give @p minecraft:wooden_shovel[can_break={blocks:["minecraft:sand"]}] 1
  3. Start breaking sand and press F on a last kick

Plugin and Datapack List

none

Paper version

This server is running Paper version 26.1.2-74-ver/26.1.2@e4e17fc (2026-07-06T16:51:09Z) (Implementing API version 26.1.2.build.74-stable)

Other

There is a chance that the fix will be backported to 1.21.11 👉👈

#

Updated your patch to
a) include the comment and
b) to require owner level permission. A command that enables owner level execution of commands should not be available on the admin level.

Approved under the idea that, if somehow there actually is a server owner out there that went out of their way to enable the chase server debug flag and then, in addition to that, somehow thought it was a great idea to make the server public, this patch will prevent them from shooting themselves in the foot even if they probably deserved it at that point.

rustic folioBOT
#
[PaperMC/Paper] New branch created: enhancement/deprecate-spawn-friendlies
rustic folioBOT
#

The issue is kind of weird from my tests:

https://github.com/user-attachments/assets/fc00290f-72de-4e52-9f48-541887eff2ac

as you can see, it takes a few seconds for the BBE to be incorrectly triggered, and switching back to the correct item instantly triggers the BBE properly. I think this has to do with lag compensation, but I am not too sure. Anyhow, I made a PR attempting to fix it so we'll see what the team thinks about it: https://github.com/PaperMC/Paper/pull/14044

rustic folioBOT
#

Is your feature request related to a problem?

Yes. The current MCA (Anvil) format uses zlib compression, which is outdated and inefficient for modern large-scale servers. Many server admins are forced to choose between staying on old, unsupported software or losing compatibility with newer, more efficient formats. LeafMC already supports these formats natively, putting Paper at a competitive disadvantage.

Describe the solution you'd like.

Add an experimental (disabled by default) world loading/saving engine that supports LINEAR_V2 and B_LINEAR region formats using ZSTD compression.

  • Implement as a config flag (e.g., use-region-format: BLINEAR_V3) in paper-global.yml
  • Allow conversion via external tools like LuminolMC/region_converter_
  • ZSTD offers ~5x faster compression and ~4x faster decompression than zlib (Zstd Benchmarks)

Describe alternatives you'v...

rustic folioBOT
#
[PaperMC/Paper] branch deleted: enhancement/deprecate-spawn-friendlies
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Expected behavior

No error should occur.

Observed/Actual behavior

During startup, an error occurs in the console:

Starting org.bukkit.craftbukkit.Main
Juli 09, 2026 2:01:27 PM org.jline.terminal.impl.ffm.CLibrary <clinit>
WARNUNG: Unable to find openpty native method in static libraries and unable to load the util library.
        - java.lang.UnsatisfiedLinkError: no util in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib

The error is only visible in the console and not within the logs.

Steps/models to reproduce

Start a server on Linux with the latest jdk. On Windows the error doesn't occur.

Plugin and Datapack List


Paper version

Affected versions:
26.1.2-74
26.2-56

Most recent version:
This server is running Paper version 26.2-56-main@8cd4f47 (2026-07-09T08:35:16Z) (Implementing API version 26.2.build.56-alpha)

Other

On 1.21.11 with Java 21, the error didn't occur.
What causes the error? Has it an...

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Expected behavior

I expected it to launch normally and me being able to easily connect without any issues

Observed/Actual behavior

i launch the run.bat and it launches normally but as soon as it finishes launching, then it just wont respond and nobody can join at all.

Steps/models to reproduce

I have no idea, i will send a compressed zip file of my server files here:
https://drive.google.com/file/d/1bpM8Oh18tCNwb7ENt_h7yg4FjKpY_Mzs/view?usp=sharing

Plugin and Datapack List

Skript, Skbee, FAWE and Worldguard

Paper version

i am running paper 1.21.11

Other

<img width="595" height="380" alt="Image" src="https://github.com/user-attachments/assets/4aebbfd4-64d7-414c-ab2e-709c856a632c" />

rustic folioBOT
rustic folioBOT
#

Expected behavior

Expected behavior
Piston pushes moss block (which should break and drop) with a sign placed on top in certain orientations, same as vanilla. The sign loses support and drops, moss block breaks and drops.

Observed/Actual behavior
Piston does not extend at all when the sign is placed on the moss block in specific orientations.
Changing the sign orientation makes it work, but vanilla does not have this restriction.

Steps to reproduce

  1. Place a normal piston facing +X
  2. Place moss block in front of it
  3. Place a sign on top of / attached to the moss block (specific orientation: ...)
  4. Power the piston
  5. On Vanilla 1.21.1: moss block drops, sign drops, piston extends normally
  6. On Paper 1.21.1 build 130: piston does not move at all

Paper version
This server is running Paper version git-Paper-130 (MC: 1.21.1)

Plugin list
None / clean test

Additional info

  • allow-headless-pistons, allow-piston-duplication, allow-permanen...
rustic folioBOT
rustic folioBOT
#

Expected behavior

Given the following setup:

  1. A wandering trader spawns with two llamas, only one is required for this example
  2. One llama is 4 blocks closer to the player compared to the trader

If the player moves far enough for the trader (that is slightly farther away than the llama) to not being tracked, but still keeps the llama within tracking distance, when the player comes closer to make the trader appear again, the leash will connect back to the wandering trader.

Observed/Actual behavior

If the player moves far enough for the trader to not being tracked, but still keeps the llama within distance, when the player comes closer to make the trader appear again, the leash will be stuck on the air in the same position the trader was before going out of tracking distance.

Steps/models to reproduce

  1. Load the following world with Paper 26.2 build 56 (jar not included):
    server.zip

  2. Fly to the...

rustic folioBOT
rustic folioBOT
#

One important thing that will either need to be documented or addressed is that the event won't be fired if the server doesn't have code of conducts enabled, or has no txt files configured in the codeofconduct folder.

Would it be worth looking into firing it cancelled, making it possible to uncancel in those situations? Like, would that behavior match how other events work or would it be considered a problem for server admins wanting to disable it?

rustic folioBOT
#

@kacpermajkowski the first two checks are exactly what Mob#checkDespawn
does, but MobCategory#isPersistent isn't part of the despawn path — it's
only used by NaturalSpawner to decide whether to spawn more of that
category. The actual third gate is the per-type
Mob#removeWhenFarAway(double) override, and since that one is dynamic,
the category check breaks on the edge cases: an untamed cat older than
~2 min and a chicken jockey's chicken are despawnable despite CREATURE
being a "persistent" category, and an axolotl that was ever bucketed never
despawns despite AXOLOTLS not being one. It happens to line up for
zombies/cows/wild axolotls, which is why your testing passed. There's no
clean way to replicate it statically since the real check takes a distance
and reads mob state — which is kind of the whole problem with this API.

#

I feel that pre-cancelled events are generally more of a legacy compat behavioral hack of "we're firing this when it really shouldn't, this is cancelled because no side-effects will occur from this, we just want to let you know" - I guess you could argue that applies here, but I think the reality is that the intent works just fine here, the intent is to send it unless something cancels it, it will just do nothing if there is no data to send, etc

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Is this something we should plug into UnsafeValues if we decided to pull something like this. E.g. via a UnsafeValues#reserveEntityId(PlayerConfigurationConnection, long)? I do not care to expose entity ids into the public API and this API can literally break everything with a wrong call.

I think putting this API in UnsafeValues would be a good call, this API does seem good for people with specialized use-cases but I agree making this a public api someone can accidentally mess with seems like a bad call.

rustic folioBOT
#

Is this something we should plug into UnsafeValues if we decided to pull something like this. E.g. via a UnsafeValues#reserveEntityId(PlayerConfigurationConnection, long)? I do not care to expose entity ids into the public API and this API can literally break everything with a wrong call.

I've went ahead and moved this to UnsafeValues#reserveEntityId(PlayerConfigurationConnection, int), I do agree that its a better spot to have something like this

rustic folioBOT
#

IMO this should not be part of the API, even in UnsafeValues. Way too easy to break the server in fun ways. And UnsafeValues in general is a bit of a questionable concept to have in general, we really should not add even more to that mess.

I am fine with just the NMS parts of it though. That would put it in a similar position as the ChannelInitializeListener "API", which is also only intended for packet-modifying stuff.

rustic folioBOT
rustic folioBOT
#

IMO this should not be part of the API, even in UnsafeValues. Way too easy to break the server in fun ways. And UnsafeValues in general is a bit of a questionable concept to have in general, we really should not add even more to that mess.

I am fine with just the NMS parts of it though. That would put it in a similar position as the ChannelInitializeListener "API", which is also only intended for packet-modifying stuff.

I mean the alternative to allowing this is listening on the LoginEvent and using NMS/paperweight to modify the entity id of the player yourself then.

But the LoginEvent is deprecated & causes the player to be created prematurely, this simply allows you to do the same thing in a safe manner where the player is not created prematurely and the flow is generally the same.

Like it's "easy to break the server" but I just...

rustic folioBOT
#

Is your feature request related to a problem?

When using a PersistentDataContainer to hold Booleans, you can basically treat the key existing as the boolean value. So, I figured why not add a way to make a valueless tag so I can just store a NamespacedKey on a PDC and check if it exists.

Describe the solution you'd like.

A new function could be added to PersistentDataContainer
void tag(NamespacedKey key)
All it'd do is run set(key, PersistentDataType.BOOLEAN, false) or something.

Then, you can use PersistentDataContainerView#has and PersistentDataContainer#remove like you would now.

Alt

Three functions would be added to the API (I'm a little unsure of the internal PDC workings, sorry)

Inside PersistentDataContainerView:

  • boolean hasTag(NamespacedKey key)

Inside PersistentDataContainer:

  • void tag(NamespacedKey key)
  • void untag(NamespacedKey key)

Alternatively, it could be addTag and removeTag.
These could be stored in a list attached...

rustic folioBOT
#

Like it's "easy to break the server" but I just don't know how much I love that line of thinking as you quickly end up restricting developer freedom from doing some cool stuff, I mean if someone breaks the server by using a colliding entity id that's their fault and it's clearly documented

What malfrador suggested here is to maintain this as internal "API". E.g. your plugin would require paperweight userdev to effectively do what the PR rn does in UnsafeValues. It is effectively another "beware here be dragons" guard for the method. We'd keep the additional field and methods on the configuration connection impl and have it be applied but it just isn't exposed at all to the normal API but instead requires you to opt into internals via paperweight.

I can kinda see malfs point too, UnsafeValues, while doing unsafe things, generally still is "safe" but possibly breaking and might return unexpected things. I don't have strong feelings either way, but if usage of paperweigh...

rustic folioBOT
rustic folioBOT
#
[PaperMC/Paper] New branch created: feature/do-not-delay-on-minor-file-fix
#

Paper halts the server for 30 seconds when performing the large world
import from 1.21.11 to newer versions.

This should not be performed when applying file fixes for 26.1 to 26.2,
which is a single non applicable file fix.

It'll still be performed when importing a spigot or a vanilla world into
the server, however after the applicable file fixes were run (including
the 1.21.11 to 26.1 file fixes).
This should be fixed once we correctly migrate the place where the paper
migration is executed.

#
[PaperMC/Paper] branch deleted: feature/do-not-delay-on-minor-file-fix
#

I think getMatchingBlocks should run height then width to match the patterns used to detect, even though the javadocs don't make any promises.

It looks like it is always width then height though?
<img width="1033" height="332" alt="image" src="https://github.com/user-attachments/assets/c1ceefe9-09e9-4f3e-bc8c-9e1db7212ea9" />
<img width="994" height="422" alt="image" src="https://github.com/user-attachments/assets/3df7ab78-9500-4e0c-bdee-ed55a674e3ba" />

rustic folioBOT
#
[00:12:57] [Server thread/INFO]: FifthColumnMC (/213.152.161.54:39237) lost connection: Disconnected
[00:32:07] [Server thread/INFO]: FifthColumnMC (/213.152.161.54:41475) lost connection: Disconnected
[00:39:23] [Server console handler/ERROR]: Caught previously unhandled exception :
java.io.IOError: java.io.IOException: Eingabe-/Ausgabefehler
	at org.jline.keymap.BindingReader.readCharacter(BindingReader.java:170) ~[jline-reader-3.20.0.jar:?]
	at org.jline.reader.impl.LineReaderImpl.readCharacter(LineReaderImpl.java:901) ~[jline-reader-3.20.0.jar:?]
	at org.jline.reader.impl.LineReaderImpl.doList(LineReaderImpl.java:4906) ~[jline-reader-3.20.0.jar:?]
	at org.jline.reader.impl.LineReaderImpl.doList(LineReaderImpl.java:4883) ~[jline-reader-3.20.0.jar:?]
	at org.jline.reader.impl.LineReaderImpl.doComplete(LineReaderImpl.java:4509) ~[jline-reader-3.20.0.jar:?]
	at org.jline.reader.impl.LineReaderImpl.doComplete(LineReaderImpl.java:4347) ~[jline-reader-3.20.0.jar:?]
	at org.jlin```...
#
[PaperMC/Paper] New branch created: cat/chore/bump-jline
#

The bug I was holding back on for this has been resolved, updates jline
to 4.3.1, noting that now we're targetting Java 25 as the base, we no
longer need the JNI terminal; This has been kept for now as jline can use
it for a fallback, but will likely be removed in the future.

rustic folioBOT
#
Starting org.bukkit.craftbukkit.Main
Juli 12, 2026 6:55:38 PM org.jline.terminal.impl.ffm.CLibrary <clinit>
WARNUNG: Unable to find openpty native method in static libraries and unable to load the util library.
        - java.lang.UnsatisfiedLinkError: no util in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib
[18:55:38 INFO]: [bootstrap] Running Java 25 (OpenJDK 64-Bit Server VM 25.0.3+9-LTS; Eclipse Adoptium Temurin-25.0.3+9) on Linux 5.4.0-231-generic (amd64)
[18:55:38 INFO]: [bootstrap] Loading Paper 26.2-DEV-HEAD@c420ed4 (1970-01-01T00:00:00Z) for Minecraft 26.2

The error remains on https://github.com/PaperMC/Paper/pull/14056.

#
[19:08:14 INFO]: [ChunkHolderManager] Saved 0 block chunks, 0 entity chunks, 0 poi chunks in world 'minecraft:the_end' in 0,00s
[19:08:14 INFO]: [ChunkHolderManager] Waiting 60s for chunk I/O to halt for world 'minecraft:the_end'
[19:08:14 INFO]: [ChunkHolderManager] Halted I/O scheduler for world 'minecraft:the_end'
2026-07-12T17:08:14.586221900Z Log4j2-AsyncAppenderEventDispatcher-1-Async ERROR An exception occurred processing Appender TerminalConsole
java.lang.IllegalStateException: Terminal has been closed
        at org.jline.terminal.impl.AbstractTerminal.checkClosed(AbstractTerminal.java:796)
        at org.jline.terminal.impl.AbstractWindowsTerminal.writer(AbstractWindowsTerminal.java:242)
        at org.jline.terminal.impl.AbstractTerminal.flush(AbstractTerminal.java:276)
        at org.jline.utils.Display.update(Display.java:786)
        at org.jline.utils.Display.update(Display.java:417)
        at org.jline.reader.impl.LineReaderImpl.printAbove(LineReaderImpl.jav```...
rustic folioBOT
#

Like it's "easy to break the server" but I just don't know how much I love that line of thinking as you quickly end up restricting developer freedom from doing some cool stuff, I mean if someone breaks the server by using a colliding entity id that's their fault and it's clearly documented

What malfrador suggested here is to maintain this as internal "API". E.g. your plugin would require paperweight userdev to effectively do what the PR rn does in UnsafeValues. It is effectively another "beware here be dragons" guard for the method. We'd keep the additional field and methods on the configuration connection impl and have it be applied but it just isn't exposed at all to the normal API but instead requires you to opt into internals via paperweight.

I can kinda see malfs point too, UnsafeValues, while doing unsafe things, generally still is "safe" but possibly breaking and might return unexpected things. I don't have strong feelings either way, but if usage of...

#

How do you plan on managing entity ids on the proxy and avoiding conflict on the backend, both for existing and then-added entities? Knowing more details of the actual use makes designing this easier in a way that isn't either too convoluted or too dangerous to expose publicly

I increment starting from 1.6 billion instead of 1, so realistically should never collide as the paper backend would have to create 1.6 billion entities before the ranges could collide. Is there a safer way to do this? Probably, but for my use case it should be good enough

#

Filtering disallowed chat characters before adding the command to the suggestion click event, prevents component serialization from failing on malformed console input and crashing the server instantly.

To Reproduce

  1. Launch the server
  2. Type any unicode control chars or § in the console
  3. Press enter and server crashed

Crash Logs

Description: Exception in server tick loop

java.lang.RuntimeException: Failed to encode Minecraft Component: empty[style={color=gray,clickEvent=SuggestCommand[command=/§]}, siblings=[literal{§}[style={color=red,underlined}], translation{key='command.context.here', args=[]}[style={color=red,italic}]]]; Disallowed chat character: '§'
	at io.papermc.paper.adventure.WrapperAwareSerializer.lambda$deserialize$0(WrapperAwareSerializer.java:28)
	at com.mojang.serialization.DataResult$Error.getOrThrow(DataResult.java:287)
	at io.papermc.paper.adventure.WrapperAwareSerializer.deserialize(WrapperAwareSerializer.jav```...
#
[PaperMC/Paper] branch deleted: feat/pr-review-status
rustic folioBOT
#
Ubuntu 22:
Starting org.bukkit.craftbukkit.Main
[18:36:10 INFO]: [bootstrap] Running Java 25 (OpenJDK 64-Bit Server VM 25.0.1+8-LTS; Eclipse Adoptium Temurin-25.0.1+8) on Linux 5.15.0-177-generic (amd64)
[18:36:10 INFO]: [bootstrap] Loading Paper 26.2-53-main@3a3d1c0 (2026-07-06T18:15:12Z) for Minecraft 26.2
Ubuntu 18:
Starting org.bukkit.craftbukkit.Main
Juli 12, 2026 6:43:21 PM org.jline.terminal.impl.ffm.CLibrary <clinit>
WARNUNG: Unable to find openpty native method in static libraries and unable to load the util library.
        - java.lang.UnsatisfiedLinkError: no util in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib
[18:43:21 INFO]: [bootstrap] Running Java 25 (OpenJDK 64-Bit Server VM 25.0.1+8-LTS; Eclipse Adoptium Temurin-25.0.1+8) on Linux 5.4.0-150-generic (amd64)
[18:43:21 INFO]: [bootstrap] Loading Paper 26.2-53-main@3a3d1c0 (2026-07-06T18:15:12Z) for Minecraft 26.2

What's interesting, with an even older kernel and Java v...

rustic folioBOT
#

Expected behavior

Hello,

I am using Paper 26.1.2 (Build 74), and loading or creating a world takes significantly longer than it did with Paper version 1.21.11.

The issue is that the worlds I am importing use a void generator, meaning very few chunks are actually stored in the region folder.

Observed/Actual behavior

[00:51:57 INFO]: Selecting spawn point for level 'minecraft:hub-1'... [00:52:04 INFO]: Loading 0 persistent chunks for level 'minecraft:hub-1'... [00:52:04 INFO]: Preparing spawn area: 100%

Steps/models to reproduce

load and import or creation world (with or without plugin world [Multiverse-core, MultiWorld,...])

Plugin and Datapack List

[01:03:18 INFO]: ℹ Server Plugins (9):
[01:03:18 INFO]: Paper Plugins (1):
[01:03:18 INFO]: - SkBee
[01:03:18 INFO]: Bukkit Plugins (8):
[01:03:18 INFO]: - ConsoleSpamFixReborn, FileCleaner, Multiverse-Core, Skript, skript-db, skript-reflect, TAB, Vault

Paper version

[01:02:15 INFO]: Checking version,...

#

[00:51:57 INFO]: Selecting spawn point for level 'minecraft:hub-1'...

You need a better void generator plugin that overrides spawn point. The server has to generate and load lots of chunks in order to find one, which is a complex pipeline that would explain the 5 second load time

How do I fix it? Is there an in-game solution or a Paper configuration setting?

rustic folioBOT
rustic folioBOT
#

Stack trace

I've been working on containerizing paper, and it's going fine enough, but I found some unfortunate behavior in world storage migration between versions. This may be an upstream bug, and if it is, then consider this report a feature request to reimplement/extend the current logic.

As is often the case with containers, I am working with host file systems being mounted into the container's file system (volumes). Since container images are immutable, if you allow the Minecraft world to be created inside the container's file system, you would lose the world as soon as it shuts down.

During one of my tests I spun up a 26.2 paper image (build 47 or so? latest stable), and reused a world that I created in a 1.20.4 paper image. This triggered the automatic storage migration process.

Unfortunately, it appears paper (vanilla Minecraft?) tries to create a new directory and rename the old one or some such operation that assumes <server_cwd>/world and <server_cwd> are on...

rustic folioBOT
#

Fixes #11245

When you open another player's inventory (invsee-style, via player.openInventory(target.getInventory())) and then click an item in your own inventory at the bottom, InventoryClickEvent reports a completely unrelated slot and item. It has been broken since around 1.14.

The top inventory in that case is drawn as a generic 9x4 chest, so it only shows 36 slots. A player inventory, though, reports a size of 41 because it also counts the four armour slots and the off-hand. The slot conversion in CraftAbstractInventoryView keyed off that reported size, so every raw slot in the bottom inventory ended up five out. The first few slots of your own inventory were even treated as part of the top.

This adds a small getTopSlots() hook (it defaults to the current behaviour, so nothing else changes) and, for a player inventory opened in a container, returns the slot count that is actually laid out. With that, convertSlot, getSlotType, and countSlots line up with the...

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Going to close this. Generally would be very low priority with how its Windows-specific and most people have small worlds.
Outright disabling the checks is not a great option, given people run some really weird filesystem setups and the potential risks involved here.
In theory someone could PR a system property to reduce the checks, that would be an acceptable solution.

If you have a very large world, you might want to consider doing a manual migration anyways though. The migration does not delete the old files, so to do an automatic migration with a 4TB world you would need 8TB of disk space.
The Minecraft Wiki changelog for 26.1 lists the file/folder changes in detail, so while its completely unsupported it is possible to carefully migrate your world manually by moving files and using an NBTEditor. For that world size, it might be worth the effort.

rustic folioBOT
#

I generally like the QoL this event provides. For anyone following along, with PlayerInteractAtEntityEvent, replacing the cube's contained item on interact can be done like so:

@EventHandler
void onInteractWithSulfurCube(PlayerInteractAtEntityEvent event) {
    if (!(event.getRightClicked() instanceof SulfurCube cube)) {
        return;
    }

    ItemStack is = event.getPlayer().getInventory().getItemInMainHand();
    if (is.getType().asItemType() == ItemType.SHEARS) {
        return;
    }

    if (!cube.getEquipment().getItem(EquipmentSlot.BODY).isEmpty()) {
        return;
    }

    event.setCancelled(true);
    cube.getEquipment().setItem(EquipmentSlot.BODY, ItemType.BIRCH_LOG.createItemStack());
    event.getPlayer().swingMainHand();
}

With this new event, that is simplified to just this:

@EventHandler
void onSulfurCubeSwallowItem(SulfurCubeSwallowItemEvent event) {
    event.setNewItem(ItemType.BIRCH_LOG.createItemStack());
}

Generally, a lot o...

#

I would replace the <br> with <p> and also fix some punctuation stuff while we are at it.

/**
 * Called when a SulfurCube swallows an item.
 * <p>
 * If the ItemStack is modified, the SulfurCube will swallow the new item
 * and not remove the original one from the player's inventory.
 * <p>
 * If the event is cancelled, the SulfurCube will not swallow the item, and
 * it will not be removed from the player's inventory.
 */
rustic folioBOT
#

We have a related but slightly different storage layout that makes the current migration approach a serious blocker for us.

Our server stores the dimensions on separate filesystems and exposes them to Paper through symlinks, for example:

world -> /data/LUN1/world
world_nether -> /data/LUN2/world_nether
world_the_end -> /data/LUN3/world_the_end


The Overworld is currently larger than 4 TB and continues to grow.

If the 26.x migration may temporarily require close to the full size of the existing world again, this effectively prevents us from upgrading. Having another 4+ TB available on the same filesystem only for a one-time migration is not realistic for us, even though the existing world itself fits and runs without any storage problem.

The separate-disk layout also makes the migration more complicated. The final 26.x structure places all dimensions below the main world directory, while in our case the actual dimension data must remain on separate filesystems. Symli...
#

We have a related but slightly different storage layout that makes the current migration approach a serious blocker for us.

Our server stores the dimensions on separate filesystems and exposes them to Paper through symlinks, for example:

world -> /data/LUN1/world
world_nether -> /data/LUN2/world_nether
world_the_end -> /data/LUN3/world_the_end

The Overworld is currently larger than 4 TB and continues to grow.

If the 26.x migration may temporarily require close to the full size of the existing world again, this effectively prevents us from upgrading. Having another 4+ TB available on the same filesystem only for a one-time migration is not realistic for us, even though the existing world itself fits and runs without any storage problem.

The separate-disk layout also makes the migration more complicated. The final 26.x structure places all dimensions below the main world directory, while in our case the actual dimension data must remain on separate filesystems. S...

#

Is approximately 2× the world size really the expected worst-case storage requirement, even on filesystems with hard-link support?

There really shouldn't be any large increases in disk usage, only files which are modified end up as temp files on the disk, everything else basically sits as a series of operations to occur, but mojangs logic expects that stuff occurs as atomic operations, otherwise they would actually need to deal with file copying, etc

Can the migration reuse unchanged region files through hard links, or are most large files rewritten and duplicated?

files are not rewritten, they should just be moved

Is there any supported way to pre-create the new directory layout and move the dimensions manually within their existing filesystems before starting 26.x?

This is handled with mojangs filefix mostly, which expects to just be able to move stuff around; But, there are also file operations in here such as splitting the level.dat up, etc; as well as papers...

rustic folioBOT
#

Yea I mean, fwiw, the heavy moves across FS (region, entities and poi folder) if you can move them to e.g. migrate_region on the same FS, start the server, let it migrate the world and then move them into the world/dimensions/minecraft/overworld folder.

Notably I don't think this would work too well with nether and end dimension as moving those into the folder is a paper migration and I don't know if we leave "unexpected" folders intact in those worlds.

And well, there is a rather valid reason to have this use a COW fs. Inplace migrating this and the server dying halfway through would be rather deadly.

rustic folioBOT
#

This PR exposes the NMS-internal SulfurCube#equipItem method as an API-method.

Currently, if you want to set the item swallowed by a SulfurCube, you have to call the following code:

cube.getEquipment().setItem(
  EquipmentSlot.BODY,
  ItemType.BIRCH_LOG.createItemStack()
);

This is fine if you know about it. However that skips a little bit of logic that's inside the NMS SulfurfCube#equipItem method. Additionally, it's not intuitive for anyone simply scrolling through the SulfurCube API methods.

(Discussion: #paper-contrib message)

rustic folioBOT
rustic folioBOT
#

While I can't speak to the large world dilema, I more or less understand electronicboy's response, so it seems that there's probably nothing to worry about in that case (unless a lot of data has to be changed).

For the actual cross-device data issue though, the only 'patch' I can think of off the top of my head that paper could do (recognizing that yeah, this probably is an upstream issue), would be for stuff to be done inside the world folder itself.

i.e.

  • mkdir "world/world original"
  • mv world/* "world/world original/" # pretend * doesn't capture the new directory
  • mkdir "world/world upgraded"
  • cd world
  • run vanilla world upgrade logic (pointing it to "world original" instead of "world", or just mkdir world/world at the start)
  • cleanup...

granted, if the user has individual directories/files inside world on a different device, this would still not work, but at that point I do think it's somewhat unreasonable to expect that level of indirection

rustic folioBOT
#

Let's not turn this into an ad or drama tracker please

If you want the fastest compression, you can use the Vanilla option that already exists to change it to lz4, which is considerably faster than zstd still.

If we implemented zstd, it'd likely be taken from https://github.com/PaperMC/Paper/pull/10231 not those versions you mentioned (one of which, by their own admission, is flawed). Compression ratio would likely be slightly worse, but require less memory and be faster. so the specific ask here is a no

rustic folioBOT
#

Expected behavior

Using BlockData#merge with a BlockData created from string should not throw errors

Observed/Actual behavior

I have a little Skript add-on, and I have a syntax which allows people to get/set block data "tags".
I recently had a report that setting the "rotation" tag on a banner would not work, but it would work on a sign (as expected).

Upon some digging, I noticed this error:

[07:35:37 INFO]: [SkBee ERROR] Could not parse block data: 'minecraft:light_gray_banner[rotation=2]' Message: Block data not created via string parsing
[07:35:37 INFO]: [SkBee ERROR] Stack Trace: com.google.common.base.Preconditions.checkArgument(Preconditions.java:141)
[07:35:37 INFO]: [SkBee ERROR] Stack Trace: org.bukkit.craftbukkit.block.data.CraftBlockData.merge(CraftBlockData.java:82)

Its saying the BlockData was not created from String, even though it most definitely was.

Upon further digging, I see this in CraftBlockData#merge
Preconditions.checkArgument(cra...

rustic folioBOT
#

In a fast check i notice a thing...

BlockData lightGrayBanner = Bukkit.createBlockData("minecraft:light_gray_banner"); // call convert from string and save to cache (computeIfAbsent)
BlockData lightGrayBannerChange = Bukkit.createBlockData("minecraft:light_gray_banner[rotation=1]"); // call convert from string but get from cache and not use the parseData of the computeIfAbsent
lightGrayBanner.merge(lightGrayBannerChange); // fails because the checkState for extra data coming from parseData not exists

not sure why the cached of minecraft:light_gray_banner[rotation=1] seems to have issues...

rustic folioBOT
#

Expected behavior

PlayerTeleportEvent#setCancelled(true) should cancel teleportation at all times

Observed/Actual behavior

Mounted to an entity (spectator target) in spectator gamemode, teleporting using the spectator menu (using mouse wheel or keyboard numbers) does NOT cancel the teleportation event.

Steps/models to reproduce

  1. Write some code to cancel PlayerTeleportEvent. I used this:
public class Main extends JavaPlugin implements Listener {
    @Override
    public void onEnable() {
        getServer().getPluginManager().registerEvents(this, this);
    }

    // i know Entity shouldn't be cached in a field, but this is just for testing
    private final AtomicReference<Entity> target = new AtomicReference<>();

    @EventHandler
    void onEntityTargetEvent(PlayerStartSpectatingEntityEvent event) {
        Entity entity = event.getNewSpectatorTarget();

        getServer().getScheduler().runTaskLater(this, () -> {
            target.set(entity);```...
rustic folioBOT
#

Expected behavior

The server starts normally and re-generated the missing world_gen_settings.dat file, filling it with default values.

Observed/Actual behavior

The following stack trace (+ log) is printed, after which the server startup process does not continue operation and has to be manually shut down.

Server Log:
||```
[21:24:42 INFO]: [bootstrap] Running Java 25 (Java HotSpot(TM) 64-Bit Server VM 25.0.3+9-LTS-jvmci-b01; Oracle Corporation Oracle GraalVM 25.0.3+9.1) on Linux 7.0.12-arch1-1 (amd64)
[21:24:42 INFO]: [bootstrap] Loading Paper 26.2-DEV (2026-07-14T19:24:42Z) for Minecraft 26.2
[21:24:43 INFO]: [PluginInitializerManager] Initializing plugins...
[21:24:44 INFO]: [PluginInitializerManager] Initialized 2 plugins
[21:24:44 INFO]: [PluginInitializerManager] Paper plugins (1):

  • Paper-Test-Plugin (1.0.0-SNAPSHOT)
    [21:24:44 INFO]: [PluginInitializerManager] Bukkit plugins (1):
  • Debuggery (1.5.1)
    WARNING: A restricted method in java.lang.System ha```...
rustic folioBOT
#

I talk about this in a few PRs related to migration...
In vanilla this just happen if delete the dimension and also the file mentioned...

For paper the issue is that file its moved and in migration/regen the fallback try to catch that file fails when overworld was deleted....

The "easy" way can be copy and not move that file for keep the fallback... Or mess with the fallback for generate that file again

(Im in phone but in the PRs for world migration i remember put mentions for that or was in discord....)

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

iirc that's what PlayerItemConsumeEvent does, it doesn't remove the original item if you change it with the setter as said in the javadocs

This event will fire when a player is finishing consuming an item (food, potion, milk bucket).
If the ItemStack is modified the server will use the effects of the new item and not remove the original one from the player's inventory.
If the event is cancelled the effect will not be applied and the item will not be removed from the player's inventory.

#

I mean both of the implementations will feel weird; removing the item even if it was changed sounds weird since it doesn't use the original item so why remove it? But also not removing feels like something where players could just click on every sulfur cube which is weird too...

I guess it's between choosing what is more appropriate and feels less weird

rustic folioBOT
#

Set chunks.auto-save-interval to -1 should disable level data saving and chunks auto save, if there's no other plugins trying to save or unload the worlds. Chunks will still save on unload. Level data saves on shutdown. Both can be saved by /save-all or World.save().

There are cases that some chunk data have to syncLoad on server thread, mostly poi searching, can be triggered by for example using eye of ender / entity AI. It may be alleviated by increasing region file cache.

About the async issue.. Mojang does have a async saving logic for other level data (maps, raids, etc.), however for level.dat it's on server thread though it does not require much changes for async. Personally I think there's no reason, maybe Mojang thinks it's a crucial file. However, Their file operations is not atomicly, so it's possible to leave no level.dat file if the process get terminated.

I don't think this is a good idea; I don't want to disable auto-save—it just doesn't sound secur...

rustic folioBOT
#

Internal testing showed that (without changing region size), storage size of Vanilla worlds at the default compression level is effectively equal to that deflate, and that's with a trained dictionary. zstd is indeed faster, but doesn't come close to lz4, and given the somewhat unfitting/wasteful region format, is "only" 2-3x faster than deflate.

Given that the gains without a dictionary are negative and that maintaining dictionaries takes time and effort both on us and on world upgrades every time a dictionary is replaced (on top of needing to ship every single previous dictionary forever), we decided not to implement it as of now. It would need to be joined with much more drastic storage changes to be worth the effort, i.e. leaf's sector format. Otherwise server owners can/need to train their own dictionaries and deal with the conversion themselves if really wanted

If storage size is your bottleneck, a simple change of the compression algorithm won't help you, if anything...

rustic folioBOT
#

Expected behavior

Create a ClickEvent without a payload, without crashing, as specified by the API

Observed/Actual behavior

I saw tons of errors in my logs :(

Steps/models to reproduce

Component component = Component.text("Helo!")
    .clickEvent(ClickEvent.custom(Key.key("milo", "bilo")));
player.sendMessage(component);

Logs:

[22:26:10 ERROR]: Error sending packet clientbound/minecraft:system_chat
io.netty.handler.codec.EncoderException: Failed to encode packet 'clientbound/minecraft:system_chat'
        at net.minecraft.network.codec.IdDispatchCodec.encode(IdDispatchCodec.java:63) ~[paper-26.2.jar:26.2-60-1cb58fb]
        at net.minecraft.network.codec.IdDispatchCodec.encode(IdDispatchCodec.java:13) ~[paper-26.2.jar:26.2-60-1cb58fb]
        at net.minecraft.network.PacketEncoder.encode(PacketEncoder.java:27) ~[paper-26.2.jar:26.2-60-1cb58fb]
        at net.minecraft.network.PacketEncoder.encode(PacketEncoder.java:12) ~[paper-26.2.jar:26.2-```...
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

I feel like the proper solution is for your plugin to have this flag that you track and check it instead of isEnable. Even if you increase this pr from a 50 lines change to a 50000 lines change to adapt the rest of the api, you won't be able to adapt the plugins. And if you're fine with isBeingEnabled but you need it in the API and not a private field in your own plugin, then I think this is more of a xy problem that you could get help with in discord instead

rustic folioBOT
#

Is your feature request related to a problem?

In the combined 26.2 development changes (#14001), CraftItemStack#asBukkitCopy(net.minecraft.world.item.ItemStack) was changed from public to private, while a new public overload accepting ItemInstance was introduced.

Our project is a dependency library that provides a compatibility layer across multiple Minecraft server versions. Because of that, lower-level conversion methods such as this one are particularly important to us when the required functionality is not consistently available through the public API.

Existing library binaries compiled against previous Paper versions reference the original asBukkitCopy(ItemStack) method directly. Changing its visibility to private causes those binaries to fail on the new version, rather than allowing them to use the new ItemInstance overload.

This breaks the shared compatibility path used across all previously supported...

#

Why are libraries poking server internals expecting to continue working on future versions?

This is also a very common operation. A GitHub code search shows that many plugins and libraries call this method directly, so the impact is not limited to our project.

We understand that it is an internal API and that compatibility is not guaranteed. However, given its widespread usage and the relatively low cost of retaining the existing overload, we believe this specific case is worth reconsidering. If preserving it is not feasible, we will adapt our compatibility layer accordingly.

rustic folioBOT
rustic folioBOT
#

Why are libraries poking server internals expecting to continue working on future versions?为什么库要干涉服务器内部实现,还指望在未来的版本中继续工作?

Isn't this normal practice? Some operations are impossible with just the encapsulated bukkit methods. Using the internal implementation allows for more flexibility and more possibilities. We can't keep asking you to add new methods every time, and those requests might be rejected. Our use of the internal implementation doesn't affect your server's operation, but your modification makes it unusable for us, requiring us to spend time making compatibility adjustments and increasing the workload for others. If you think we shouldn't access the internal implementation, how can the encapsulated methods perform more operations?

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

While I agree that it wouldn't hurt anyone to make this method public again, you should keep in mind that internals are internals, they're not a part of the public stable API. You could for example use MethodHandles to access that method, they are much faster than reflection, almost as fast as direct call, and they would (for now) work for all versions.

This raises a question: if it's almost as fast as a simple call, why go through a detour to execute it when you can call it directly? Secondly, it's encapsulated content; why make it private? I understand you say it's the core logic, but it only converts internal item objects into Bukkit items, which doesn't affect the server's correct operation. Why make it private? You said you created another class; you could keep this and let another class with the same name handle it, instead of removing or making it private. If you use my library, and I make this type of method private in the next update, what will you choose? Continu...

#

This is internal code, not an exposed part of a library, nobody makes guarantees over the ABI of internals which exist solely for their own code, where practices like the least visibility requires for a method is usually the default.

ItemStacks in the API have been modified a lot over the past few years, methods like a bukkit copy make limited sense when bukkit stacks a wrapper over a mojang stack

rustic folioBOT
#

Expected behavior

Having a custom argument, which throws a command exception inside its parser, declared before a signed argument type should throw the command exception as normal, whilst not causing a signed command mismatch error.

Observed/Actual behavior

The executing client gets a different exception:

This command had unexpected or missing command argument signatures.

The following errors appear in the console:

[17:43:53 INFO]: Strokkur24 issued server command: /this-crashes-execution hi hi
[17:43:53 ERROR]: Signed command mismatch between server and client ('this-crashes-execution hi hi'): got [signedmessage] from client, but expected []
[17:43:53 WARN]: Failed to update secure chat state for Strokkur24: 'The command had unexpected or missing command argument signatures.'

Additionally, when the very same client that send the command tries to send a chat message, it gets hit with a:

Chat disabled due to broken chain. Please try reconnecting.
```...
rustic folioBOT
rustic folioBOT
#
[PaperMC/Paper] New branch created: startup-perf
rustic folioBOT
#

Expected behavior

Migrate world to new format

Observed/Actual behavior

Instantly hits a cross-device link error due to trying to link a file outside the filesystem boundaries.

Steps/models to reproduce

  1. Make a dataset or filesystem mountpoint for mcserver/world (or any depth down to: world/dimensions/minecraft/overworld for example)
  2. Install into mcserver/ using a papermc version from earlier this year (Say, a release for 1.21.11)
  3. Run it
  4. Stop it once some world generates
  5. Upgrade
  6. Run it
  7. Migration fails due to a hardlink attempt across different filesystems

Plugin and Datapack List

None

Paper version

26.2-38-dev/26.2@58e1f84

Previous version: 26.1.2-61-8dea6f1 (MC: 26.1.2)

(It was also 1.21.11 earlier)

Other

I think this niche problem could be solved by Paper retrying this preparation step with a traditional copy of the world data rather than making a link. Though this would not be very efficient on a CoW filesystem, it w...

rustic folioBOT
#

Expected behavior

When specifying an item in the dialog body, it should properly apply MiniMessage formatting there, that was the behaviour on PaperMC 1.21.11.

Observed/Actual behavior

<img width="610" height="205" alt="Image" src="https://github.com/user-attachments/assets/3a98045f-c174-4571-9371-bfe974c0c6c5" />

The MiniMessage formatting is completely skipped in dialog body items on latest PaperMC 26.2.

Steps/models to reproduce

I have prepared this sample java code to debug the issue:

        String itemName = "stick[custom_name=\"<red>test\",lore=['<gold>This is a test lore line']]";
        ItemStack item = Bukkit.getItemFactory().createItemStack(itemName);
        data.caster().getEquipment().setItemInMainHand(item);

        Dialog dialog = Dialog.create(builder -> {
            builder.empty().type(DialogType.notice())
                    .base(DialogBase.builder(Component.text("Test Dialog"))
                            .body(List.of(```...
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

I could maybe see a use case for being able to set one part of the rotation relative and the other absolute, which wouldn't be possible with just an addRotation(yaw, pitch) method. I'm not immediately a fan of the current proposed method since I dislike having ambiguous boolean parameters in methods, something like a setRotation(Something.relative(2f), Something.absolute(90f)) could fix that.

I added Angle for that

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

I would like to know if the version check should be dropped (the method with a different signature can't be compiled against 26.2 anyways) and if the added code should be at the start or end of the method. I tried to figure it from the changes but it did not lead me to a fixed result.

I also hope that the removal of the remnant method is ok and if I should also remove the methods which now just call super.

rustic folioBOT
#

Positive works too as long as IDEs support it, I am just more familiar with jetbrains'.

I don't have any suggestions for the javadocs, just needs to be sufficient enough so that plugin devs can know what it does without needing to ask in paper-dev

okay i use the NonNegative (like components) annotation because 0 its a valid number and Positive not allow that...

and for docs... im try something i hope basic explain what this does....

rustic folioBOT
rustic folioBOT
#
  1. Yes, any chained call after one of the pages setter methods will break with a java.lang.IncompatibleClassChangeError: Class org.bukkit.craftbukkit.inventory.CraftMetaBookSigned does not implement the requested interface net.kyori.adventure.inventory.Book. When I am correct that can't be fixed easily because that is an independent call to a different interface? Changing that would also rewrite all "legit" calls to adventure books. Having that method at the end of the chain works however since all other methods (author and title) return the BookMeta and not the Book.
  2. That is nothing that I thought of but like my thoughts to 1.: With the openBook method on the player that is kinda legit, but you could also pass the item stack when you work with meta anyways - without you would just work with a Book directly?

Here is my test with the branch::
||java @Override public boolean execute(final CommandSender sender, final String commandLabel, final String[] args)...

rustic folioBOT
#

Expected behavior

When a player disconnects, the server releases all references to their ServerPlayer object once nothing legitimate holds it. Specifically, per-map holder tracking (MapItemSavedData.carriedByPlayers and the associated HoldingPlayer records) should remove entries for disconnected players, allowing the player object and any per-player map render state to be garbage collected.

Observed/Actual behavior

Disconnected players' ServerPlayer objects are retained indefinitely. Each map's carriedByPlayers list keeps a strong reference to every player who ever received that map's data; entries are only removed by tickCarriedBy, which never runs again for a departed player (maps displayed in item frames are never "carried" by them again). After 100 players joined, received map data from ~3,600 maps in item frames, and disconnected, a forced full GC left 101 ServerPlayer instances and ~42,000 stale holder records on the heap. Reusing/recycling the map ids (540 r...

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

I would also like if I should put another fix for the WritableBookMeta storing the pages as legacy string and converting them leads to that components or if I should put all changes to the Craft classes into a separate PR:

<img width="636" height="148" alt="grafik" src="https://github.com/user-attachments/assets/7aac7f0c-b42f-461e-b530-4288047ee65f" />
Code:
||```java
final Component deserialized = MiniMessage.miniMessage().deserialize("Really");
for (final Material material : new Material[]{Material.WRITTEN_BOOK, Material.WRITABLE_BOOK}) {
final ItemStack book = ItemStack.of(material);
final BookMeta bookMeta = (BookMeta) book.getItemMeta();
bookMeta.title(deserialized).author(deserialized).pages(deserialized);
book.setItemMeta(bookMeta);
player.give(book);
}||

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Moonrise has a configuration, currently commented, for TPS catchup.
This basically makes this configuration accessible so people that don't want TPS catchup can disable it in their servers.

This addresses the discussion at https://github.com/PaperMC/Paper/discussions/10488.
Some plugins probably still rely on the catchup, although documentation on proper practices has been around for years to not rely on that, plus this is an opt-in feature, since I kept the default value as 5 ticks.

rustic folioBOT
#

There's a candidate implementation in a downstream fork worth reviewing: rafalohaki/CanvaSigma@65b979c. As far as I can verify, it correctly clears carriedByPlayers, carriedBy, and player decorations. In its 512-map/24-viewer test, retained state falls to the
active-player baseline.

One scaling consideration: this implementation scans the complete global saved-data cache separately for every departing player, and the callback may also run when players leave a level during world/dimension transitions.

This could make two workloads expensive:

  1. Disconnect storms, where the full catalogue is scanned once per departing player.
  2. Hub-style servers with frequent world transitions.

One possible approach is to queue departures briefly and perform one catalogue scan for the batch, removing all queued players during
that pass. This would reduce a 100-player storm from 100 catalogue scans to one, while preserving the same cleanup semantics, though the batched pass would n...

rustic folioBOT
#

As offered above, here are measurements at approximately 50× the downstream test's map catalogue size.

The rig used 25,000 real cached MapItemSavedData instances and 100 Mineflayer clients with 420 holder relationships each, giving 42,000 relationships before departure, on stock Paper 26.2 build 48 (87c4d42). A rig-only reflection plugin performed the same holder removals as the candidate implementation.

Single disconnect

  • Per-player scan: 10.934 ms
  • One-player batched scan: 9.563 ms

Isolated departures look acceptable at this catalogue size — though not literally free on a server already near its 50 ms tick budget.

100-client disconnect storm

  • Control: retained all 42,000 relationships.
  • Per-player cleanup: 100 catalogue scans, 1,504.2 ms total measured cleanup.
  • Coalesced cleanup: one catalogue scan, 30.308 ms total measured cleanup.
  • Both cleanup modes removed all 42,000 relationships.

In this run, coalescing reduced cleanup wor...

#
[PaperMC/Paper] branch deleted: startup-perf
rustic folioBOT
rustic folioBOT
#

Expected behavior

entity.getData(DataComponentTypes.SULFUR_CUBE_CONTENT); should return the sulfur sube content and not throw an exception.

Observed/Actual behavior

Class cast exception: https://haste.devcord.club/nj1BB8

Steps/models to reproduce

Simply try to access the contents of a sulfur cube using getData

Plugin and Datapack List

<img width="887" height="119" alt="Image" src="https://github.com/user-attachments/assets/43ef09f1-ab7e-4f32-a8d8-e93e827aeb9a" />
Only built in datapacks.

Paper version

This server is running Paper version 26.2-65-main@fc9375a (2026-07-22T08:55:19Z) (Implementing API version 26.2.build.65-beta)
You are running the latest version
Previous version: 26.2-63-3a55f62 (MC: 26.2)

Other

When I try to access the contents of a sulfur cube via the getData() method using this code:
https://haste.devcord.club/8bSbQw
I get the following exception:
https://haste.devcord.club/nj1BB8
Full server log:
https://haste.devcord.club/...

rustic folioBOT
#

This pull request changes how chunk packets are constructed to send separate Block Entity Update packets based on the block entity's size, and not just on how many block entities are in the chunk.

Each block entity is serialized once to not add overhead for checking the data size:

  • If it's not too big or hasn't exceeded the block entity limit per chunk, it's added to the regular block entity data list directly.
  • If it is, it's re-serialized as a packet to be sent separately alongside the chunk packet

The client-bound block entity data packet now also has a fallback for when it's too large to be sent, to prevent being kicked.

  • A new AsyncBlockEntityUpdateTooLargeEvent is fired
  • The block entity update is ignored

I was not able to perceive any performance loss for normal or large block entities when profiling, however there is a theoretical tradeoff where large block entities would be serialized twice, this should not matter in most cases

rustic folioBOT
rustic folioBOT
#

This PR addesses https://github.com/PaperMC/Paper/issues/13832

This does not trigger for world generation (when the end portal generates with all eyes)
It also, at the moment of writing this, does not trigger for the end gateway and exit end portal, as those don't have straightforward access to the Entity that will trigger the portal creation.

See:

  1. net.minecraft.world.level.levelgen.feature.EndGatewayFeature
  2. net.minecraft.world.level.levelgen.feature.EndPodiumFeature

Compared to:

  1. net.minecraft.world.level.levelgen.feature.EndPlatformFeature at L28
  2. net.minecraft.world.level.block.EndPortalBlock at L100
rustic folioBOT
#

Is your feature request related to a problem?

I would like to log command execution. I can easily track players that try to execute any command with PlayerCommandPreprocessEvent. This event however does not give any insights whether the command was executed successfully or not.

Describe the solution you'd like.

A PostCommandInvocationEvent like velocity has it already, would solve this problem perfectly with a result argument.

Describe alternatives you've considered.

You could just not log the command result, but especially for logging purpose this is extremely helpful to identify irregular behavior.

Other

No response

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

This PR improvement the logic for PlayerItemConsumeEvent, currently only its called when the use of item reach 0 (consume) this logic works when the consume time is set and its not 0, when its 0 this logic is skipped and the event its not called, for fix this i call this event for that case too and handle the most of logic like happen with the item in use...

This can close https://github.com/PaperMC/Paper/issues/13138

rustic folioBOT
rustic folioBOT
#

Is your feature request related to a problem?

There is no problem. But this comes from an inconsistency; TNTPrimed and Creeper both have a method to get the igniter of the explosive. ExplosiveMinecart does not.

Describe the solution you'd like.

Add a way to get the igniter of an explosive minecart. TNTPrimed has getSource(), Creeper has getIgniter(), yet ExplosiveMinecart entity has no way to get the igniter.

Describe alternatives you've considered.

I've considered adding data to the persistent data container of the explosive minecart to know who ignited the minecart.

Other

No response

rustic folioBOT
rustic folioBOT
#

Is your feature request related to a problem?

Currently the air change event only returns the new oxygen ticks, if you wanted to, let's say, make air deplete twice as fast, you would need to know what was the change and multiply that by two, which the API does not currently provide.

Describe the solution you'd like.

To fix the issue the API should provide either a "getOldAmount" or a "getChange" method (or both!)

Describe alternatives you've considered.

The only alternative I could think of is tracking the old tick amount every time the event is called and compare it with the current event, but that's janky

Other

No response

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Interesting question—does this mean that, thanks to this very quirk, a dual-dimension mob farm built around Nether portals could outperform vanilla, albeit with a slight lag increase? Mobs teleport one tick earlier the instant they spawn, so the local cap is reached more slowly and more mobs can generate. Has this been fixed yet?

I never expected to have to refute my own self from a year ago. Based on my more detailed testing recently, this non‑vanilla behavior does indeed improve the efficiency of double‑dimension mob farms—by up to a factor of two. This is because the mobs' lifetime is reduced by 1 game tick, which frees up the mob cap earlier, allowing the next batch of mobs to spawn sooner. I tested this using a Zombified Piglin farm that produces 10 million drops in vanilla, and the result was that the output doubled to 20 million. However, as I mentioned before, this also causes slight differences in the position and momentum of entities after they pass through porta...

rustic folioBOT
rustic folioBOT
#

I am not a huge fan of of possibly skipping an entire block entity.

What is the end goal here? What in-game scenario and then plugin response would benefit from this addition?
I can partially understand that a "byte size" threshold might be more relevant than a plain "count" threshold on the oversized block entity logic but I cannot see much use in letting plugins handle an oversized block entity that somehow does not even fit into a ClientboundBlockEntityDataPacket

#

I partially agree with mbax here, the method name should reflect that this is an attempt at equipping an item. I love cube.nom(ItemStack) /s. SulfurCube#attemptAbsorb / tryAbsorb / absorb would work. So would swallow. Its not really an active equipping.

Javadocs should mention that events are called.

Also unsure about the boolean return, how do I get the itemstack that was possibly dropped from the sulfur cube?


Tho the more I think about it the less convinced I am that this method is even needed in the first place. The use case for actually running the vanilla logic seem small. E.g. how often would a plugin really need to "simulate" a player actively attempting to place a block into a sulfur cube. Most of the times it'd probably be a direct set and playing the noise, which this method does not offer fine control over.
The primary motivation for adding this method seem to be related to API simplicity, which is a fair goal but that could be solved via a p...

#

The two Craft* changes don't belong here, but the commodore changes look reasonable

As already wrote to mbax in the DC I made these changes to retain the behavior to before the adventure 5 change. After that the Writable Book no longer had colorful pages and the WrittenBook no longer had neither title nor author.

For that reason I see that as required part of the fix to maintain backwards compatibility/have consistent behavior.

#

@lynxplay

Agree with Lulu. It is a bit nasty, a typed key should be able to extend Key, it is identifying something via a namespace and value but the fact that a the plain key implementation considers any key with equal namespace and value equal means we should probably bite the bullet and make this keyed instead. A pretty meh equal impl of KeyImpl imo, idk if this is worth bringing up with adventure folks.

I don't think that TypedKey should be able to extend Key. It is not really a key by itself, but a tuple of two keys (registry identifier + element identifier). Even if adventure's KeyImpl were to check for the exact class and thereby make this adhere to the contract of equals, it would still be very unintuitive to have two different Keys where namespace and value match but they're not equal. This becomes especially confusing when a TypedKey gets passed into a function that accepts Key and the static type information of one of them being a TypedKey is lost....

#

Your concerns sound very reasonable. Based on that, would the following changes be accepted?

  • Addition of SulfurCube#setEquipped(ItemStack), with the sole purpose of silently setting the currently equipped item stack, with the goal being API simplicity.
  • Addition of ItemStack SulfurCube#getEquipped(), the appropriate getter, same use case as above.
  • Rename boolean equipItem(ItemStack) to boolean swallow(ItemStack), noting the events + logical difference to setEquipped, cross referencing both in @see Javadoc note?
rustic folioBOT
#

This all based around the idea that once a packet is too big the player will be kicked from the server.

When a chunk contains an excessive amount of block entities, or a few massive block entities, the player will be kicked and unless the server sends the player to spawn when they rejoin, they won't be able to join back.

In any case, when this is hit we want the safest recovery possible, which in my opinion is skipping the block data and instead showing a "data-less" block.

The new event is useful for server owners / plugin developers as when this happens it's usually a sign of a chunk that may need to be purged or have the block entity be removed, without the event Paper would simply be silently hiding the block data without plugins being able to do something about it.

rustic folioBOT
rustic folioBOT
#

Hi! I’ve previously contributed to the PaperMC documentation, and I’d like to work on this as my first contribution to the Paper codebase.

My proposed scope is to update LootGenerateEvent so its loot-table field, constructor parameter, and getLootTable() return value are correctly marked nullable, and to clarify in the Javadocs that an unknown or unregistered loot table can result in null.

I would leave a possible getLootTableKey() API addition for a separate change because that requires additional API design and may overlap with the loot-table registry work in #13657.

Would this narrower nullability and documentation fix be acceptable?

#

Same issue here. Upgraded to experimental from 1.21.3. World folder is on a single volume. Here's a snippet from the log output if it helps:

[17:38:56 WARN]: [WorldFolderMigration] ===================== ! ALERT ! =====================
[17:38:56 WARN]: [WorldFolderMigration] World storage migration is required during startup.
[17:38:56 WARN]: [WorldFolderMigration] If you do not have a backup: interrupt the server now. Use Ctrl+C, your panel kill function, etc.
[17:38:56 WARN]: [WorldFolderMigration] =====================================================
[17:38:56 WARN]: [WorldFolderMigration] Continuing in 30 seconds...
[17:39:26 INFO]: [WorldFolderMigration] Continuing with startup world migration.
[17:39:26 INFO]: Starting upgrade for world "Telvanni"
[17:39:26 INFO]: Upgrading progress: 0%
[17:39:27 INFO]: Upgrading progress: 38%
[17:39:28 INFO]: Upgrading progress: 72%
[17:39:30 INFO]: Upgrading progress: 98%
[17:39:32 INFO]: Upgrading progress: 99%
[17:39:32 INFO]: File```...
rustic folioBOT
rustic folioBOT
#

Is your feature request related to a problem?

Based on the discussion here and [this message](#1530836467763511387 message).

tl;dr of this. is discussion about the usefulness of the various old configuration files - in this case - commands.yml

Describe the solution you'd like.

If we're going to touch commands.yml, it's a good time to make it even more useful and give it some more abilities that will save time from making or looking for plugins having to do with the simplest things regarding commands.

  • ability to create commands with basic functionality, like command that sends minimessage message to the command sender

Describe alternatives you've considered.

Using messy plugins like mycommand or skript to alias or create commands that just send text back, which is not ideal, because the aliases made by those commands are usually...

#
[PaperMC/Paper] New branch created: extra-files
#
[PaperMC/Paper] branch deleted: extra-files
#
[PaperMC/Paper] New branch created: extra-files
rustic folioBOT
#

Also, it would be very nice (at least for me and my team) if the default path to ".paper" directory could be changed via command line argument at server startup, i.e. -DPaper.cacheDirectory=... or --paper-cache-directory ... (similar to already existing --paper-settings-directory) <3

That would be a really nice addition when we are already creating a single source of truth for that in PaperCacheDir :+1:

#

Is your feature request related to a problem?

A fresh Paper install generates nine config surfaces: server.properties,
bukkit.yml, spigot.yml, commands.yml, permissions.yml, help.yml,
config/paper-global.yml, config/paper-world-defaults.yml, and a paper-world.yml
per world.

bukkit.yml and spigot.yml aren't laid out the way Paper is laid out. They're
laid out the way Bukkit was in 2011 and Spigot was in 2013. Keeping them is
reasonable, but the side effect is that new options land in config/ while the
related old ones stay where they were, so a lot of single knobs are now spread
over two to four files under different names and different units.

Here's what we have with fresh configs:

Dimension toggles. bukkit.yml:

settings:
  allow-end: true

paper-global.yml:

misc:
  enable-nether: true

Same scope, same meaning. One is allow-, one is enable-. One is under
settings, one is buried in misc. enable-nether was allow-nether in
server.properties b...

#

Slightly more complex concept - introducing some form of "command condition", plugins could potentially register new custom conditions to the server too, that could then be used in the commands.yml to allow creating slightly more complicated commands.

Although I am not sure if this would necessarily provide any new functionality over an alias and could just make the file complicated for niche reasons

rustic folioBOT
#
[PaperMC/Paper] branch deleted: extra-files
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#
[PaperMC/Paper] New branch created: exp-annotations
#

Expected behavior

When a repeating ScheduledTask is cancelled while it is running, I would expect it to report CANCELLED_RUNNING until the callback finishes and CANCELLED afterwards.

Observed/Actual behavior

Future runs are cancelled correctly, but the task never leaves CANCELLED_RUNNING. Calling cancel() later also returns NEXT_RUNS_CANCELLED_ALREADY, even though the callback has already finished

I reproduced this with a repeating global-region task on Paper 26.2-83. The callback only ran once, but the state was still CANCELLED_RUNNING one and two seconds after it returned.

Log from the reproduction:

[21:36:47 INFO]: [ScheduledTaskStateRepro] callback-start run=1 state-before-cancel=RUNNING
[21:36:47 INFO]: [ScheduledTaskStateRepro] cancel-during-callback=NEXT_RUNS_CANCELLED
[21:36:47 INFO]: [ScheduledTaskStateRepro] state-after-cancel-in-callback=CANCELLED_RUNNING
[21:36:47 INFO]: [ScheduledTaskStateRepro] callback-returning run=1
[21:36:48```...
#

Is your feature request related to a problem?

Using paper-26.1.2-74.jar (currently marked as supported on download page).

Currently to ignoreVanillaPermissions you have to set it manually in commands.yml or via

((CraftServer) Bukkit.getServer()).ignoreVanillaPermissions = true;

I'm managing a mini games network, where on each backend server a single plugin exists, that should take control of this backend server and therefore the minigame. I find it a better solution to configure the server to my liking via plugins than via configuration files. As commands.yml was made optional, i'd favor to set this via plugin.

Describe the solution you'd like.

Expose a setter (and maybe a getter) for CraftServer#ignoreVanillaPermissions.

Something like org.bukkit.Server#setIgnoreVanillaPermissions(boolean) and org.bukkit.Server#getIgnoreVanillaPermissions().

I would say, that changing this via plugin is temporary for the current runtime of the server and is not...

rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Is your feature request related to a problem?

Yes it is related, the main problem is that Spigot 26.2-R0.1-SNAPSHOT contains this method and would be very nice if also Paper had also this method since it would make plugins more easly compatible with different server softwares

Describe the solution you'd like.

Add that method

Describe alternatives you've considered.

I've considered using an Adapter that detect which software is running and uses the right method but more work that could be avoided by adding that method

Other

https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/Mannequin.html#setPlayerProfile(org.bukkit.profile.PlayerProfile)

#

As far as I can tell this isn't just due to the presence of a requires predicate (i.e., _ -> true works & source.getSender().hasPermission("some.permission") does too (NullCommandSender#hasPermission always returns true)), but more that instanceof Player returns false for the NullCommandSender used when testing whether the node is restricted.

As a workaround you could additionally test if the sender's name is empty when wanting to restrict commands to only

rustic folioBOT
#

Something else that may be worth mentioning is that, tested using only the code from above, it sometimes makes the player move in unexpected ways, including:

[13:00:45 WARN]: JustEli moved too quickly! 9.930077890270105,0.0,-12.614604219647621

And using code that is extremely similar to the above code, I have had players report getting teleported into weird positions, even to the void at Y -300!

If this behavior is as expected, is there a way to detect this "teleportation" because currently it goes under the radar. I can't detect where the player is going, other than for the event that is canceled (but it still happens). This is still an issue on 26.2.

#

Closes #10708.

CraftMerchantRecipe's scalar setters (setUses, setDemand, setExperienceReward, setSpecialPrice, and so on) write straight through to the backing NMS MerchantOffer, so they take effect the moment you call them. The ingredient methods did not: addIngredient, removeIngredient, and setIngredients were inherited unchanged from the API's MerchantRecipe and only touched the base list. The handle's baseCostA/costB were rebuilt exclusively inside toMinecraft(), which runs on trade refresh, so setExperienceReward(true) applied instantly while setIngredients(...) only landed once the trade screen rebuilt.

The issue asks to make this consistent one way or another. This picks write-through, since it matches the eight existing scalar setters and the fact that getRecipe() hands back a live-backed wrapper. Ingredient changes now sync to the handle immediately; ingredient-agnostic behavior is unchanged.

  • Overrides addIngredient, removeIngredien...
rustic folioBOT
#

I talk about this in [discord](#paper-contrib message) this PR make a few improvements to allow more uses for the Interaction Entity

  • Allow modify behaviour for projectiles, currently the projectile just ignore the entity, this PR allow change that and then you can listen the ProjectileHitEvent, this can help for cases where wanna use a Display and also an Interaction
  • Call Damage Events for damages not related to Player, currently only the direct damage by Player are called, other damages are ignored... the PR now call for the others damages in cancel state because the final damage its ignored, i follow the same logic than ArmorStand where the damage events are called even if the entity cannot be damaged (Invulnerable tag)
rustic folioBOT
#

Expected behavior

Sulfur cube doesn't disappear if PlayerInteractAtEntityEvent cancelled, Bucket in player's hand remains empty.

Observed/Actual behavior

Bucket remains empty, sulfur cube still exists in the world

Steps/models to reproduce

  1. Install a plugin that has this:
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
public void onPlayerInteractAtEntityEvent(PlayerInteractAtEntityEvent event) {
    event.setCancelled(true);
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onPlayerInteractAtEntityEventMonitor(PlayerInteractAtEntityEvent event) {
    getLogger().info(String.format("PlayerInteractAtEntityEvent %s: %b", event.getRightClicked(), event.isCancelled()));
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onPlayerBucketEntityEvent(PlayerBucketEntityEvent event) {
    getLogger().info(String.format("PlayerBucketEntityEvent %s: %b", e```...
rustic folioBOT
rustic folioBOT
#

Expected behavior

Setting either 'chat-spam-threshold-seconds' or 'command-spam-threshold-seconds' in server.properties to 0 prevents players from being kicked for spam when sending chat messages/typing commands.

Observed/Actual behavior

On Paper servers, setting these properties to 0 makes it so you can't send any chat messages/commands at all without being kicked from the server for spam.

On vanilla, however, setting these properties simply makes it so players no longer get kicked for spam, as intended.

Steps/models to reproduce

Create a new Paper 26.2 server and set both 'chat-spam-threshold-seconds' and 'command-spam-threshold-seconds' to 0
Start the server
Without being opped, send a single message or type a single command and see what happens.

Plugin and Datapack List

No plugins or datapacks apart from the built-in ones: [vanilla (built-in)], [file/bukkit (world)], [paper (built-in)]

Paper version

[16:13:54 INFO]: Checking version, please w...

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

I started this PR just trying to fix #14113, but after attempting to clean up the logic, I found that it missed quite a bit of client prediction, so I decided to do a bit of a bigger refactor. More notes on the commit messages.

I also figured it'd be safe to tackle #11496 while I was modifying this part of the code, noting that right now it is safe to not resend tracked entity data for interaction entities as they don't do any client-side prediction.

Opening as a draft as I have yet to test all the cases that have been fixed, I'll try to edit the PR with a video showing the parts that were missed in the previous logic. If someone suffering from #14113 or #11496 wants to test the PR, you can hit me up in the Paper discord if you do find issues

rustic folioBOT
rustic folioBOT
rustic folioBOT
#

Expected behavior

A world created or saved by Paper 26.2 beta should be fully compatible with Vanilla 26.2 and NeoForge 26.2.

The world should start without requiring any manual file modifications or file copying.

Observed/Actual behavior

Vanilla 26.2 and NeoForge 26.2 fail to load the world with:

Unable to read or access the world gen settings file!
world/data/minecraft/world_gen_settings.dat

IllegalStateException: Overworld settings missing

The file world/data/minecraft/world_gen_settings.dat is missing.

However, Paper stores world_gen_settings.dat in:

world/dimensions/minecraft/overworld/data/minecraft/world_gen_settings.dat

After manually copying this file to:

world/data/minecraft/world_gen_settings.dat

both Vanilla 26.2 and NeoForge 26.2 start successfully and the world loads correctly.

Steps/models to reproduce

  1. Create or start a Minecraft 26.2 world using Paper 26.2 beta.
  2. Stop the Paper server normally.
  3. Copy...