From 1a1346d3bc8864d420f23acd4e257890c4c2ee42 Mon Sep 17 00:00:00 2001 From: Jules Date: Mon, 19 Feb 2024 12:52:44 +0100 Subject: [PATCH] Fixed NPE with guild gui --- .../mmocore/api/util/MMOCoreUtils.java | 21 +- .../net/Indyuce/mmocore/gui/PlayerStats.java | 50 +-- .../mmocore/gui/api/GeneratedInventory.java | 16 +- .../mmocore/gui/api/adaptor/Adaptor.java | 26 +- .../gui/api/adaptor/ClassicAdaptor.java | 12 +- .../gui/api/adaptor/ThreeDimAdaptor.java | 10 +- .../gui/api/item/ErrorPlaceholders.java | 12 + .../mmocore/gui/api/item/Placeholders.java | 18 +- .../gui/social/friend/EditableFriendList.java | 13 +- .../gui/social/guild/EditableGuildAdmin.java | 2 +- .../gui/social/guild/EditableGuildView.java | 375 +++++++++--------- .../gui/social/party/EditablePartyView.java | 4 +- 12 files changed, 312 insertions(+), 247 deletions(-) create mode 100644 MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/item/ErrorPlaceholders.java diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/util/MMOCoreUtils.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/util/MMOCoreUtils.java index 752ddea1..e809d480 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/util/MMOCoreUtils.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/util/MMOCoreUtils.java @@ -6,10 +6,7 @@ import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.hologram.Hologram; import io.lumine.mythic.lib.version.VersionMaterial; import net.Indyuce.mmocore.MMOCore; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Sound; +import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; @@ -34,6 +31,20 @@ public class MMOCoreUtils { return item != null && item.hasItemMeta() && item.getItemMeta().hasDisplayName(); } + /** + * If a given player is not in the server cache, no information + * cannot be retrieved from that player (without using requests + * to MC servers obviously). In that case, the instance of + * OfflinePlayer is pretty much useless and it only wraps its + * UUID which was already known beforehand. + * + * @param player Offline player instance to test + * @return Is the instance valid + */ + public static boolean isInvalid(OfflinePlayer player) { + return player.getName() == null; + } + public static String displayName(ItemStack item) { return item.hasItemMeta() && item.getItemMeta().hasDisplayName() ? item.getItemMeta().getDisplayName() : caseOnWords(item.getType().name().replace("_", " ")); @@ -43,7 +54,7 @@ public class MMOCoreUtils { * @param current Current value of resource * @param maxStat Maximum value of resource * @return Clamped resource value. If the provided current value is 0, - * this function will return the maximum resource value. + * this function will return the maximum resource value. */ public static double fixResource(double current, double maxStat) { return current == 0 ? maxStat : Math.max(0, Math.min(current, maxStat)); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java index 6729450e..b383ff4e 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java @@ -22,10 +22,10 @@ import net.Indyuce.mmocore.party.AbstractParty; import net.Indyuce.mmocore.player.stats.StatInfo; import org.apache.commons.lang.Validate; import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -123,36 +123,26 @@ public class PlayerStats extends EditableInventory { return new Placeholders() { final net.Indyuce.mmocore.api.player.stats.PlayerStats stats = inv.target.getStats(); + @Nullable @Override - public String apply(OfflinePlayer player, String str) { - String explored = str; - // Internal placeholders - while (explored.contains("{") && explored.substring(explored.indexOf("{")).contains("}")) { - final int begin = explored.indexOf("{"), end = explored.indexOf("}"); - final String holder = explored.substring(begin + 1, end); - String replaced; - if (holder.endsWith("_base")) { - final String stat = UtilityMethods.enumName(holder.substring(0, holder.length() - 5)); - replaced = StatManager.format(stat, stats.getBase(stat)); - } else if (holder.endsWith("_extra")) { - final String stat = UtilityMethods.enumName(holder.substring(0, holder.length() - 6)); - replaced = StatManager.format(stat, MythicLib.plugin.getStats().getTotalValue(stat, stats.getMap()) - stats.getBase(stat)); - } else if (holder.startsWith("attribute_")) { - final PlayerAttribute attr = MMOCore.plugin.attributeManager.get(holder.substring(10).replace("_", "-").toLowerCase()); - replaced = String.valueOf(inv.target.getAttributes().getAttribute(attr)); - } else { - final String stat = UtilityMethods.enumName(holder); - replaced = StatManager.format(stat, MythicLib.plugin.getStats().getTotalValue(stat, stats.getMap())); - } - - str = str.replace("{" + holder + "}", replaced); - - // Increase counter - explored = explored.substring(end + 1); + public String getPlaceholder(String holder) { + if (holder.endsWith("_base")) { + final String stat = UtilityMethods.enumName(holder.substring(0, holder.length() - 5)); + return StatManager.format(stat, stats.getBase(stat)); } - // External placeholders - return MMOCore.plugin.placeholderParser.parse(player, str); + if (holder.endsWith("_extra")) { + final String stat = UtilityMethods.enumName(holder.substring(0, holder.length() - 6)); + return StatManager.format(stat, MythicLib.plugin.getStats().getTotalValue(stat, stats.getMap()) - stats.getBase(stat)); + } + + if (holder.startsWith("attribute_")) { + final PlayerAttribute attr = MMOCore.plugin.attributeManager.get(holder.substring(10).replace("_", "-").toLowerCase()); + return String.valueOf(inv.target.getAttributes().getAttribute(attr)); + } + + final String stat = UtilityMethods.enumName(holder); + return StatManager.format(stat, MythicLib.plugin.getStats().getTotalValue(stat, stats.getMap())); } }; } @@ -219,7 +209,7 @@ public class PlayerStats extends EditableInventory { Placeholders holders = new Placeholders(); int count = inv.target.getParty().getOnlineMembers().size(); - holders.register("count", "" + count); + holders.register("count", String.valueOf(count)); for (StatModifier buff : MMOCore.plugin.partyManager.getBonuses()) holders.register("buff_" + buff.getStat().toLowerCase(), buff.multiply(count - 1).toString()); @@ -243,7 +233,7 @@ public class PlayerStats extends EditableInventory { ItemStack disp = super.display(inv, n); if (disp.getType() == VersionMaterial.PLAYER_HEAD.toMaterial()) { SkullMeta meta = (SkullMeta) disp.getItemMeta(); - inv.dynamicallyUpdateItem(this, n, disp, current -> { + inv.asyncUpdate(this, n, disp, current -> { meta.setOwningPlayer(inv.target.getPlayer()); current.setItemMeta(meta); }); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java index daf76dd1..934d96ff 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java @@ -13,6 +13,8 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; import java.util.function.Consumer; public abstract class GeneratedInventory extends PluginInventory { @@ -32,7 +34,6 @@ public abstract class GeneratedInventory extends PluginInventory { } public EditableInventory getEditable() { - return editable; } @@ -78,13 +79,12 @@ public abstract class GeneratedInventory extends PluginInventory { adaptor.open(); } - /** - * @deprecated Not a fan of that implementation. - * Better work with {@link InventoryItem#setDisplayed(Inventory, GeneratedInventory)} - */ - @Deprecated - public void dynamicallyUpdateItem(InventoryItem item, int n, ItemStack placed, Consumer update) { - adaptor.dynamicallyUpdateItem(item, n, placed, update); + public void asyncUpdate(InventoryItem item, int n, ItemStack placed, Consumer update) { + adaptor.asyncUpdate(item, n, placed, update); + } + + public void asyncUpdate(CompletableFuture future, InventoryItem item, int n, ItemStack placed, BiConsumer update) { + adaptor.asyncUpdate(future, item, n, placed, update); } @Override diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/Adaptor.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/Adaptor.java index 60f0f291..f8ba8441 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/Adaptor.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/Adaptor.java @@ -4,6 +4,8 @@ import net.Indyuce.mmocore.gui.api.GeneratedInventory; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import org.bukkit.inventory.ItemStack; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; import java.util.function.Consumer; public abstract class Adaptor { @@ -17,6 +19,26 @@ public abstract class Adaptor { public abstract void close(); - @Deprecated - public abstract void dynamicallyUpdateItem(InventoryItem item, int n, ItemStack placed, Consumer update); + /** + * Applies a modification to an item in a new asynchronous thread. + * This is mostly used to apply owners to skulls as this creates a + * request to the Minecraft servers to get the player head. + * + * @param item Inventory item + * @param n Inventory item index + * @param placed Item already generated + * @param update What to do with the item + */ + public abstract void asyncUpdate(InventoryItem item, int n, ItemStack placed, Consumer update); + + /** + * Applies a modification after the given future is complete. + * + * @param future Future being completed + * @param item Inventory item + * @param n Inventory item index + * @param placed Item already generated + * @param update What to do with the item + */ + public abstract void asyncUpdate(CompletableFuture future, InventoryItem item, int n, ItemStack placed, BiConsumer update); } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ClassicAdaptor.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ClassicAdaptor.java index 8631c909..7acdfa89 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ClassicAdaptor.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ClassicAdaptor.java @@ -9,6 +9,8 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; import java.util.function.Consumer; public class ClassicAdaptor extends Adaptor { @@ -29,13 +31,21 @@ public class ClassicAdaptor extends Adaptor { } @Override - public void dynamicallyUpdateItem(InventoryItem item, int n, ItemStack placed, Consumer update) { + public void asyncUpdate(InventoryItem item, int n, ItemStack placed, Consumer update) { Bukkit.getScheduler().runTaskAsynchronously(MMOCore.plugin, () -> { update.accept(placed); open.setItem(item.getSlots().get(n), placed); }); } + @Override + public void asyncUpdate(CompletableFuture future, InventoryItem item, int n, ItemStack placed, BiConsumer update) { + future.thenAccept(t -> { + update.accept(t, placed); + open.setItem(item.getSlots().get(n), placed); + }); + } + public Inventory getInventory() { Inventory inv = Bukkit.createInventory(generated, generated.getEditable().getSlots(), MythicLib.plugin.getPlaceholderParser().parse(generated.getPlayer(), generated.calculateName())); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ThreeDimAdaptor.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ThreeDimAdaptor.java index 0c713c51..08067c71 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ThreeDimAdaptor.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ThreeDimAdaptor.java @@ -10,7 +10,6 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.gui.api.GeneratedInventory; import net.Indyuce.mmocore.gui.api.InventoryClickContext; import net.Indyuce.mmocore.gui.api.item.InventoryItem; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.entity.ArmorStand; @@ -34,6 +33,8 @@ import org.bukkit.util.Vector; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; import java.util.function.Consumer; public class ThreeDimAdaptor extends Adaptor { @@ -346,8 +347,13 @@ public class ThreeDimAdaptor extends Adaptor { } @Override - public void dynamicallyUpdateItem(InventoryItem item, int n, ItemStack placed, Consumer update) { + public void asyncUpdate(InventoryItem item, int n, ItemStack placed, Consumer update) { + // Not implemented + } + @Override + public void asyncUpdate(CompletableFuture future, InventoryItem item, int n, ItemStack placed, BiConsumer update) { + // Not implemented } private class SpawnPacketListener extends PacketAdapter { diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/item/ErrorPlaceholders.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/item/ErrorPlaceholders.java new file mode 100644 index 00000000..5b490a0c --- /dev/null +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/item/ErrorPlaceholders.java @@ -0,0 +1,12 @@ +package net.Indyuce.mmocore.gui.api.item; + +import org.jetbrains.annotations.Nullable; + +public class ErrorPlaceholders extends Placeholders { + + @Nullable + @Override + public String getPlaceholder(String placeholder) { + return "???"; + } +} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/item/Placeholders.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/item/Placeholders.java index 17156567..95e3db23 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/item/Placeholders.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/api/item/Placeholders.java @@ -2,6 +2,7 @@ package net.Indyuce.mmocore.gui.api.item; import net.Indyuce.mmocore.MMOCore; import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -10,11 +11,17 @@ import java.util.Map; public class Placeholders { private final Map placeholders = new HashMap<>(); - public void register(String path, Object obj) { - placeholders.put(path, obj.toString()); + public void register(@Nullable String path, @Nullable Object obj) { + placeholders.put(path, String.valueOf(obj)); } - public String apply(OfflinePlayer player, String str) { + @Nullable + public String getPlaceholder(String placeholder) { + return placeholders.get(placeholder); + } + + @NotNull + public String apply(@NotNull OfflinePlayer player, @NotNull String str) { // Remove conditions first str = removeCondition(str); @@ -30,7 +37,7 @@ public class Placeholders { while (explored.contains("{") && explored.substring(explored.indexOf("{")).contains("}")) { final int begin = explored.indexOf("{"), end = explored.indexOf("}"); final String holder = explored.substring(begin + 1, end); - @Nullable String found = placeholders.get(holder); + @Nullable String found = getPlaceholder(holder); /* * Do NOT replace the placeholder unless a corresponding value has @@ -38,8 +45,7 @@ public class Placeholders { * math expansions which interferes with MMOCore placeholders since * it uses {....} as well. */ - if (found != null) - str = str.replace("{" + holder + "}", found); + if (found != null) str = str.replace("{" + holder + "}", found); // Increase counter explored = explored.substring(end + 1); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendList.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendList.java index 9e7b3149..67886b05 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendList.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendList.java @@ -4,12 +4,14 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.player.PlayerActivity; import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.input.ChatInput; import net.Indyuce.mmocore.api.util.input.PlayerInput.InputType; import net.Indyuce.mmocore.api.util.math.format.DelayFormat; import net.Indyuce.mmocore.gui.api.EditableInventory; import net.Indyuce.mmocore.gui.api.GeneratedInventory; import net.Indyuce.mmocore.gui.api.InventoryClickContext; +import net.Indyuce.mmocore.gui.api.item.ErrorPlaceholders; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; @@ -68,7 +70,7 @@ public class EditableFriendList extends EditableInventory { return new FriendListInventory(data, this); } - public static class OfflineFriendItem extends InventoryItem { + class OfflineFriendItem extends InventoryItem { public OfflineFriendItem(FriendItem parent, ConfigurationSection config) { super(parent, config); } @@ -87,6 +89,7 @@ public class EditableFriendList extends EditableInventory { @Override public Placeholders getPlaceholders(GeneratedInventory inv, int n) { OfflinePlayer friend = getEffectivePlayer(inv, n); + if (MMOCoreUtils.isInvalid(friend)) return new ErrorPlaceholders(); Placeholders holders = new Placeholders(); holders.register("name", friend.getName()); @@ -95,7 +98,7 @@ public class EditableFriendList extends EditableInventory { } } - public static class OnlineFriendItem extends SimplePlaceholderItem { + class OnlineFriendItem extends SimplePlaceholderItem { public OnlineFriendItem(FriendItem parent, ConfigurationSection config) { super(parent, config); } @@ -126,7 +129,7 @@ public class EditableFriendList extends EditableInventory { } } - public static class FriendItem extends SimplePlaceholderItem { + class FriendItem extends SimplePlaceholderItem { private final OnlineFriendItem online; private final OfflineFriendItem offline; @@ -150,7 +153,7 @@ public class EditableFriendList extends EditableInventory { ItemMeta meta = disp.getItemMeta(); meta.getPersistentDataContainer().set(UUID_NAMESPACEDKEY, PersistentDataType.STRING, friend.getUniqueId().toString()); if (meta instanceof SkullMeta) - inv.dynamicallyUpdateItem(this, n, disp, current -> { + inv.asyncUpdate(this, n, disp, current -> { ((SkullMeta) meta).setOwningPlayer(friend); current.setItemMeta(meta); }); @@ -170,7 +173,7 @@ public class EditableFriendList extends EditableInventory { } } - public class FriendListInventory extends GeneratedInventory { + class FriendListInventory extends GeneratedInventory { private int page; public FriendListInventory(PlayerData playerData, EditableInventory editable) { diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildAdmin.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildAdmin.java index 2b886701..3c8a9b3c 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildAdmin.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildAdmin.java @@ -78,7 +78,7 @@ public class EditableGuildAdmin extends EditableInventory { meta.getPersistentDataContainer().set(UUID_NAMESPACEDKEY, PersistentDataType.STRING, uuid.toString()); if (meta instanceof SkullMeta && offlinePlayer != null) - inv.dynamicallyUpdateItem(this, n, disp, current -> { + inv.asyncUpdate(this, n, disp, current -> { ((SkullMeta) meta).setOwningPlayer(offlinePlayer); current.setItemMeta(meta); }); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildView.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildView.java index 89cb3abf..7e4d22e6 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildView.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildView.java @@ -3,12 +3,14 @@ package net.Indyuce.mmocore.gui.social.guild; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.input.ChatInput; import net.Indyuce.mmocore.api.util.input.PlayerInput; import net.Indyuce.mmocore.api.util.math.format.DelayFormat; import net.Indyuce.mmocore.gui.api.EditableInventory; import net.Indyuce.mmocore.gui.api.GeneratedInventory; import net.Indyuce.mmocore.gui.api.InventoryClickContext; +import net.Indyuce.mmocore.gui.api.item.ErrorPlaceholders; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; @@ -22,237 +24,240 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.UUID; public class EditableGuildView extends EditableInventory { - private static final NamespacedKey UUID_NAMESPACEDKEY = new NamespacedKey(MMOCore.plugin, "Uuid"); + private static final NamespacedKey UUID_NAMESPACEDKEY = new NamespacedKey(MMOCore.plugin, "Uuid"); - public EditableGuildView() { - super("guild-view"); - } + public EditableGuildView() { + super("guild-view"); + } - @Override - public InventoryItem load(String function, ConfigurationSection config) { - return function.equals("member") ? new MemberItem(config) : (function.equals("next") || function.equals("previous") || function.equals("disband") || function.equals("invite")) ? new ConditionalItem(function, config) : new SimplePlaceholderItem(config); - } + @Override + public InventoryItem load(String function, ConfigurationSection config) { + return function.equals("member") ? new MemberItem(config) : (function.equals("next") || function.equals("previous") || function.equals("disband") || function.equals("invite")) ? new ConditionalItem(function, config) : new SimplePlaceholderItem(config); + } - public static class MemberDisplayItem extends InventoryItem { - public MemberDisplayItem(MemberItem memberItem, ConfigurationSection config) { - super(memberItem, config); - } + public static class MemberDisplayItem extends InventoryItem { + public MemberDisplayItem(MemberItem memberItem, ConfigurationSection config) { + super(memberItem, config); + } - @Override - public boolean hasDifferentDisplay() { - return true; - } + @Override + public boolean hasDifferentDisplay() { + return true; + } - @Override - public Placeholders getPlaceholders(GuildViewInventory inv, int n) { - UUID uuid = inv.members.get(n); - Placeholders holders = new Placeholders(); - /* - * Will never be null since a players name will always be recorded - * if they've been in a guild - */ - holders.register("name", Bukkit.getOfflinePlayer(uuid).getName()); + @NotNull + @Override + public OfflinePlayer getEffectivePlayer(GuildViewInventory inv, int n) { + return Bukkit.getOfflinePlayer(inv.members.get(n)); + } - OfflinePlayerData offline = OfflinePlayerData.get(uuid); - holders.register("class", offline.getProfess().getName()); - holders.register("level", offline.getLevel()); - holders.register("since", new DelayFormat(2).format(System.currentTimeMillis() - offline.getLastLogin())); + @Override + public Placeholders getPlaceholders(GuildViewInventory inv, int n) { + UUID uuid = inv.members.get(n); + OfflinePlayer player = getEffectivePlayer(inv, n); - return holders; - } + Placeholders holders = new Placeholders(); + OfflinePlayerData offline = OfflinePlayerData.get(uuid); + holders.register("name", MMOCoreUtils.isInvalid(player) ? "???" : player.getName()); + holders.register("class", offline.getProfess().getName()); + holders.register("level", offline.getLevel()); + holders.register("since", new DelayFormat(2).format(System.currentTimeMillis() - offline.getLastLogin())); + return holders; + } - @Override - public ItemStack display(GuildViewInventory inv, int n) { - UUID uuid = inv.members.get(n); + @Override + public ItemStack display(GuildViewInventory inv, int n) { + UUID uuid = inv.members.get(n); - ItemStack disp = super.display(inv, n); - ItemMeta meta = disp.getItemMeta(); - meta.getPersistentDataContainer().set(UUID_NAMESPACEDKEY, PersistentDataType.STRING, uuid.toString()); + ItemStack disp = super.display(inv, n); + ItemMeta meta = disp.getItemMeta(); + meta.getPersistentDataContainer().set(UUID_NAMESPACEDKEY, PersistentDataType.STRING, uuid.toString()); - if (meta instanceof SkullMeta) - inv.dynamicallyUpdateItem(this, n, disp, current -> { - ((SkullMeta) meta).setOwningPlayer(Bukkit.getOfflinePlayer(uuid)); - current.setItemMeta(meta); - }); + if (meta instanceof SkullMeta) + inv.asyncUpdate(this, n, disp, current -> { + ((SkullMeta) meta).setOwningPlayer(Bukkit.getOfflinePlayer(uuid)); + current.setItemMeta(meta); + }); - disp.setItemMeta(meta); - return disp; - } - } + disp.setItemMeta(meta); + return disp; + } + } - public class MemberItem extends SimplePlaceholderItem { - private final InventoryItem empty; - private final MemberDisplayItem member; + public class MemberItem extends SimplePlaceholderItem { + private final InventoryItem empty; + private final MemberDisplayItem member; - public MemberItem(ConfigurationSection config) { - super(Material.BARRIER, config); + public MemberItem(ConfigurationSection config) { + super(Material.BARRIER, config); - Validate.notNull(config.contains("empty"), "Could not load empty config"); - Validate.notNull(config.contains("member"), "Could not load member config"); + Validate.notNull(config.contains("empty"), "Could not load empty config"); + Validate.notNull(config.contains("member"), "Could not load member config"); - empty = new SimplePlaceholderItem(config.getConfigurationSection("empty")); - member = new MemberDisplayItem(this, config.getConfigurationSection("member")); - } + empty = new SimplePlaceholderItem(config.getConfigurationSection("empty")); + member = new MemberDisplayItem(this, config.getConfigurationSection("member")); + } - @Override - public ItemStack display(GuildViewInventory inv, int n) { - int index = n * inv.getPage(); - return inv.getPlayerData().getGuild().countMembers() > index ? member.display(inv, index) : empty.display(inv, index); - } + @Override + public ItemStack display(GuildViewInventory inv, int n) { + int index = n * inv.getPage(); + return inv.getPlayerData().getGuild().countMembers() > index ? member.display(inv, index) : empty.display(inv, index); + } - @Override - public boolean hasDifferentDisplay() { - return true; - } - } + @Override + public boolean hasDifferentDisplay() { + return true; + } + } - public class ConditionalItem extends SimplePlaceholderItem { - private final String function; + public class ConditionalItem extends SimplePlaceholderItem { + private final String function; - public ConditionalItem(String func, ConfigurationSection config) { - super(config); - this.function = func; - } + public ConditionalItem(String func, ConfigurationSection config) { + super(config); + this.function = func; + } - @Override - public ItemStack display(GuildViewInventory inv, int n) { + @Override + public ItemStack display(GuildViewInventory inv, int n) { - if (function.equals("next")) - if (inv.getPage() == (inv.getPlayerData().getGuild().countMembers() + 20) - / inv.getByFunction("member").getSlots().size()) - return null; - if (function.equals("previous") && inv.getPage() == 1) - return null; - if ((function.equals("disband") || function.equals("invite")) && !inv.getPlayerData().getGuild().getOwner().equals(inv.getPlayer().getUniqueId())) - return null; - return super.display(inv, n); - } - } + if (function.equals("next")) + if (inv.getPage() == (inv.getPlayerData().getGuild().countMembers() + 20) + / inv.getByFunction("member").getSlots().size()) + return null; + if (function.equals("previous") && inv.getPage() == 1) + return null; + if ((function.equals("disband") || function.equals("invite")) && !inv.getPlayerData().getGuild().getOwner().equals(inv.getPlayer().getUniqueId())) + return null; + return super.display(inv, n); + } + } - public GeneratedInventory newInventory(PlayerData data) { - return new GuildViewInventory(data, this); - } + public GeneratedInventory newInventory(PlayerData data) { + return new GuildViewInventory(data, this); + } - public class GuildViewInventory extends GeneratedInventory { - private final int maxpages; + public class GuildViewInventory extends GeneratedInventory { + private final int maxpages; - private int page = 1; - private List members; + private int page = 1; + private List members; - public GuildViewInventory(PlayerData playerData, EditableInventory editable) { - super(playerData, editable); + public GuildViewInventory(PlayerData playerData, EditableInventory editable) { + super(playerData, editable); - maxpages = (playerData.getGuild().countMembers() + 20) / editable.getByFunction("member").getSlots().size(); - } + maxpages = (playerData.getGuild().countMembers() + 20) / editable.getByFunction("member").getSlots().size(); + } - @Override - public void open() { - members = playerData.getGuild().listMembers(); - super.open(); - } + @Override + public void open() { + members = playerData.getGuild().listMembers(); + super.open(); + } - @Override - public String calculateName() { - return getName().replace("{online_players}", "" + getPlayerData().getGuild().countOnlineMembers()).replace("{page}", "" + page).replace("{maxpages}", "" + maxpages).replace("{players}", String.valueOf(getPlayerData().getGuild().countMembers())).replace("{tag}", getPlayerData().getGuild().getTag()).replace("{name}", getPlayerData().getGuild().getName()); - } + @Override + public String calculateName() { + return getName().replace("{online_players}", "" + getPlayerData().getGuild().countOnlineMembers()).replace("{page}", "" + page).replace("{maxpages}", "" + maxpages).replace("{players}", String.valueOf(getPlayerData().getGuild().countMembers())).replace("{tag}", getPlayerData().getGuild().getTag()).replace("{name}", getPlayerData().getGuild().getName()); + } - @Override - public void whenClicked(InventoryClickContext context, InventoryItem item) { - if (item.getFunction().equals("leave")) { - playerData.getGuild().removeMember(playerData.getUniqueId()); - player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); - player.closeInventory(); - return; - } + @Override + public void whenClicked(InventoryClickContext context, InventoryItem item) { + if (item.getFunction().equals("leave")) { + playerData.getGuild().removeMember(playerData.getUniqueId()); + player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); + player.closeInventory(); + return; + } - if (item.getFunction().equals("next") && page != maxpages) { - page++; - open(); - return; - } + if (item.getFunction().equals("next") && page != maxpages) { + page++; + open(); + return; + } - if (item.getFunction().equals("previous") && page != 1) { - page--; - open(); - return; - } + if (item.getFunction().equals("previous") && page != 1) { + page--; + open(); + return; + } - if (item.getFunction().equals("disband")) { - if (!playerData.getGuild().getOwner().equals(playerData.getUniqueId())) - return; - MMOCore.plugin.dataProvider.getGuildManager().unregisterGuild(playerData.getGuild()); - player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); - player.closeInventory(); - return; - } + if (item.getFunction().equals("disband")) { + if (!playerData.getGuild().getOwner().equals(playerData.getUniqueId())) + return; + MMOCore.plugin.dataProvider.getGuildManager().unregisterGuild(playerData.getGuild()); + player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); + player.closeInventory(); + return; + } - if (item.getFunction().equals("invite")) { - if (!playerData.getGuild().getOwner().equals(playerData.getUniqueId())) - return; + if (item.getFunction().equals("invite")) { + if (!playerData.getGuild().getOwner().equals(playerData.getUniqueId())) + return; - /* - * if (playerData.getGuild().getMembers().count() >= max) { - * ConfigMessage.fromKey("guild-is-full").send(player); - * player.playSound(player.getLocation(), - * Sound.ENTITY_VILLAGER_NO, 1, 1); return; } - */ + /* + * if (playerData.getGuild().getMembers().count() >= max) { + * ConfigMessage.fromKey("guild-is-full").send(player); + * player.playSound(player.getLocation(), + * Sound.ENTITY_VILLAGER_NO, 1, 1); return; } + */ - new ChatInput(player, PlayerInput.InputType.GUILD_INVITE, context.getInventoryHolder(), input -> { - Player target = Bukkit.getPlayer(input); - if (target == null) { - ConfigMessage.fromKey("not-online-player", "player", input).send(player); - player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 1); - open(); - return; - } + new ChatInput(player, PlayerInput.InputType.GUILD_INVITE, context.getInventoryHolder(), input -> { + Player target = Bukkit.getPlayer(input); + if (target == null) { + ConfigMessage.fromKey("not-online-player", "player", input).send(player); + player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 1); + open(); + return; + } - long remaining = playerData.getGuild().getLastInvite(target) + 60 * 2 * 1000 - System.currentTimeMillis(); - if (remaining > 0) { - ConfigMessage.fromKey("guild-invite-cooldown", "player", target.getName(), "cooldown", new DelayFormat().format(remaining)).send(player); - open(); - return; - } + long remaining = playerData.getGuild().getLastInvite(target) + 60 * 2 * 1000 - System.currentTimeMillis(); + if (remaining > 0) { + ConfigMessage.fromKey("guild-invite-cooldown", "player", target.getName(), "cooldown", new DelayFormat().format(remaining)).send(player); + open(); + return; + } - PlayerData targetData = PlayerData.get(target); - if (playerData.getGuild().hasMember(targetData.getUniqueId())) { - ConfigMessage.fromKey("already-in-guild", "player", target.getName()).send(player); - player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 1); - open(); - return; - } + PlayerData targetData = PlayerData.get(target); + if (playerData.getGuild().hasMember(targetData.getUniqueId())) { + ConfigMessage.fromKey("already-in-guild", "player", target.getName()).send(player); + player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 1); + open(); + return; + } - playerData.getGuild().sendGuildInvite(playerData, targetData); - ConfigMessage.fromKey("sent-guild-invite", "player", target.getName()).send(player); - player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); - open(); - }); - } + playerData.getGuild().sendGuildInvite(playerData, targetData); + ConfigMessage.fromKey("sent-guild-invite", "player", target.getName()).send(player); + player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); + open(); + }); + } - if (item.getFunction().equals("member") && context.getClickType() == ClickType.RIGHT) { - if (!playerData.getGuild().getOwner().equals(playerData.getUniqueId())) - return; + if (item.getFunction().equals("member") && context.getClickType() == ClickType.RIGHT) { + if (!playerData.getGuild().getOwner().equals(playerData.getUniqueId())) + return; - String tag = context.getClickedItem().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING); - if (tag == null || tag.isEmpty()) - return; + String tag = context.getClickedItem().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING); + if (tag == null || tag.isEmpty()) + return; - OfflinePlayer target = Bukkit.getOfflinePlayer(UUID.fromString(tag)); - if (target.equals(player)) - return; + OfflinePlayer target = Bukkit.getOfflinePlayer(UUID.fromString(tag)); + if (target.equals(player)) + return; - playerData.getGuild().removeMember(target.getUniqueId()); - ConfigMessage.fromKey("kick-from-guild", "player", target.getName()).send(player); - player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); - } - } + playerData.getGuild().removeMember(target.getUniqueId()); + ConfigMessage.fromKey("kick-from-guild", "player", target.getName()).send(player); + player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); + } + } - public int getPage() { - return page; - } - } + public int getPage() { + return page; + } + } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyView.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyView.java index 765e3010..eb0d16da 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyView.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyView.java @@ -57,7 +57,7 @@ public class EditablePartyView extends EditableInventory { if (member.isOnline()) holders.register("name", member.getPlayer().getName()); holders.register("class", member.getProfess().getName()); - holders.register("level", "" + member.getLevel()); + holders.register("level", member.getLevel()); holders.register("since", new DelayFormat(2).format(System.currentTimeMillis() - member.getLastLogin())); return holders; } @@ -77,7 +77,7 @@ public class EditablePartyView extends EditableInventory { meta.getPersistentDataContainer().set(UUID_NAMESPACEDKEY, PersistentDataType.STRING, member.getUniqueId().toString()); if (meta instanceof SkullMeta) - inv.dynamicallyUpdateItem(this, n, disp, current -> { + inv.asyncUpdate(this, n, disp, current -> { ((SkullMeta) meta).setOwningPlayer(member); current.setItemMeta(meta); });