mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2024-12-22 04:37:42 +01:00
Fixed soulbound when disabling 'keep-soulbound-on-death'
This commit is contained in:
parent
ebe041d8d5
commit
d1f2af29c3
@ -5,7 +5,7 @@ import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackMessage;
|
|||||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
|
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
|
||||||
import io.lumine.mythic.lib.version.SpigotPlugin;
|
import io.lumine.mythic.lib.version.SpigotPlugin;
|
||||||
import net.Indyuce.mmoitems.api.ItemTier;
|
import net.Indyuce.mmoitems.api.ItemTier;
|
||||||
import net.Indyuce.mmoitems.api.SoulboundInfo;
|
import net.Indyuce.mmoitems.api.DeathItemsHandler;
|
||||||
import net.Indyuce.mmoitems.api.Type;
|
import net.Indyuce.mmoitems.api.Type;
|
||||||
import net.Indyuce.mmoitems.api.crafting.MMOItemUIFilter;
|
import net.Indyuce.mmoitems.api.crafting.MMOItemUIFilter;
|
||||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||||
@ -263,8 +263,8 @@ public class MMOItems extends JavaPlugin {
|
|||||||
// Save player data
|
// Save player data
|
||||||
PlayerData.getLoaded().forEach(data -> data.save(false));
|
PlayerData.getLoaded().forEach(data -> data.save(false));
|
||||||
|
|
||||||
// Drop abandonned soulbound items
|
// Drop abandoned items
|
||||||
SoulboundInfo.getAbandonnedInfo().forEach(SoulboundInfo::dropItems);
|
DeathItemsHandler.getActive().forEach(info -> info.giveItems(true));
|
||||||
|
|
||||||
// Close inventories
|
// Close inventories
|
||||||
for (Player player : Bukkit.getOnlinePlayers())
|
for (Player player : Bukkit.getOnlinePlayers())
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
package net.Indyuce.mmoitems.api;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import net.Indyuce.mmoitems.MMOItems;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class DeathItemsHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Items that need to be given to the player whenever he respawns.
|
||||||
|
*/
|
||||||
|
private final List<ItemStack> items = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the player leaves the server before removing, the cached items will be
|
||||||
|
* lost. the plugin saves the last location of the player to drop the items
|
||||||
|
* when the server shuts down this way they are 'saved'
|
||||||
|
*/
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to store which items must be given back to which player
|
||||||
|
*/
|
||||||
|
private static final Map<UUID, DeathItemsHandler> INFO = new WeakHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instanced when a player dies if some Soulbound items must be kept in the
|
||||||
|
* player's inventory and need to be cached before the player respawns.
|
||||||
|
* <p>
|
||||||
|
* If the player leaves the server leaving one object of this type in server
|
||||||
|
* RAM, the cached items need to be dropped if the server closes before the
|
||||||
|
* player respawns again.
|
||||||
|
*/
|
||||||
|
public DeathItemsHandler(@NotNull Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerItem(@NotNull ItemStack item) {
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerIfNecessary() {
|
||||||
|
if (!items.isEmpty()) INFO.put(player.getUniqueId(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param forceDrop Should the items all drop on the ground
|
||||||
|
*/
|
||||||
|
public void giveItems(boolean forceDrop) {
|
||||||
|
|
||||||
|
// Drop all items on the ground
|
||||||
|
if (forceDrop) for (ItemStack drop : items)
|
||||||
|
player.getWorld().dropItem(player.getLocation(), drop);
|
||||||
|
|
||||||
|
// First try to add them to inventory
|
||||||
|
else {
|
||||||
|
final ItemStack[] toArray = this.items.toArray(new ItemStack[0]);
|
||||||
|
for (ItemStack drop : player.getInventory().addItem(toArray).values())
|
||||||
|
player.getWorld().dropItem(player.getLocation(), drop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to add the items to the player's inventory, or drops them
|
||||||
|
* on the ground if the player's inventory is full. In the meantime,
|
||||||
|
* the player's item info is removed from the map.
|
||||||
|
*
|
||||||
|
* @param player Target player respawning
|
||||||
|
*/
|
||||||
|
public static void readAndRemove(@NotNull Player player) {
|
||||||
|
final @Nullable DeathItemsHandler handler = INFO.remove(player.getUniqueId());
|
||||||
|
if (handler != null) Bukkit.getScheduler().runTaskLater(MMOItems.plugin, () -> handler.giveItems(false), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Soulbound info of players who have not clicked the respawn button
|
||||||
|
* and yet have items cached in server RAM
|
||||||
|
*/
|
||||||
|
public static Collection<DeathItemsHandler> getActive() {
|
||||||
|
return INFO.values();
|
||||||
|
}
|
||||||
|
}
|
@ -1,83 +0,0 @@
|
|||||||
package net.Indyuce.mmoitems.api;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
public class SoulboundInfo {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Items that need to be given to the player whenever he respawns.
|
|
||||||
*/
|
|
||||||
private final List<ItemStack> items = new ArrayList<>();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the player leaves the server before removing, the cached items will be
|
|
||||||
* lost. the plugin saves the last location of the player to drop the items
|
|
||||||
* when the server shuts down this way they are 'saved'
|
|
||||||
*/
|
|
||||||
private final Location loc;
|
|
||||||
private final Player player;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to store which items must be given back to which player
|
|
||||||
*/
|
|
||||||
private static final Map<UUID, SoulboundInfo> INFO = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instanced when a player dies if some souljbound items must be kept in the
|
|
||||||
* player's inventory and need to be cached before the player respawns.
|
|
||||||
*
|
|
||||||
* If the player leaves the server leaving one object of this type in server
|
|
||||||
* RAM, the cached items need to be dropped if the server closes before the
|
|
||||||
* player respawns again
|
|
||||||
*/
|
|
||||||
public SoulboundInfo(Player player) {
|
|
||||||
this.player = player;
|
|
||||||
loc = player.getLocation().clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(ItemStack item) {
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasItems() {
|
|
||||||
return !items.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setup() {
|
|
||||||
INFO.put(player.getUniqueId(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void giveItems() {
|
|
||||||
for (ItemStack item : items)
|
|
||||||
for (ItemStack drop : player.getInventory().addItem(item).values())
|
|
||||||
player.getWorld().dropItem(player.getLocation(), drop);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dropItems() {
|
|
||||||
items.forEach(item -> loc.getWorld().dropItem(loc, item));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void read(Player player) {
|
|
||||||
if (INFO.containsKey(player.getUniqueId())) {
|
|
||||||
INFO.get(player.getUniqueId()).giveItems();
|
|
||||||
INFO.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Soulbound info of players who have not clicked the respawn button
|
|
||||||
* and yet have items cached in server RAM
|
|
||||||
*/
|
|
||||||
public static Collection<SoulboundInfo> getAbandonnedInfo() {
|
|
||||||
return INFO.values();
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ import io.lumine.mythic.lib.api.event.armorequip.ArmorEquipEvent;
|
|||||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||||
import net.Indyuce.mmoitems.MMOItems;
|
import net.Indyuce.mmoitems.MMOItems;
|
||||||
import net.Indyuce.mmoitems.api.SoulboundInfo;
|
import net.Indyuce.mmoitems.api.DeathItemsHandler;
|
||||||
import net.Indyuce.mmoitems.api.Type;
|
import net.Indyuce.mmoitems.api.Type;
|
||||||
import net.Indyuce.mmoitems.api.interaction.util.InteractItem;
|
import net.Indyuce.mmoitems.api.interaction.util.InteractItem;
|
||||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||||
@ -28,12 +28,12 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class PlayerListener implements Listener {
|
public class PlayerListener implements Listener {
|
||||||
private final Map<Player, List<ItemStack>> deathItems = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Careful, MMOCore and MMOMana runs on LOWEST
|
* MythicLib runs of LOWEST
|
||||||
|
* MMOCore and MMOInventory runs on LOW
|
||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.LOW)
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
public void loadPlayerData(PlayerJoinEvent event) {
|
public void loadPlayerData(PlayerJoinEvent event) {
|
||||||
MMOItems.plugin.getRecipes().refreshRecipeBook(event.getPlayer());
|
MMOItems.plugin.getRecipes().refreshRecipeBook(event.getPlayer());
|
||||||
PlayerData.load(event.getPlayer());
|
PlayerData.load(event.getPlayer());
|
||||||
@ -60,59 +60,40 @@ public class PlayerListener implements Listener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent players from dropping items which are bound to them with a
|
* Prevent players from dropping items which are bound to them with a
|
||||||
* soulbound. Items are cached inside a map waiting for the player to
|
* Soulbound. Items are cached inside a map waiting for the player to
|
||||||
* respawn. If he does not respawn the items are dropped on the ground, this
|
* respawn. If he does not respawn the items are dropped on the ground, this
|
||||||
* way there don't get lost
|
* way there don't get lost
|
||||||
*/
|
*/
|
||||||
@EventHandler(priority = EventPriority.HIGH)
|
@EventHandler(priority = EventPriority.HIGH)
|
||||||
public void onDeathForSoulbound(PlayerDeathEvent event) {
|
public void keepItemsOnDeath(PlayerDeathEvent event) {
|
||||||
if (event.getKeepInventory() || !MMOItems.plugin.getLanguage().keepSoulboundOnDeath)
|
if (event.getKeepInventory()) return;
|
||||||
return;
|
|
||||||
|
|
||||||
Player player = event.getEntity();
|
final Player player = event.getEntity();
|
||||||
SoulboundInfo soulboundInfo = new SoulboundInfo(player);
|
final DeathItemsHandler soulboundInfo = new DeathItemsHandler(player);
|
||||||
|
|
||||||
Iterator<ItemStack> iterator = event.getDrops().iterator();
|
final Iterator<ItemStack> iterator = event.getDrops().iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
ItemStack item = iterator.next();
|
final ItemStack item = iterator.next();
|
||||||
NBTItem nbt = NBTItem.get(item);
|
final NBTItem nbt = NBTItem.get(item);
|
||||||
|
|
||||||
if (nbt.hasTag("MMOITEMS_DISABLE_DEATH_DROP") && nbt.getBoolean("MMOITEMS_DISABLE_DEATH_DROP")) {
|
|
||||||
iterator.remove();
|
|
||||||
if (!deathItems.containsKey(player))
|
|
||||||
deathItems.put(player, new ArrayList<>());
|
|
||||||
|
|
||||||
deathItems.get(player).add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* not a perfect check but it's very sufficient and so we avoid
|
* Not a perfect check but it's very sufficient and so we avoid
|
||||||
* using a JsonParser followed by map checkups in the SoulboundData
|
* using a JsonParser followed by map checkups in the SoulboundData
|
||||||
* constructor
|
* constructor
|
||||||
*/
|
*/
|
||||||
else if (nbt.hasTag("MMOITEMS_SOULBOUND") && nbt.getString("MMOITEMS_SOULBOUND").contains(player.getUniqueId().toString())) {
|
if ((MMOItems.plugin.getLanguage().keepSoulboundOnDeath && nbt.getBoolean("MMOITEMS_DISABLE_DEATH_DROP"))
|
||||||
|
|| (nbt.hasTag("MMOITEMS_SOULBOUND") && nbt.getString("MMOITEMS_SOULBOUND").contains(player.getUniqueId().toString()))) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
soulboundInfo.add(item);
|
soulboundInfo.registerItem(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (soulboundInfo.hasItems())
|
soulboundInfo.registerIfNecessary();
|
||||||
soulboundInfo.setup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onRespawn(PlayerRespawnEvent event) {
|
public void onRespawn(PlayerRespawnEvent event) {
|
||||||
Player player = event.getPlayer();
|
DeathItemsHandler.readAndRemove(event.getPlayer());
|
||||||
|
|
||||||
if (MMOItems.plugin.getLanguage().keepSoulboundOnDeath)
|
|
||||||
SoulboundInfo.read(player);
|
|
||||||
|
|
||||||
if (deathItems.containsKey(player)) {
|
|
||||||
Bukkit.getScheduler().runTaskLater(MMOItems.plugin, () -> {
|
|
||||||
player.getInventory().addItem(deathItems.get(player).toArray(new ItemStack[0]));
|
|
||||||
deathItems.remove(player);
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@ -161,7 +142,7 @@ public class PlayerListener implements Listener {
|
|||||||
* player cast abilities or attacks with not the correct stats
|
* player cast abilities or attacks with not the correct stats
|
||||||
*
|
*
|
||||||
* @deprecated This does cost some performance and that update
|
* @deprecated This does cost some performance and that update
|
||||||
* method NEEDS some improvement in the future
|
* method NEEDS some improvement in the future
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@ -175,7 +156,7 @@ public class PlayerListener implements Listener {
|
|||||||
* player cast abilities or attacks with not the correct stats
|
* player cast abilities or attacks with not the correct stats
|
||||||
*
|
*
|
||||||
* @deprecated This does cost some performance and that update
|
* @deprecated This does cost some performance and that update
|
||||||
* method NEEDS some improvement in the future
|
* method NEEDS some improvement in the future
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@EventHandler
|
@EventHandler
|
||||||
|
Loading…
Reference in New Issue
Block a user