Skip to content

Regression: PlayerDeathEvent custom drops are mutated into AIR by the server after the event is handled #11520

@0dinD

Description

@0dinD

Expected behavior

PlayerDeathEvent custom drops are not mutated in any way by the server after the event is handled.

Observed/Actual behavior

PlayerDeathEvent custom drops are mutated into AIR by the server after the event is handled.

Steps/models to reproduce

Given the following (somewhat contrived) example code:

package org.example.plugin;

import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;

public class ExamplePlugin extends JavaPlugin implements Listener {

	@Override
	public void onEnable() {
		getServer().getPluginManager().registerEvents(this, this);
	}

	@EventHandler
	public void onPlayerDeath(PlayerDeathEvent e) {
		final ItemStack itemStack = new ItemStack(Material.DIAMOND);
		// Any custom drops added are affected by this issue
		e.getDrops().add(itemStack);

		// This one prints the diamond, it's fine.
		getLogger().info(">>> Item stack before PlayerDeathEvent: " + itemStack);
		getServer().getScheduler().runTask(this, () -> {
			// This one prints AIR, where did the diamond go?
			// If you attach a debugger you can see that the underlying NMS item is still
			// a diamond, but the item stack count is set to 0, which is why the item is treated as AIR.
			getLogger().info(">>> Item stack after PlayerDeathEvent: " + itemStack);
		});
	}

}

You should be able to observe the following output when a player dies (e.g. using /kill):

[ExamplePlugin] >>> Item stack before PlayerDeathEvent: ItemStack{DIAMOND x 1}
[ExamplePlugin] >>> Item stack after PlayerDeathEvent: ItemStack{AIR x 0}

As you can see, the item stack added as a custom drop was mutated into AIR by the server. Note that this issue only affects custom drops added, not any of the original drops that the player had in their inventory.

Plugin and Datapack List

[03:14:44 INFO]: Server Plugins (1):
[03:14:44 INFO]: Bukkit Plugins:
[03:14:44 INFO]:  - ExamplePlugin
[03:15:38 INFO]: There are 3 data pack(s) enabled: [vanilla (built-in)], [file/bukkit (world)], [paper (built-in)]
[03:15:38 INFO]: There are no more data packs available

Paper version

[03:16:13 INFO]: Checking version, please wait...
[03:16:13 INFO]: This server is running Paper version 1.21.1-128-master@d348cb8 (2024-10-21T16:23:24Z) (Implementing API version 1.21.1-R0.1-SNAPSHOT)
You are running the latest version

Other

After some testing, I can conclude that this seems to be a regression introduced in build 79 for Minecraft 1.21.1, i.e. commit 0a53f1d. On earlier builds, the drops are not mutated into air and so both of the log statements in the example code print a diamond, as expected.

I didn't debug far enough to tell what code path is setting the item stack count to 0, but to me it seems like the regression introduced in build 79 is that the custom drop item stacks are no longer copied, so if the server mutates them then that will now affect the API user. I'm not entirely sure if the API user should guard against this by cloning the item stack or if this is a bug that should be fixed in Paper, but I'm leaning toward the latter. In which case, please see my PR #11521 for a possible patch to fix this regression.

Let me know if this seems correct or if I have perhaps misunderstood something.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: acceptedDisputed bug is accepted as valid or Feature accepted as desired to be added.type: bugSomething doesn't work as it was intended to.version: 1.21.1Game version 1.21.1

    Type

    No fields configured for Bug.

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions