Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions API/src/main/java/fr/maxlego08/menu/api/InventoryListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ default boolean addItem(BaseInventory baseInventory, boolean inPlayerInventory,
return false;
}

/**
* Called when the item of a button already placed is replaced after the inventory has been opened,
* for example once a player head texture has been loaded.
*
* @return true if the listener displayed the item itself and the default placement must be skipped
*/
default boolean updateItem(BaseInventory baseInventory, boolean inPlayerInventory, ItemButton itemButton) {
return false;
}

default void onInventoryPreOpen(Player player, BaseInventory baseInventory, int page, Object... objects){

}
Expand Down
10 changes: 10 additions & 0 deletions API/src/main/java/fr/maxlego08/menu/api/engine/ItemButton.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ public ItemButton setLeftClick(@NotNull Consumer<InventoryClickEvent> onLeftClic
return this;
}

/**
* Changes the item stored by this button without placing it anywhere.
* The caller is responsible for displaying it.
*
* @param displayItem the new display item
*/
public void setDisplayItem(@NotNull ItemStack displayItem) {
this.displayItem = displayItem;
}

public void updateDisplayItem(@NotNull ItemStack displayItem) {
this.displayItem = displayItem;
if (this.inPlayerInventory) {
Expand Down
36 changes: 36 additions & 0 deletions Common/src/main/java/fr/maxlego08/menu/inventory/VInventory.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,42 @@ public ItemButton addItem(boolean inPlayerInventory, int slot, ItemStack itemSta
return button;
}

/**
* Replaces the item of a button already placed, keeping its click handlers.
* Goes through the same anti-dupe and inventory listeners as {@link #addItem(boolean, int, ItemStack, boolean)},
* so a button placed in the player inventory is updated in the player inventory and not in the menu.
*/
public void updateItem(boolean inPlayerInventory, int slot, @NotNull ItemStack itemStack, boolean enableAntiDupe) {

if (this.isClose) return;

ItemButton button = (inPlayerInventory ? this.playerInventoryItems : this.items).get(slot);
if (button == null) return;

ItemStack displayStack = itemStack.clone();

if (Configuration.enableAntiDupe && enableAntiDupe) {
displayStack = this.plugin.getDupeManager().protectItem(displayStack);
}

button.setDisplayItem(itemStack);

boolean needCancel = false;
for (InventoryListener inventoryListener : this.plugin.getInventoryManager().getInventoryListeners()) {
if (inventoryListener.updateItem(this, inPlayerInventory, button)) {
needCancel = true;
}
}

if (needCancel) return;

if (inPlayerInventory) {
this.player.getInventory().setItem(slot, displayStack);
} else {
this.inventory.setItem(slot, displayStack);
}
}

@Override
public void removeItem(int slot) {
this.items.remove(slot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,17 @@ public void displayFinalButton(@NotNull Button button, @NotNull Placeholders pla
int maxSlotSize = button.isPlayerInventory() ? 36 : this.inventory.size();

if (button.getPlayerHead() != null && itemStack.getItemMeta() instanceof SkullMeta) {
this.plugin.getScheduler().runAsync(w -> {
var scheduler = this.plugin.getScheduler();
scheduler.runAsync(w -> {
var updatedItemStack = this.plugin.getInventoryManager().postProcessSkullItemStack(itemStack, button, this.player, placeholders);
for (int slot : slots) {
if (slot < 0 || slot >= maxSlotSize) continue;
// Back on the player's thread, and in the inventory the button was placed in (menu or player inventory)
scheduler.runAtEntity(this.player, w2 -> {
for (int slot : slots) {
if (slot < 0 || slot >= maxSlotSize) continue;

this.getSpigotInventory().setItem(slot, updatedItemStack);
}
this.updateItem(button.isPlayerInventory(), slot, updatedItemStack, true);
}
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ public boolean addItem(BaseInventory baseInventory, boolean inPlayerInventory, I
return false;
}

public boolean updateItem(BaseInventory baseInventory, boolean inPlayerInventory, ItemButton itemButton) {
Player player = baseInventory.getPlayer();
if (baseInventory.getClearInvType() == ClearInvType.PACKET_EVENT && inPlayerInventory && player != null) {
// Still waiting for the post open flush: replace the pending packet, otherwise send it now
if (this.pendingInventoryUpdates.containsKey(player.getUniqueId())) {
this.addItemLater(player, itemButton.getSlot(), itemButton.getDisplayItem());
} else {
this.addItemInstantly(player, itemButton.getSlot(), itemButton.getDisplayItem());
}
return true;
}
return false;
}

public void onInventoryPreOpen(Player player, BaseInventory baseInventory, int page, Object... objects){
this.pendingInventoryUpdates.remove(player.getUniqueId());
}
Expand Down