mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2024-12-22 04:37:42 +01:00
Improved soulbound.can-drop
option to support moving items around in chests, dispensers...
This commit is contained in:
parent
cef7d0163a
commit
c71f673bc4
@ -192,22 +192,16 @@ public class MMOItemTemplate implements ItemReference, PreloadedObject {
|
|||||||
return options.contains(option);
|
return options.contains(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MMOItemBuilder newBuilder(@Nullable Player player) {
|
|
||||||
if (player != null) {
|
|
||||||
return newBuilder(PlayerData.get(player).getRPG());
|
|
||||||
}
|
|
||||||
return newBuilder((RPGPlayer) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MMOItemBuilder newBuilder() {
|
public MMOItemBuilder newBuilder() {
|
||||||
return newBuilder((RPGPlayer) null);
|
return newBuilder((RPGPlayer) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MMOItemBuilder newBuilder(@Nullable Player player) {
|
||||||
|
return newBuilder(player == null ? null : PlayerData.get(player).getRPG());
|
||||||
|
}
|
||||||
|
|
||||||
public MMOItemBuilder newBuilder(@Nullable PlayerData player) {
|
public MMOItemBuilder newBuilder(@Nullable PlayerData player) {
|
||||||
if (player != null) {
|
return newBuilder(player == null ? null : player.getRPG());
|
||||||
return newBuilder(player.getRPG());
|
|
||||||
}
|
|
||||||
return newBuilder((RPGPlayer) null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -233,12 +227,11 @@ public class MMOItemTemplate implements ItemReference, PreloadedObject {
|
|||||||
* @param forDisplay Should it take modifiers into account
|
* @param forDisplay Should it take modifiers into account
|
||||||
* @return Item builder with random level and tier?
|
* @return Item builder with random level and tier?
|
||||||
*/
|
*/
|
||||||
|
@NotNull
|
||||||
public MMOItemBuilder newBuilder(@Nullable RPGPlayer player, boolean forDisplay) {
|
public MMOItemBuilder newBuilder(@Nullable RPGPlayer player, boolean forDisplay) {
|
||||||
|
|
||||||
// No player ~ default settings
|
// No player ~ default settings
|
||||||
if (player == null) {
|
if (player == null) return newBuilder(0, null);
|
||||||
return newBuilder(0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read from player
|
// Read from player
|
||||||
int itemLevel = hasOption(TemplateOption.LEVEL_ITEM) ? MMOItems.plugin.getTemplates().rollLevel(player.getLevel()) : 0;
|
int itemLevel = hasOption(TemplateOption.LEVEL_ITEM) ? MMOItems.plugin.getTemplates().rollLevel(player.getLevel()) : 0;
|
||||||
@ -251,6 +244,7 @@ public class MMOItemTemplate implements ItemReference, PreloadedObject {
|
|||||||
* @param itemTier The desired item tier, can be null
|
* @param itemTier The desired item tier, can be null
|
||||||
* @return Item builder with specific item level and tier
|
* @return Item builder with specific item level and tier
|
||||||
*/
|
*/
|
||||||
|
@NotNull
|
||||||
public MMOItemBuilder newBuilder(int itemLevel, @Nullable ItemTier itemTier) {
|
public MMOItemBuilder newBuilder(int itemLevel, @Nullable ItemTier itemTier) {
|
||||||
return new MMOItemBuilder(this, itemLevel, itemTier);
|
return new MMOItemBuilder(this, itemLevel, itemTier);
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,11 @@ public class MMOUtils {
|
|||||||
return particle.getDataType() == Particle.DustOptions.class;
|
return particle.getDataType() == Particle.DustOptions.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optimized Soulbound check based on the fact that the
|
||||||
|
* compressed item Soulbound data contains only one UUID,
|
||||||
|
* the target player's UUID, sparing one Json parse pass.
|
||||||
|
*/
|
||||||
public static boolean isSoulboundTo(@NotNull NBTItem item, @NotNull Player player) {
|
public static boolean isSoulboundTo(@NotNull NBTItem item, @NotNull Player player) {
|
||||||
final @Nullable String foundNbt = item.getString("MMOITEMS_SOULBOUND");
|
final @Nullable String foundNbt = item.getString("MMOITEMS_SOULBOUND");
|
||||||
return foundNbt != null && foundNbt.contains(player.getUniqueId().toString());
|
return foundNbt != null && foundNbt.contains(player.getUniqueId().toString());
|
||||||
|
@ -6,6 +6,7 @@ import net.Indyuce.mmoitems.comp.PhatLootsHook;
|
|||||||
import net.Indyuce.mmoitems.gui.listener.GuiListener;
|
import net.Indyuce.mmoitems.gui.listener.GuiListener;
|
||||||
import net.Indyuce.mmoitems.listener.*;
|
import net.Indyuce.mmoitems.listener.*;
|
||||||
import net.Indyuce.mmoitems.listener.option.DroppedItems;
|
import net.Indyuce.mmoitems.listener.option.DroppedItems;
|
||||||
|
import net.Indyuce.mmoitems.listener.option.SoulboundNoDrop;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
public class MMOItemsBukkit {
|
public class MMOItemsBukkit {
|
||||||
@ -33,6 +34,9 @@ public class MMOItemsBukkit {
|
|||||||
if (plugin.getLanguage().disableRemovedItems)
|
if (plugin.getLanguage().disableRemovedItems)
|
||||||
Bukkit.getPluginManager().registerEvents(new DisabledItemsListener(plugin), plugin);
|
Bukkit.getPluginManager().registerEvents(new DisabledItemsListener(plugin), plugin);
|
||||||
|
|
||||||
|
if (!plugin.getConfig().getBoolean("soulbound.can-drop"))
|
||||||
|
Bukkit.getPluginManager().registerEvents(new SoulboundNoDrop(), plugin);
|
||||||
|
|
||||||
// Profile support
|
// Profile support
|
||||||
if (MythicLib.plugin.hasProfiles())
|
if (MythicLib.plugin.hasProfiles())
|
||||||
Bukkit.getPluginManager().registerEvents(new ProfileSupportListener(), plugin);
|
Bukkit.getPluginManager().registerEvents(new ProfileSupportListener(), plugin);
|
||||||
|
@ -21,7 +21,6 @@ import org.bukkit.event.inventory.CraftItemEvent;
|
|||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
import org.bukkit.event.inventory.PrepareItemCraftEvent;
|
import org.bukkit.event.inventory.PrepareItemCraftEvent;
|
||||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.inventory.CraftingInventory;
|
import org.bukkit.inventory.CraftingInventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
@ -137,13 +136,6 @@ public class ItemListener implements Listener {
|
|||||||
if (newItem != null) event.setCurrentItem(newItem);
|
if (newItem != null) event.setCurrentItem(newItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
|
||||||
private void dropItem(PlayerDropItemEvent event) {
|
|
||||||
NBTItem nbt = NBTItem.get(event.getItemDrop().getItemStack());
|
|
||||||
if (!MMOItems.plugin.getConfig().getBoolean("soulbound.can-drop") && nbt.hasTag("MMOITEMS_SOULBOUND"))
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void playerJoin(PlayerJoinEvent event) {
|
public void playerJoin(PlayerJoinEvent event) {
|
||||||
if (!MythicLib.plugin.hasProfiles()) updateInventory(event.getPlayer());
|
if (!MythicLib.plugin.hasProfiles()) updateInventory(event.getPlayer());
|
||||||
|
@ -81,11 +81,6 @@ public class PlayerListener implements Listener {
|
|||||||
final ItemStack item = iterator.next();
|
final ItemStack item = iterator.next();
|
||||||
final NBTItem nbt = NBTItem.get(item);
|
final NBTItem nbt = NBTItem.get(item);
|
||||||
|
|
||||||
/*
|
|
||||||
* Not a perfect check but it's very sufficient and so we avoid
|
|
||||||
* using a JsonParser followed by map checkups in the SoulboundData
|
|
||||||
* constructor
|
|
||||||
*/
|
|
||||||
if (nbt.getBoolean("MMOITEMS_DISABLE_DEATH_DROP") || (MMOItems.plugin.getLanguage().keepSoulboundOnDeath && MMOUtils.isSoulboundTo(nbt, player))) {
|
if (nbt.getBoolean("MMOITEMS_DISABLE_DEATH_DROP") || (MMOItems.plugin.getLanguage().keepSoulboundOnDeath && MMOUtils.isSoulboundTo(nbt, player))) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
soulboundInfo.registerItem(item);
|
soulboundInfo.registerItem(item);
|
||||||
|
@ -0,0 +1,154 @@
|
|||||||
|
package net.Indyuce.mmoitems.listener.option;
|
||||||
|
|
||||||
|
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||||
|
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
|
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useful Resources:
|
||||||
|
* - <a href="https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/event/inventory/InventoryAction.html">...</a>
|
||||||
|
* - <a href="https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/event/inventory/InventoryType.html">...</a>
|
||||||
|
*
|
||||||
|
* @author Jules
|
||||||
|
*/
|
||||||
|
public class SoulboundNoDrop implements Listener {
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||||
|
public void cannotDrop(PlayerDropItemEvent event) {
|
||||||
|
if (isBound(event.getItemDrop().getItemStack(), event.getPlayer())) event.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||||
|
public void cannotDragAround(InventoryDragEvent event) {
|
||||||
|
|
||||||
|
if (event.getView().getType() == InventoryType.CRAFTING) return;
|
||||||
|
|
||||||
|
// This easily allows to check if the item was dragged in or out of the player's inventory
|
||||||
|
final int topInventorySize = event.getView().getTopInventory().getContents().length;
|
||||||
|
for (Map.Entry<Integer, ItemStack> entry : event.getNewItems().entrySet())
|
||||||
|
if (entry.getKey() < topInventorySize && isBound(entry.getValue(), event.getWhoClicked())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||||
|
public void cannotMoveAround(InventoryClickEvent event) {
|
||||||
|
|
||||||
|
// Can only move around in
|
||||||
|
if (event.getView().getType() == InventoryType.CRAFTING) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Depends on click and inventory type.
|
||||||
|
final boolean result = isSafe(event);
|
||||||
|
if (!result) event.setCancelled(true);
|
||||||
|
} catch (RuntimeException exception) {
|
||||||
|
|
||||||
|
// Safe check...
|
||||||
|
if (isBound(event.getCurrentItem(), event.getWhoClicked()) || isBound(event.getCursor(), event.getWhoClicked()))
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSafe(@NotNull InventoryClickEvent event) {
|
||||||
|
switch (event.getAction()) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pickups
|
||||||
|
*/
|
||||||
|
case NOTHING: // 'Nothing happens' is safe enough
|
||||||
|
case PICKUP_ALL: // Can pickup any item
|
||||||
|
case PICKUP_SOME:
|
||||||
|
case PICKUP_HALF:
|
||||||
|
case PICKUP_ONE:
|
||||||
|
case COLLECT_TO_CURSOR: // Considered a pickup
|
||||||
|
case CLONE_STACK: // (Creative) Clones currentItem into cursor. Considered a pickup
|
||||||
|
case HOTBAR_MOVE_AND_READD: // Some is given to the player, but not the target inventory, hence safe!
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Drop cursor. Check cursor
|
||||||
|
*/
|
||||||
|
case DROP_ONE_CURSOR: // Check cursor (dropped)
|
||||||
|
case DROP_ALL_CURSOR:
|
||||||
|
return !isBound(event.getCursor(), event.getWhoClicked());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Drop current item. Check current item
|
||||||
|
*/
|
||||||
|
case DROP_ALL_SLOT: // Check current item (dropped)
|
||||||
|
case DROP_ONE_SLOT:
|
||||||
|
return !isBound(event.getCurrentItem(), event.getWhoClicked());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Places. Check cursor only if place is in remove inventory
|
||||||
|
*/
|
||||||
|
case SWAP_WITH_CURSOR:
|
||||||
|
case PLACE_ALL:
|
||||||
|
case PLACE_SOME:
|
||||||
|
case PLACE_ONE: {
|
||||||
|
|
||||||
|
// Can place any item in player's inventory
|
||||||
|
if (event.getClickedInventory().getType() == InventoryType.PLAYER) return true;
|
||||||
|
|
||||||
|
// Only accepted if the item is not soulbound
|
||||||
|
return !isBound(event.getCursor(), event.getWhoClicked());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Swap with hotbar. Check hotbar item only if
|
||||||
|
* swap is done with remote inventory
|
||||||
|
*/
|
||||||
|
case HOTBAR_SWAP: {
|
||||||
|
|
||||||
|
// Can place any item in player's inventory
|
||||||
|
if (event.getClickedInventory().getType() == InventoryType.PLAYER) return true;
|
||||||
|
|
||||||
|
// Check hotbar
|
||||||
|
final ItemStack hotbarItem = event.getWhoClicked().getInventory().getItem(event.getHotbarButton());
|
||||||
|
return !isBound(hotbarItem, event.getWhoClicked());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shift click item move. Check current item only if
|
||||||
|
* being placed in remove inventory
|
||||||
|
*/
|
||||||
|
case MOVE_TO_OTHER_INVENTORY: {
|
||||||
|
|
||||||
|
// Can move anything to player's inventory
|
||||||
|
if (event.getClickedInventory().getType() != InventoryType.PLAYER) return true;
|
||||||
|
|
||||||
|
// Check current item
|
||||||
|
return !isBound(event.getCurrentItem(), event.getWhoClicked());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For anything else, check both current item and cursor for safeguard.
|
||||||
|
* Maybe caused by 1.20.6+ inventory actions and other plugins.
|
||||||
|
*/
|
||||||
|
case UNKNOWN:
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBound(@Nullable ItemStack item, @NotNull HumanEntity player) {
|
||||||
|
return item != null && item.hasItemMeta() && MMOUtils.isSoulboundTo(NBTItem.get(item), (Player) player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -125,12 +125,15 @@ soulbound:
|
|||||||
base: 1
|
base: 1
|
||||||
per-lvl: 1
|
per-lvl: 1
|
||||||
|
|
||||||
# Whether or not soulbound items should be
|
# Whether soulbound items should be
|
||||||
# kept when a player dies.
|
# kept when a player dies.
|
||||||
keep-on-death: true
|
keep-on-death: true
|
||||||
|
|
||||||
# Whether or not soulbound item can be
|
# [Experimental feature]
|
||||||
# dropped by the player
|
# When toggled off, players cannot drop or take
|
||||||
|
# Soulbound items away from their inventory.
|
||||||
|
# Requires `keep-on-death` enabled.
|
||||||
|
# Changes apply on server restart.
|
||||||
can-drop: true
|
can-drop: true
|
||||||
|
|
||||||
# Enable, disable, and customize the weapon effects here.
|
# Enable, disable, and customize the weapon effects here.
|
||||||
|
Loading…
Reference in New Issue
Block a user