-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend HumanEntity#dropItem API #11810
base: main
Are you sure you want to change the base?
Extend HumanEntity#dropItem API #11810
Conversation
All of the default methods that are single-line redirects probably make it harder to parse than they help, I'd reduce some or even all of them, not sure. If you do want to keep default helpers, they should be moved as proper |
Oh that's smart, I hadn't though about that. Thanks for that suggestion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And you can remove the Paper comments and add imports instead of fqn
paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
Outdated
Show resolved
Hide resolved
paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
Outdated
Show resolved
Hide resolved
Are this many overloads really needed? |
I think removing the thrower parameter would already decrease the method amount by a fair bit |
I feel like that is too complicated and would kinda defeat its purpose.
That feels weird, as dropping an item sounds like you actually don't have it in your inventory anymore. Giving the developer the task of removing it themselves feels like a fair bit of unneeded code in this context. |
I mean, it would not remove a single method, as there is also That sounds like a good middle-ground solution to me. If the developer wants to set the thrower they can do so. That means it would turn to only these overloads:
|
It's similar to already existing methods (e.g. World#dropItem), entity spawning methods have the save overloads.
No, I mean to literally not link the dropped itemstack to anything, i.e. the drop would simply drop the cloned item no matter its source, not remove it from inventory or anything else. Then you just get the item in that slot and decrease its amount. |
It's not entirely the same though. @Override
public org.bukkit.entity.Item dropItem(Location loc, ItemStack item, Consumer<? super org.bukkit.entity.Item> function) {
Preconditions.checkArgument(loc != null, "Location cannot be null");
Preconditions.checkArgument(item != null, "ItemStack cannot be null");
ItemEntity entity = new ItemEntity(this.world, loc.getX(), loc.getY(), loc.getZ(), CraftItemStack.asNMSCopy(item));
org.bukkit.entity.Item itemEntity = (org.bukkit.entity.Item) entity.getBukkitEntity();
entity.pickupDelay = 10;
if (function != null) {
function.accept(itemEntity);
}
this.world.addFreshEntity(entity, SpawnReason.CUSTOM);
return itemEntity;
} Notice the In my implementation, I directly call |
You can add overload to Edit: by the way, since it calls Player#drop, might be useful to mention in javadoc that it'll cause PlayerDropItemEvent? |
It'd honestly rather not change NMS code without a valid reason. Could add the JavaDocs information though |
Should be fine, it's done all the time and is a small change. I'd argue the ability to drop any item, not linked to inventory would be more useful and cover more cases. You can already get an item by int/equipment slot and decrease its amount alongside if you need that. |
I suggest that it is not yet merged. After some discussion, I'd like to change it one last time |
paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
Outdated
Show resolved
Hide resolved
paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
Show resolved
Hide resolved
Alright, I've done the following changes now:
|
Very well, I will go to work doing the changes! |
I would call those methods
I would call those methods |
Just for testing, I setup the following command: event.registrar().register(Commands.literal("drop")
.then(Commands.literal("one")
.executes(ctx -> {
((Player) ctx.getSource().getExecutor()).dropItemRandomly(EquipmentSlot.HAND, 1);
return 1;
}))
.then(Commands.literal("all")
.executes(ctx -> {
((Player) ctx.getSource().getExecutor()).dropItemAll(EquipmentSlot.HAND);
return 1;
}))
.then(Commands.literal("any")
.then(Commands.argument("item", ArgumentTypes.itemStack())
.executes(ctx -> {
((Player) ctx.getSource().getExecutor()).dropAnyItem(ctx.getArgument("item", ItemStack.class), item -> {
item.setGlowing(true);
});
return 1;
})))
.build()); You can see the result here: reduced_5.mp4 |
Also, I don't really like that all methods require an item consumer (or null) |
I feel like new API users could get confused on what those methods do, even when reading the JavaDoc (which I am yet to add).
Yeah, sounds like a good idea. |
I already have overload methods for that |
Most of these are just default methods on the interface @Nullable
public Item dropItemRandomly(@NotNull EquipmentSlot slot, int amount, @Nullable Consumer<Item> entityOperation);
@Nullable
public default Item dropItemRandomly(@NotNull EquipmentSlot slot, int amount) {
return this.dropItemRandomly(slot, amount, null);
}
@Nullable
public default Item dropItemAll(int slot, @Nullable Consumer<Item> entityOperation) {
return this.dropItem(slot, Integer.MAX_VALUE, entityOperation);
}
@Nullable
public default Item dropItemAll(int slot) {
return this.dropItemAll(slot, null);
}
@Nullable
public default Item dropItemAll(@NotNull EquipmentSlot slot, @Nullable Consumer<Item> entityOperation) {
return this.dropItem(slot, Integer.MAX_VALUE, entityOperation);
}
@Nullable
public default Item dropItemAll(@NotNull EquipmentSlot slot) {
return this.dropItemAll(slot, null);
} |
|
Do you have any idea on what I could rename |
Potentially somthing like |
Not sure I like it. |
but i think just mentioning in the docs that the item is not tied to the players inventory at all and will spawn a new item is better |
Yeah probably. I am not having any ideas either |
Clashing with other methods isn't ideal either, since the behavior is different enough. Even with javadocs it'd be quite easy to miss. I don't like |
Would |
As another suggestion, |
Maybe |
Yeah I like that one. |
Ok, now its just soo many methods. What was the original issue with a |
@@ -1376,6 +1383,11 @@ | |||
+ return null; | |||
+ } | |||
+ } | |||
+ // Paper start - Extend HumanEntity#dropItem API | |||
+ if (entityOperation != null) { | |||
+ entityOperation.accept((org.bukkit.entity.Item) itemEntity.getBukkitEntity()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might make sense to apply it before PlayerDropItemEvent
?
|
||
final net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack); | ||
|
||
final ItemEntity droppedEntity = this.getHandle().drop(nmsItemStack, throwRandomly, true, true, entityOperation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drop
should have a separate handling for cancelled PlayerDropItemEvent
in case of arbitrary items. This is a special case, the item's source might not be player's inventory, so the item should not be neccesarily added to the player's inventory, but rather let the dev handle it.
Edit: also, as an example, if the item was from the inventory, we will be adding back its copy, essentially duplicating the item, which might not be the desired behavior. It is way easier to manually add the item to inventory if this is wanted than to prevent this if this would be the default behavior.
Too many overloads for a single method, I guess.
That should cut it down to like a quarter of the methods. And that's gonna be it. |
I think non-entityOperation ones could stay (@Machine-Maker?), given that's the only overload left; while this would be 3 methods * 2 for item consumption overloads, it would be on pair with other such APIs, and requiring users to pass |
Closes #11656
Post-softspoon version of #11689
Motive
Developers currently have to either use NMS or copy-paste the already existing NMS implementation. This PR aims to fix that by exposing ways to call that NMS implementation more easily by extending onto the (Human)Player#dropItem method to provide more extensive ways of making the player drop items from their inventory.
What does it add?
The following method have been added:
Item dropItem(int slot, int amount, @Nullable Consumer<Item> entityOperation)
Item dropItem(int slot, int amount)
Item dropItem(@NotNull EquipmentSlot slot, int amount, @Nullable Consumer<Item> entityOperation)
Item dropItem(@NotNull EquipmentSlot slot, int amount)
Item dropItemRandomly(int slot, int amount, @Nullable Consumer<Item> entityOperation)
Item dropItemRandomly(int slot, int amount)
Item dropItemRandomly(@NotNull EquipmentSlot slot, int amount, @Nullable Consumer<Item> entityOperation)
Item dropItemRandomly(@NotNull EquipmentSlot slot, int amount)
Item dropItems(int slot, @Nullable Consumer<Item> entityOperation)
Item dropItems(int slot)
Item dropItems(@NotNull EquipmentSlot slot, @Nullable Consumer<Item> entityOperation)
Item dropItems(@NotNull EquipmentSlot slot)
Item dropItemsRandomly(int slot, @Nullable Consumer<Item> entityOperation)
Item dropItemsRandomly(int slot)
Item dropItemsRandomly(@NotNull EquipmentSlot slot, @Nullable Consumer<Item> entityOperation)
Item dropItemsRandomly(@NotNull EquipmentSlot slot)
Item dropItem(@Nullable ItemStack itemStack, @Nullable Consumer<Item> entityOperation)
Item dropItem(@Nullable ItemStack itemStack)
Item dropItemRandomly(@Nullable ItemStack itemStack, @Nullable Consumer<Item> entityOperation)
Item dropItemRandomly(@Nullable ItemStack itemStack)
This may look like a lot at first glance (and it kind of is), but in reality, most of these are just default methods on the
HumanEntity
interface. The only, actually implemented methods are:Item dropItem(int slot, int amount, @Nullable Consumer<Item> entityOperation)
Item dropItem(@NotNull EquipmentSlot slot, int amount, @Nullable Consumer<Item> entityOperation)
Item dropItemRandomly(int slot, int amount, @Nullable Consumer<Item> entityOperation)
Item dropItemRandomly(@NotNull EquipmentSlot slot, int amount, @Nullable Consumer<Item> entityOperation)
Item dropItem(@Nullable ItemStack itemStack, @Nullable Consumer<Item> entityOperation)
Item dropItemRandomly(@Nullable ItemStack itemStack, @Nullable Consumer<Item> entityOperation)
And even among these neither have more than 5 lines in their implementation in
CraftHumanEntity
.All logic goes through the added methods
private CraftHumanEntity#dropItemRaw(...)
andprivate CraftHumandEntity#dropAnyItemRaw(...)
, where the logic is fairly simple due to the pre-implemented NMS methodPlayer.dropItem(...)
.Furthermore,
booleam dropItem(boolean)
has been deprecated in favor ofItem dropItems(EquipmentSlot.HAND)
orItem dropItem(EquipmentSlot.HAND, 1)
.Implementation details
Internally, the implementation calls
net.minecraft.world.entity.player.Player#dropItem(...)
, making it a fairly maintainable API.I have added an additional overload to the the
Player#dropItem(...)
method, which takes in a nullableConsumer<org.bukkit.entity.Item>
to allow for entity operations before the Entity has been added to the world.JavaDocs status
JavaDocs have been added.
Usage example