diff --git a/pom.xml b/pom.xml index 5e56b9fe..de31e9b4 100644 --- a/pom.xml +++ b/pom.xml @@ -125,6 +125,11 @@ https://papermc.io/repo/repository/maven-public/ + + dmulloy2-repo + https://repo.dmulloy2.net/repository/public/ + + @@ -188,6 +193,13 @@ provided + + com.comphenix.protocol + ProtocolLib + 4.8.0 + provided + + net.citizensnpcs Citizens diff --git a/src/main/java/net/Indyuce/mmocore/MMOCore.java b/src/main/java/net/Indyuce/mmocore/MMOCore.java index 6017dad8..3f2172c7 100644 --- a/src/main/java/net/Indyuce/mmocore/MMOCore.java +++ b/src/main/java/net/Indyuce/mmocore/MMOCore.java @@ -28,7 +28,6 @@ import net.Indyuce.mmocore.guild.GuildModuleType; import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.guild.provided.MMOCoreGuildModule; import net.Indyuce.mmocore.listener.*; -import net.Indyuce.mmocore.listener.bungee.GetMMOCorePlayerListener; import net.Indyuce.mmocore.listener.event.PlayerPressKeyListener; import net.Indyuce.mmocore.listener.option.*; import net.Indyuce.mmocore.listener.profession.FishingListener; @@ -110,6 +109,8 @@ public class MMOCore extends JavaPlugin { public boolean shouldDebugSQL, hasBungee; + private static final int MYTHICLIB_COMPATIBILITY_INDEX = 7; + public MMOCore() { plugin = this; } @@ -185,12 +186,9 @@ public class MMOCore extends JavaPlugin { // Checks if the server runs with Bungee hasBungee = SpigotConfig.bungee & !Bukkit.getServer().getOnlineMode(); - //Setups the channel for Bungee - if(hasBungee) { - getServer().getMessenger().registerOutgoingPluginChannel(this,"namespace:give_mmocore_player"); - getServer().getMessenger().registerOutgoingPluginChannel(this,"namespace:get_mmocore_player"); - getServer().getMessenger().registerIncomingPluginChannel(this,"namespace:get_mmocore_player",new GetMMOCorePlayerListener()); - } + + + /* * Resource regeneration. Must check if entity is dead otherwise regen will make @@ -277,9 +275,8 @@ public class MMOCore extends JavaPlugin { getLogger().log(Level.WARNING, "Could not load hotbar swapping: " + exception.getMessage()); } - if (getConfig().getBoolean("prevent-spawner-xp")) { + if (getConfig().getBoolean("prevent-spawner-xp")) Bukkit.getPluginManager().registerEvents(new NoSpawnerEXP(), this); - } if (getConfig().getBoolean("death-exp-loss.enabled")) Bukkit.getPluginManager().registerEvents(new DeathExperienceLoss(), this); @@ -300,12 +297,12 @@ public class MMOCore extends JavaPlugin { /* * Initialize player data from all online players. This is very important to do - * that after registering all the classes otherwise the player datas can't + * that after registering all the professses otherwise the player datas can't * recognize what profess the player has and professes will be lost */ Bukkit.getOnlinePlayers().forEach(player -> dataProvider.getDataManager().setup(player.getUniqueId())); - // Load guild data after loading player data + // load guild data after loading player data dataProvider.getGuildManager().load(); // Command diff --git a/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java b/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java index f49b9026..7f6cbbd5 100644 --- a/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java +++ b/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java @@ -154,6 +154,9 @@ public class DefaultMMOLoader extends MMOLoader { if (config.getKey().equals("craftitem")) return new CraftItemExperienceSource(dispenser, config); + if (config.getKey().equals("fishitem")) + return new FishItemExperienceSource(dispenser, config); + return null; } diff --git a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java index a3fa80c5..82ed628c 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java @@ -27,6 +27,7 @@ import net.Indyuce.mmocore.experience.ExperienceTableClaimer; import net.Indyuce.mmocore.experience.PlayerProfessions; import net.Indyuce.mmocore.experience.droptable.ExperienceItem; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; +import net.Indyuce.mmocore.gui.api.GeneratedInventory; import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; import net.Indyuce.mmocore.party.AbstractParty; @@ -84,6 +85,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc private final Map classSlots = new HashMap<>(); private final Map lastActivity = new HashMap<>(); + /** * Saves all the items that have been unlocked so far by * the player. This is used for: @@ -244,6 +246,8 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc return skillPoints; } + + @Override public int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item) { String key = object.getKey() + "." + table.getId() + "." + item.getId(); diff --git a/src/main/java/net/Indyuce/mmocore/api/util/MMOCoreUtils.java b/src/main/java/net/Indyuce/mmocore/api/util/MMOCoreUtils.java index 2c57d437..0183b320 100644 --- a/src/main/java/net/Indyuce/mmocore/api/util/MMOCoreUtils.java +++ b/src/main/java/net/Indyuce/mmocore/api/util/MMOCoreUtils.java @@ -85,6 +85,11 @@ public class MMOCoreUtils { return t; } + public static String toEnumName(String str) { + return str.replace("-","_").replace(" ","_").toUpperCase(); + } + + public static String toBase64(ItemStack[] items) { try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); diff --git a/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java b/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java index 205ccc12..8f316301 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java +++ b/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java @@ -2,19 +2,19 @@ package net.Indyuce.mmocore.gui; import io.lumine.mythic.lib.manager.StatManager; import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.event.PlayerAttributeUseEvent; -import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute; import net.Indyuce.mmocore.api.player.attribute.PlayerAttributes; -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.InventoryItem; -import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; +import net.Indyuce.mmocore.api.SoundEvent; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.gui.api.EditableInventory; +import net.Indyuce.mmocore.gui.api.item.Placeholders; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.event.inventory.InventoryClickEvent; public class AttributeView extends EditableInventory { public AttributeView() { @@ -90,7 +90,7 @@ public class AttributeView extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equalsIgnoreCase("reallocation")) { int spent = playerData.getAttributes().countSkillPoints(); @@ -131,7 +131,7 @@ public class AttributeView extends EditableInventory { } // Amount of points spent - final boolean shiftClick = event.isShiftClick(); + final boolean shiftClick = context.getClickType().isShiftClick(); int pointsSpent = shiftClick ? ((AttributeItem) item).shiftCost : 1; if (attribute.hasMax()) pointsSpent = Math.min(pointsSpent, attribute.getMax() - ins.getBase()); diff --git a/src/main/java/net/Indyuce/mmocore/gui/ClassConfirmation.java b/src/main/java/net/Indyuce/mmocore/gui/ClassConfirmation.java index dad42be6..0e6ffd9b 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/ClassConfirmation.java +++ b/src/main/java/net/Indyuce/mmocore/gui/ClassConfirmation.java @@ -5,6 +5,7 @@ import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent; import net.Indyuce.mmocore.api.player.profess.PlayerClass; 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.PluginInventory; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; @@ -107,10 +108,7 @@ public class ClassConfirmation extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { - if (event.getInventory() != event.getClickedInventory()) - return; - + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("back")) last.open(); diff --git a/src/main/java/net/Indyuce/mmocore/gui/ClassSelect.java b/src/main/java/net/Indyuce/mmocore/gui/ClassSelect.java index dea606ac..6b408afe 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/ClassSelect.java +++ b/src/main/java/net/Indyuce/mmocore/gui/ClassSelect.java @@ -1,8 +1,6 @@ package net.Indyuce.mmocore.gui; import io.lumine.mythic.lib.MythicLib; -import io.lumine.mythic.lib.api.item.ItemTag; -import io.lumine.mythic.lib.api.item.NBTItem; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.SoundEvent; @@ -11,15 +9,17 @@ import net.Indyuce.mmocore.api.player.profess.ClassOption; import net.Indyuce.mmocore.api.player.profess.PlayerClass; 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.InventoryItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.manager.InventoryManager; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; import java.util.ArrayList; import java.util.Comparator; @@ -27,134 +27,134 @@ import java.util.List; import java.util.stream.Collectors; public class ClassSelect extends EditableInventory { - public ClassSelect() { - super("class-select"); - } + public ClassSelect() { + super("class-select"); + } - @Override - public InventoryItem load(String function, ConfigurationSection config) { - return function.equals("class") ? new ClassItem(config) : new SimplePlaceholderItem(config); - } + @Override + public InventoryItem load(String function, ConfigurationSection config) { + return function.equals("class") ? new ClassItem(config) : new SimplePlaceholderItem(config); + } - public GeneratedInventory newInventory(PlayerData data) { - return new ProfessSelectionInventory(data, this); - } + public GeneratedInventory newInventory(PlayerData data) { + return new ProfessSelectionInventory(data, this); + } - public class ClassItem extends SimplePlaceholderItem { - private final String name; - private final List lore; + public class ClassItem extends SimplePlaceholderItem { + private final String name; + private final List lore; - public ClassItem(ConfigurationSection config) { - super(Material.BARRIER, config); + public ClassItem(ConfigurationSection config) { + super(Material.BARRIER, config); - this.name = config.getString("name"); - this.lore = config.getStringList("lore"); - } + this.name = config.getString("name"); + this.lore = config.getStringList("lore"); + } - public boolean hasDifferentDisplay() { - return true; - } + public boolean hasDifferentDisplay() { + return true; + } - @Override - public ItemStack display(ProfessSelectionInventory inv, int n) { - if (n >= inv.classes.size()) - return null; + @Override + public ItemStack display(ProfessSelectionInventory inv, int n) { + if (n >= inv.classes.size()) + return null; - PlayerClass profess = inv.classes.get(n); - ItemStack item = profess.getIcon(); - ItemMeta meta = item.getItemMeta(); - if (hideFlags()) - meta.addItemFlags(ItemFlag.values()); - meta.setDisplayName(MythicLib.plugin.parseColors(name).replace("{name}", profess.getName())); - List lore = new ArrayList<>(this.lore); + PlayerClass profess = inv.classes.get(n); + ItemStack item = profess.getIcon(); + ItemMeta meta = item.getItemMeta(); + if (hideFlags()) + meta.addItemFlags(ItemFlag.values()); + meta.setDisplayName(MythicLib.plugin.parseColors(name).replace("{name}", profess.getName())); + List lore = new ArrayList<>(this.lore); - int index = lore.indexOf("{lore}"); - if (index >= 0) { - lore.remove(index); - for (int j = 0; j < profess.getDescription().size(); j++) - lore.add(index + j, profess.getDescription().get(j)); - } + int index = lore.indexOf("{lore}"); + if (index >= 0) { + lore.remove(index); + for (int j = 0; j < profess.getDescription().size(); j++) + lore.add(index + j, profess.getDescription().get(j)); + } - index = lore.indexOf("{attribute-lore}"); - if (index >= 0) { - lore.remove(index); - for (int j = 0; j < profess.getAttributeDescription().size(); j++) - lore.add(index + j, profess.getAttributeDescription().get(j)); - } + index = lore.indexOf("{attribute-lore}"); + if (index >= 0) { + lore.remove(index); + for (int j = 0; j < profess.getAttributeDescription().size(); j++) + lore.add(index + j, profess.getAttributeDescription().get(j)); + } + meta.getPersistentDataContainer().set(new NamespacedKey(MMOCore.plugin, "class_id"), PersistentDataType.STRING, profess.getId()); + meta.setLore(lore); + item.setItemMeta(meta); + return item; + } + } - meta.setLore(lore); - item.setItemMeta(meta); - return NBTItem.get(item).addTag(new ItemTag("classId", profess.getId())).toItem(); - } - } + public class ProfessSelectionInventory extends GeneratedInventory { + private final List classes = MMOCore.plugin.classManager.getAll().stream().filter(c -> c.hasOption(ClassOption.DISPLAY)) + .sorted(Comparator.comparingInt(PlayerClass::getDisplayOrder)).collect(Collectors.toList()); - public class ProfessSelectionInventory extends GeneratedInventory { - private final List classes = MMOCore.plugin.classManager.getAll().stream().filter(c -> c.hasOption(ClassOption.DISPLAY)) - .sorted(Comparator.comparingInt(PlayerClass::getDisplayOrder)).collect(Collectors.toList()); + public ProfessSelectionInventory(PlayerData playerData, EditableInventory editable) { + super(playerData, editable); + } - public ProfessSelectionInventory(PlayerData playerData, EditableInventory editable) { - super(playerData, editable); - } + @Override + public String calculateName() { + return getName(); + } - @Override - public String calculateName() { - return getName(); - } + @Override + public void whenClicked(InventoryClickContext context, InventoryItem item) { + if (item.getFunction().equals("class")) { + String classId = context.getItemStack().getItemMeta().getPersistentDataContainer().get(new NamespacedKey(MMOCore.plugin, "class_id"), PersistentDataType.STRING); + if (classId.equals("")) + return; - @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { - if (item.getFunction().equals("class")) { - String tag = NBTItem.get(event.getCurrentItem()).getString("classId"); - if (tag.equals("")) - return; + if (playerData.getClassPoints() < 1) { + MMOCore.plugin.soundManager.getSound(SoundEvent.CANT_SELECT_CLASS).playTo(player); + new ConfigMessage("cant-choose-new-class").send(player); + return; + } - if (playerData.getClassPoints() < 1) { - MMOCore.plugin.soundManager.getSound(SoundEvent.CANT_SELECT_CLASS).playTo(player); - new ConfigMessage("cant-choose-new-class").send(player); - return; - } + PlayerClass profess = MMOCore.plugin.classManager.get(classId); + if (profess.hasOption(ClassOption.NEEDS_PERMISSION) && !player.hasPermission("mmocore.class." + profess.getId().toLowerCase())) { + MMOCore.plugin.soundManager.getSound(SoundEvent.CANT_SELECT_CLASS).playTo(player); + new ConfigMessage("no-permission-for-class").send(player); + return; + } - PlayerClass profess = MMOCore.plugin.classManager.get(tag); - if (profess.hasOption(ClassOption.NEEDS_PERMISSION) && !player.hasPermission("mmocore.class." + profess.getId().toLowerCase())) { - MMOCore.plugin.soundManager.getSound(SoundEvent.CANT_SELECT_CLASS).playTo(player); - new ConfigMessage("no-permission-for-class").send(player); - return; - } + if (profess.equals(playerData.getProfess())) { + MMOCore.plugin.soundManager.getSound(SoundEvent.CANT_SELECT_CLASS).playTo(player); + MMOCore.plugin.configManager.getSimpleMessage("already-on-class", "class", profess.getName()).send(player); + return; + } - if (profess.equals(playerData.getProfess())) { - MMOCore.plugin.soundManager.getSound(SoundEvent.CANT_SELECT_CLASS).playTo(player); - MMOCore.plugin.configManager.getSimpleMessage("already-on-class", "class", profess.getName()).send(player); - return; - } + InventoryManager.CLASS_CONFIRM.newInventory(playerData, findDeepestSubclass(playerData, profess), this).open(); + } + } + } - InventoryManager.CLASS_CONFIRM.newInventory(playerData, findDeepestSubclass(playerData, profess), this).open(); - } - } - } + /** + * When switching from a class where you had progress before, + * you should be instantly redirected to the highest subclass + * in the subclass tree that you chose, because your progress + * is saved there. + *

+ * It's also more RPG style to take the player back to the subclass + * he chose because that way he can't turn back and chose another path. + *

+ * This does NOT function properly with subclass nets yet. + * + * @param root The root class, it's called the root because since the + * player was able to choose it in the class GUI, it should + * be at the bottom of the class tree. + */ + private PlayerClass findDeepestSubclass(PlayerData player, PlayerClass root) { + for (String checkedName : player.getSavedClasses()) { + PlayerClass checked = MMOCore.plugin.classManager.getOrThrow(checkedName); + if (root.hasSubclass(checked)) + return checked; + } - /** - * When switching from a class where you had progress before, - * you should be instantly redirected to the highest subclass - * in the subclass tree that you chose, because your progress - * is saved there. - *

- * It's also more RPG style to take the player back to the subclass - * he chose because that way he can't turn back and chose another path. - * - * This does NOT function properly with subclass nets yet. - * - * @param root The root class, it's called the root because since the - * player was able to choose it in the class GUI, it should - * be at the bottom of the class tree. - */ - private PlayerClass findDeepestSubclass(PlayerData player, PlayerClass root) { - for (String checkedName : player.getSavedClasses()) { - PlayerClass checked = MMOCore.plugin.classManager.getOrThrow(checkedName); - if (root.hasSubclass(checked)) - return checked; - } - - return root; - } + return root; + } } diff --git a/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java b/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java index cdd27b10..2768c3e0 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java +++ b/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java @@ -13,6 +13,7 @@ import net.Indyuce.mmocore.experience.Booster; import net.Indyuce.mmocore.experience.Profession; 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.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; @@ -22,7 +23,6 @@ import org.apache.commons.lang.Validate; import org.bukkit.ChatColor; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; @@ -183,7 +183,7 @@ public class PlayerStats extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext event, InventoryItem item) { if (item.hasFunction()) if (item.getFunction().equals("boost-next")) { boostOffset++; diff --git a/src/main/java/net/Indyuce/mmocore/gui/QuestViewer.java b/src/main/java/net/Indyuce/mmocore/gui/QuestViewer.java index 8623599b..37fce99d 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/QuestViewer.java +++ b/src/main/java/net/Indyuce/mmocore/gui/QuestViewer.java @@ -6,6 +6,7 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.quest.Quest; 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.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; @@ -15,12 +16,16 @@ import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.util.math.format.DelayFormat; import org.apache.commons.lang.Validate; import org.bukkit.ChatColor; +import org.bukkit.NamespacedKey; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; +import org.checkerframework.checker.units.qual.N; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -162,9 +167,12 @@ public class QuestViewer extends EditableInventory { meta.setDisplayName(holders.apply(inv.getPlayer(), getName())); meta.addItemFlags(ItemFlag.values()); meta.setLore(lore); + + + meta.getPersistentDataContainer().set(new NamespacedKey(MMOCore.plugin,"quest_id"), PersistentDataType.STRING,quest.getId()); item.setItemMeta(meta); - return NBTItem.get(item).addTag(new ItemTag("questId", quest.getId())).toItem(); + return item; } private Placeholders getPlaceholders(PlayerData data, Quest quest) { @@ -207,7 +215,7 @@ public class QuestViewer extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("previous")) { page--; open(); @@ -221,11 +229,12 @@ public class QuestViewer extends EditableInventory { } if (item.getFunction().equals("quest")) { - String tag = NBTItem.get(event.getCurrentItem()).getString("questId"); - if (tag.equals("")) + String questId = context.getItemStack().getItemMeta().getPersistentDataContainer() + .get(new NamespacedKey(MMOCore.plugin,"quest_id"), PersistentDataType.STRING); + if (questId.equals("")) return; - Quest quest = MMOCore.plugin.questManager.get(tag); + Quest quest = MMOCore.plugin.questManager.get(questId); if (playerData.getQuestData().hasCurrent()) { @@ -233,7 +242,7 @@ public class QuestViewer extends EditableInventory { * check if the player is cancelling his ongoing quest. */ if (playerData.getQuestData().hasCurrent(quest)) { - if (event.getAction() == InventoryAction.PICKUP_HALF) { + if (context.getClickType() == ClickType.RIGHT) { playerData.getQuestData().start(null); MMOCore.plugin.soundManager.getSound(SoundEvent.CANCEL_QUEST).playTo(player); MMOCore.plugin.configManager.getSimpleMessage("cancel-quest").send(player); diff --git a/src/main/java/net/Indyuce/mmocore/gui/SkillList.java b/src/main/java/net/Indyuce/mmocore/gui/SkillList.java index ee4393ea..a16a22e1 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/SkillList.java +++ b/src/main/java/net/Indyuce/mmocore/gui/SkillList.java @@ -4,6 +4,7 @@ import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.item.ItemTag; import io.lumine.mythic.lib.api.item.NBTItem; import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.api.player.PlayerData; @@ -17,6 +18,7 @@ import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemFlag; @@ -283,7 +285,7 @@ public class SkillList extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { /* if (skillSlots.contains(event.getRawSlot()) @@ -296,7 +298,7 @@ public class SkillList extends EditableInventory { */ if (item.getFunction().equals("skill")) { - int index = skillSlots.size() * page + skillSlots.indexOf(event.getRawSlot()); + int index = skillSlots.size() * page + skillSlots.indexOf(context.getSlot()); player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 2); selected = skills.get(index); open(); @@ -321,11 +323,11 @@ public class SkillList extends EditableInventory { * binding or unbinding skills. */ if (item.getFunction().equals("slot")) { - int index = slotSlots.indexOf(event.getRawSlot()); + int index = slotSlots.indexOf(context.getSlot()); // unbind if there is a current spell. - if (event.getAction() == InventoryAction.PICKUP_HALF) { + if (context.getClickType() == ClickType.RIGHT) { if (!playerData.hasSkillBound(index)) { MMOCore.plugin.configManager.getSimpleMessage("no-skill-bound").send(player); player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2); @@ -384,7 +386,7 @@ public class SkillList extends EditableInventory { return; } - if (event.isShiftClick()) { + if (context.getClickType().isShiftClick()) { if (playerData.getSkillPoints() < shiftCost) { MMOCore.plugin.configManager.getSimpleMessage("not-enough-skill-points-shift", "shift_points", "" + shiftCost).send(player); player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2); diff --git a/src/main/java/net/Indyuce/mmocore/gui/SubclassConfirmation.java b/src/main/java/net/Indyuce/mmocore/gui/SubclassConfirmation.java index bc64667d..4a24ac27 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/SubclassConfirmation.java +++ b/src/main/java/net/Indyuce/mmocore/gui/SubclassConfirmation.java @@ -5,6 +5,7 @@ import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent; import net.Indyuce.mmocore.api.player.profess.PlayerClass; 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.PluginInventory; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; @@ -50,9 +51,7 @@ public class SubclassConfirmation extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { - if (event.getInventory() != event.getClickedInventory()) - return; + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("back")) last.open(); diff --git a/src/main/java/net/Indyuce/mmocore/gui/SubclassSelect.java b/src/main/java/net/Indyuce/mmocore/gui/SubclassSelect.java index 1e85268b..25cff48a 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/SubclassSelect.java +++ b/src/main/java/net/Indyuce/mmocore/gui/SubclassSelect.java @@ -7,6 +7,7 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.profess.PlayerClass; 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.InventoryItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.manager.InventoryManager; @@ -107,12 +108,12 @@ public class SubclassSelect extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("back")) InventoryManager.CLASS_SELECT.newInventory(playerData).open(); if (item.getFunction().equals("class")) { - String tag = NBTItem.get(event.getCurrentItem()).getString("classId"); + String tag = NBTItem.get(context.getItemStack()).getString("classId"); if (tag.equals("")) return; diff --git a/src/main/java/net/Indyuce/mmocore/gui/WaypointViewer.java b/src/main/java/net/Indyuce/mmocore/gui/WaypointViewer.java index 668c6b15..68e5176d 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/WaypointViewer.java +++ b/src/main/java/net/Indyuce/mmocore/gui/WaypointViewer.java @@ -1,6 +1,7 @@ package net.Indyuce.mmocore.gui; import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.api.player.PlayerActivity; @@ -222,7 +223,7 @@ public class WaypointViewer extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("next")) { page++; open(); @@ -236,7 +237,7 @@ public class WaypointViewer extends EditableInventory { } if (item.getFunction().equals("waypoint")) { - PersistentDataContainer container = event.getCurrentItem().getItemMeta().getPersistentDataContainer(); + PersistentDataContainer container = context.getItemStack().getItemMeta().getPersistentDataContainer(); String tag = container.has(new NamespacedKey(MMOCore.plugin, "waypointId"), PersistentDataType.STRING) ? container.get(new NamespacedKey(MMOCore.plugin, "waypointId"), PersistentDataType.STRING) : ""; diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/EditableInventory.java b/src/main/java/net/Indyuce/mmocore/gui/api/EditableInventory.java index 5660ded8..45a59c9a 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/api/EditableInventory.java +++ b/src/main/java/net/Indyuce/mmocore/gui/api/EditableInventory.java @@ -2,6 +2,8 @@ package net.Indyuce.mmocore.gui.api; import io.lumine.mythic.lib.MythicLib; import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.util.MMOCoreUtils; +import net.Indyuce.mmocore.gui.api.adaptor.AdaptorType; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.TriggerItem; import org.apache.commons.lang.Validate; @@ -14,79 +16,119 @@ import java.util.Set; import java.util.logging.Level; public abstract class EditableInventory { - private final String id; + private final String id; - private String name; - private int slots; + private AdaptorType adaptorType; + private String name; + private int slots; - /* - * this set is linked so it keeps the order/priority in which the items are - * loaded from the config. - */ - private final Set items = new LinkedHashSet<>(); + protected double radius, angleGap, verticalGap, curvature, verticalOffset, interactSensitivity; - protected static final DecimalFormat decimal = MythicLib.plugin.getMMOConfig().decimal; + /* + * This set is linked so it keeps the order/priority in + * which the items are loaded from the config. + */ + private final Set items = new LinkedHashSet<>(); - public EditableInventory(String id) { - this.id = id; - Validate.notNull(id, "ID must not be null"); - } + protected static final DecimalFormat decimal = MythicLib.plugin.getMMOConfig().decimal; - public void reload(FileConfiguration config) { + public EditableInventory(String id) { + this.id = id; + Validate.notNull(id, "ID must not be null"); + } - this.name = config.getString("name"); - Validate.notNull(name, "Name must not be null"); + public void reload(FileConfiguration config) { - this.slots = Math.min(Math.max(9, config.getInt("slots")), 54); - Validate.isTrue((slots % 9) == 0, "Slots must be a multiple of 9"); + this.adaptorType = AdaptorType.valueOf(MMOCoreUtils.toEnumName(config.getString("adaptor-type", "classic-adaptor"))); + Validate.notNull(adaptorType, config.getString("adaptor-type") + " does not correspond to an adaptor-type.");//TODO + this.radius = config.getDouble("radius", 2); + this.angleGap = config.getDouble("angle-gap", 10); + this.verticalGap = config.getDouble("vertical-gap", 1); + this.curvature = config.getDouble("curvature", 1); + this.verticalOffset = config.getDouble("vertical-offset", 0); + this.interactSensitivity = config.getDouble("interact-sensitivity", 0.97); - items.clear(); - if (config.contains("items")) { - Validate.notNull(config.getConfigurationSection("items"), "Could not load item list"); - for (String key : config.getConfigurationSection("items").getKeys(false)) - try { - ConfigurationSection section = config.getConfigurationSection("items." + key); - Validate.notNull(section, "Could not load config"); - InventoryItem loaded = loadInventoryItem(section); - items.add(loaded); - } catch (IllegalArgumentException exception) { - MMOCore.log(Level.WARNING, "Could not load item '" + key + "' from inventory '" + getId() + "': " + exception.getMessage()); - } - } - } + this.name = config.getString("name"); + Validate.notNull(name, "Name must not be null"); - public String getId() { - return id; - } + this.slots = Math.min(Math.max(9, config.getInt("slots")), 54); + Validate.isTrue((slots % 9) == 0, "Slots must be a multiple of 9"); - public Set getItems() { - return items; - } + items.clear(); + if (config.contains("items")) { + Validate.notNull(config.getConfigurationSection("items"), "Could not load item list"); + for (String key : config.getConfigurationSection("items").getKeys(false)) + try { + ConfigurationSection section = config.getConfigurationSection("items." + key); + Validate.notNull(section, "Could not load config"); + InventoryItem loaded = loadInventoryItem(section); + items.add(loaded); + } catch (IllegalArgumentException exception) { + MMOCore.log(Level.WARNING, "Could not load item '" + key + "' from inventory '" + getId() + "': " + exception.getMessage()); + } + } + } - public String getName() { - return name; - } + public String getId() { + return id; + } - public int getSlots() { - return slots; - } + public Set getItems() { + return items; + } - public InventoryItem getByFunction(String function) { - for (InventoryItem item : items) - if (item.getFunction().equals(function)) - return item; - return null; - } + public String getName() { + return name; + } - public abstract InventoryItem load(String function, ConfigurationSection config); + public int getSlots() { + return slots; + } - private InventoryItem loadInventoryItem(ConfigurationSection config) { - String function = config.contains("function") ? config.getString("function").toLowerCase() : ""; + public AdaptorType getAdaptorType() { + return adaptorType; + } - if (function.startsWith("trigger:")) - return new TriggerItem(config, function.substring(8)); + public double getRadius() { + return radius; + } - return load(function, config); - } + public double getAngleGap() { + return angleGap; + } + + public double getVerticalGap() { + return verticalGap; + } + + public double getInteractSensitivity() { + return interactSensitivity; + } + + public double getCurvature() { + return curvature; + } + + public double getVerticalOffset() { + return verticalOffset; + } + + public InventoryItem getByFunction(String function) { + for (InventoryItem item : items) + if (item.getFunction().equals(function)) + return item; + return null; + } + + public abstract InventoryItem load(String function, ConfigurationSection config); + + private InventoryItem loadInventoryItem(ConfigurationSection config) { + String function = config.contains("function") ? config.getString("function").toLowerCase() : ""; + + if (function.startsWith("trigger:")) + return new TriggerItem(config, function.substring(8)); + + return load(function, config); + } } diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java b/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java index 85be0d26..18d77a25 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java +++ b/src/main/java/net/Indyuce/mmocore/gui/api/GeneratedInventory.java @@ -1,12 +1,11 @@ package net.Indyuce.mmocore.gui.api; -import io.lumine.mythic.lib.MythicLib; -import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.gui.api.adaptor.Adaptor; +import net.Indyuce.mmocore.gui.api.adaptor.ClassicAdaptor; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.TriggerItem; -import org.bukkit.Bukkit; -import org.bukkit.event.inventory.InventoryClickEvent; +import org.apache.commons.lang.Validate; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -17,13 +16,13 @@ import java.util.function.Consumer; public abstract class GeneratedInventory extends PluginInventory { private final EditableInventory editable; private final List loaded = new ArrayList<>(); - - private Inventory open; + private final Adaptor adaptor; public GeneratedInventory(PlayerData playerData, EditableInventory editable) { super(playerData); this.editable = editable; + this.adaptor = editable.getAdaptorType().supply(this); } public List getLoaded() { @@ -59,13 +58,8 @@ public abstract class GeneratedInventory extends PluginInventory { @Override public Inventory getInventory() { - Inventory inv = Bukkit.createInventory(this, editable.getSlots(), MythicLib.plugin.getPlaceholderParser().parse(getPlayer(), calculateName())); - - for (InventoryItem item : editable.getItems()) - if (item.canDisplay(this)) - item.setDisplayed(inv, this); - - return inv; + Validate.isTrue(adaptor instanceof ClassicAdaptor); + return ((ClassicAdaptor) adaptor).getInventory(); } public void open() { @@ -76,7 +70,7 @@ public abstract class GeneratedInventory extends PluginInventory { */ loaded.clear(); - getPlayer().openInventory(open = getInventory()); + adaptor.open(); } /** @@ -85,28 +79,24 @@ public abstract class GeneratedInventory extends PluginInventory { */ @Deprecated public void dynamicallyUpdateItem(InventoryItem item, int n, ItemStack placed, Consumer update) { - Bukkit.getScheduler().runTaskAsynchronously(MMOCore.plugin, () -> { - update.accept(placed); - open.setItem(item.getSlots().get(n), placed); - }); + adaptor.dynamicallyUpdateItem(item, n, placed, update); + } - public void whenClicked(InventoryClickEvent event) { - event.setCancelled(true); + public void whenClicked(InventoryClickContext context) { + context.setCancelled(true); + InventoryItem item = getBySlot(context.getSlot()); + if (item == null) + return; - if (event.getClickedInventory() != null && event.getClickedInventory().equals(event.getInventory())) { - InventoryItem item = getBySlot(event.getSlot()); - if (item == null) - return; - - if (item instanceof TriggerItem) - ((TriggerItem) item).getTrigger().apply(getPlayerData()); - else - whenClicked(event, item); - } + if (item instanceof TriggerItem) + ((TriggerItem) item).getTrigger().apply(getPlayerData()); + else + whenClicked(context, item); } + public abstract String calculateName(); - public abstract void whenClicked(InventoryClickEvent event, InventoryItem item); + public abstract void whenClicked(InventoryClickContext context, InventoryItem item); } diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/InventoryClickContext.java b/src/main/java/net/Indyuce/mmocore/gui/api/InventoryClickContext.java new file mode 100644 index 00000000..bbd059e3 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/gui/api/InventoryClickContext.java @@ -0,0 +1,56 @@ +package net.Indyuce.mmocore.gui.api; + + +import org.bukkit.event.Cancellable; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +public class InventoryClickContext { + private final int slot; + private final ItemStack itemStack; + private final ClickType clickType; + + private final Cancellable event; + + private Inventory inv; + + public InventoryClickContext(int slot, ItemStack itemStack, ClickType clickType, Cancellable event) { + this.slot = slot; + this.itemStack = itemStack; + this.clickType = clickType; + this.event = event; + } + + public void setCancelled(boolean val) { + event.setCancelled(val); + } + + public boolean isCancelled() { + return event.isCancelled(); + } + + public int getSlot() { + return slot; + } + + public ItemStack getItemStack() { + return itemStack; + } + + public Cancellable getEvent() { + return event; + } + + public Inventory getInventory() { + return inv; + } + + public boolean isClassic() { + return inv != null; + } + + public ClickType getClickType() { + return clickType; + } +} diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/PluginInventory.java b/src/main/java/net/Indyuce/mmocore/gui/api/PluginInventory.java index f9dde71e..3b17636a 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/api/PluginInventory.java +++ b/src/main/java/net/Indyuce/mmocore/gui/api/PluginInventory.java @@ -1,43 +1,41 @@ package net.Indyuce.mmocore.gui.api; +import net.Indyuce.mmocore.api.player.PlayerData; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; -import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; -import net.Indyuce.mmocore.api.player.PlayerData; - public abstract class PluginInventory implements InventoryHolder { - protected final Player player; - protected final PlayerData playerData; + protected final Player player; + protected final PlayerData playerData; - public PluginInventory(PlayerData playerData) { - this.playerData = playerData; - player = playerData.getPlayer(); - } + public PluginInventory(PlayerData playerData) { + this.playerData = playerData; + player = playerData.getPlayer(); + } - public PluginInventory(Player player) { - this.player = player; - this.playerData = player.getOpenInventory() != null && player.getOpenInventory().getTopInventory().getHolder() instanceof PluginInventory ? ((PluginInventory) player.getOpenInventory().getTopInventory().getHolder()).playerData : PlayerData.get(player); - } + public PluginInventory(Player player) { + this.player = player; + this.playerData = player.getOpenInventory() != null && player.getOpenInventory().getTopInventory().getHolder() instanceof PluginInventory ? ((PluginInventory) player.getOpenInventory().getTopInventory().getHolder()).playerData : PlayerData.get(player); + } - public PlayerData getPlayerData() { - return playerData; - } + public PlayerData getPlayerData() { + return playerData; + } - public Player getPlayer() { - return player; - } + public Player getPlayer() { + return player; + } - public void open() { - getPlayer().openInventory(getInventory()); - } + /** + * Opens classic inventory, throws + */ + public void open() { + getPlayer().openInventory(getInventory()); + } - public abstract Inventory getInventory(); + public abstract void whenClicked(InventoryClickContext context); - public abstract void whenClicked(InventoryClickEvent event); - - public void whenClosed(InventoryCloseEvent event) { - } + public void whenClosed(InventoryCloseEvent event) { + } } diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/Adaptor.java b/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/Adaptor.java new file mode 100644 index 00000000..60f0f291 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/Adaptor.java @@ -0,0 +1,22 @@ +package net.Indyuce.mmocore.gui.api.adaptor; + +import net.Indyuce.mmocore.gui.api.GeneratedInventory; +import net.Indyuce.mmocore.gui.api.item.InventoryItem; +import org.bukkit.inventory.ItemStack; + +import java.util.function.Consumer; + +public abstract class Adaptor { + protected final GeneratedInventory generated; + + public Adaptor(GeneratedInventory generated) { + this.generated = generated; + } + + public abstract void open(); + + public abstract void close(); + + @Deprecated + public abstract void dynamicallyUpdateItem(InventoryItem item, int n, ItemStack placed, Consumer update); +} diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/AdaptorType.java b/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/AdaptorType.java new file mode 100644 index 00000000..79022132 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/AdaptorType.java @@ -0,0 +1,20 @@ +package net.Indyuce.mmocore.gui.api.adaptor; + +import net.Indyuce.mmocore.gui.api.GeneratedInventory; + +import java.util.function.Function; + +public enum AdaptorType { + CLASSIC_ADAPTOR(ClassicAdaptor::new), + THREE_DIM_ADAPTOR(ThreeDimAdaptor::new); + + private final Function supplier; + + AdaptorType(Function supplier) { + this.supplier = supplier; + } + + public Adaptor supply(GeneratedInventory inv) { + return this.supplier.apply(inv); + } +} diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ClassicAdaptor.java b/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ClassicAdaptor.java new file mode 100644 index 00000000..8631c909 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ClassicAdaptor.java @@ -0,0 +1,62 @@ +package net.Indyuce.mmocore.gui.api.adaptor; + +import io.lumine.mythic.lib.MythicLib; +import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.gui.api.GeneratedInventory; +import net.Indyuce.mmocore.gui.api.item.InventoryItem; +import org.bukkit.Bukkit; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.List; +import java.util.function.Consumer; + +public class ClassicAdaptor extends Adaptor { + private Inventory open; + + public ClassicAdaptor(GeneratedInventory generated) { + super(generated); + } + + @Override + public void open() { + generated.getPlayer().openInventory(open = getInventory()); + } + + @Override + public void close() { + + } + + @Override + public void dynamicallyUpdateItem(InventoryItem item, int n, ItemStack placed, Consumer update) { + Bukkit.getScheduler().runTaskAsynchronously(MMOCore.plugin, () -> { + update.accept(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())); + + for (InventoryItem item : generated.getEditable().getItems()) + if (item.canDisplay(generated)) + setDisplayed(inv, item); + + return inv; + } + + private void setDisplayed(Inventory inv, InventoryItem item) { + generated.addLoaded(item); + List slots = item.getSlots(); + + if (!item.hasDifferentDisplay()) { + ItemStack display = item.display(generated); + for (int slot : slots) + inv.setItem(slot, display); + } else + for (int j = 0; j < slots.size(); j++) + inv.setItem(slots.get(j), item.display(generated, j)); + + } +} diff --git a/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ThreeDimAdaptor.java b/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ThreeDimAdaptor.java new file mode 100644 index 00000000..579e959e --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/gui/api/adaptor/ThreeDimAdaptor.java @@ -0,0 +1,499 @@ +package net.Indyuce.mmocore.gui.api.adaptor; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import io.lumine.mythic.lib.api.util.TemporaryListener; +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; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.function.Consumer; + +public class ThreeDimAdaptor extends Adaptor { + private final double INITIAL_PERCENTAGE = 0.20; + private final double INCREMENT_PERCENTAGE = 0.20; + + private SpawnPacketListener packetListener; + private InteractListener interactListener; + private final HashMap armorStands = new HashMap<>(); + + private final HashSet loreArmorStand = new HashSet<>(); + + private final HashMap hiddenArmorStand = new HashMap<>(); + + private boolean firstTime = true; + + private final Vector direction = generated.getPlayer().getEyeLocation().getDirection().setY(0); + private final Location location = generated.getPlayer().getLocation().add(new Vector(0, generated.getEditable().getVerticalOffset(), 0)); + + //Zoomed=-1 no armorstand are under zoom + private int zoomed = -1; + + + public ThreeDimAdaptor(GeneratedInventory generated) { + super(generated); + } + + + @Override + public void open() { + if (!firstTime) { + fastClose(); + fastOpen(); + return; + } + firstTime = false; + //MMOCore.plugin.protocolManager.addPacketListener(packetListener = new SpawnPacketListener()); + interactListener = new InteractListener(); + for (InventoryItem item : generated.getEditable().getItems()) { + if (item.canDisplay(generated)) { + setInventoryItem(item, INITIAL_PERCENTAGE); + } + } + + + new BukkitRunnable() { + double total_percentage = INITIAL_PERCENTAGE; + + @Override + public void run() { + if (total_percentage < 1) { + total_percentage += INCREMENT_PERCENTAGE; + for (int slot : armorStands.keySet()) { + armorStands.get(slot).teleport(getLocation(slot, total_percentage)); + } + } else { + cancel(); + } + + } + }.runTaskTimer(MMOCore.plugin, 0L, 1L); + + + } + + @Override + public void close() { + //Closes the packet listener,the interact listener and destroys the armor stands. + //MMOCore.plugin.protocolManager.removePacketListener(packetListener); + interactListener.close(); + removeLore(); + + new BukkitRunnable() { + double total_percentage = 1; + + @Override + public void run() { + if (total_percentage > INITIAL_PERCENTAGE) { + total_percentage -= INCREMENT_PERCENTAGE; + for (int slot : armorStands.keySet()) { + armorStands.get(slot).teleport(getLocation(slot, total_percentage)); + } + } else { + for (ArmorStand armorStand : armorStands.values()) + armorStand.remove(); + cancel(); + } + + } + }.runTaskTimer(MMOCore.plugin, 0L, 1L); + + + } + + /** + * Opens the inventory without the little animation + */ + public void fastOpen() { + //MMOCore.plugin.protocolManager.addPacketListener(packetListener = new SpawnPacketListener()); + interactListener = new InteractListener(); + for (InventoryItem item : generated.getEditable().getItems()) { + if (item.canDisplay(generated)) { + setInventoryItem(item, 1); + } + } + if (zoomed != -1) { + displayLore(zoomed); + armorStands.get(zoomed).teleport(getLocation(zoomed, 0.75)); + } + } + + + /** + * Closes the inventory without the little animation + */ + public void fastClose() { + //Closes the packet listener,the interact listener and destroys the armor stands. + //MMOCore.plugin.protocolManager.removePacketListener(packetListener); + interactListener.close(); + + for (ArmorStand armorStand : armorStands.values()) + armorStand.remove(); + removeLore(); + + } + + private void setInventoryItem(InventoryItem item, double percentage) { + generated.addLoaded(item); + + List slots = item.getSlots(); + if (item.hasDifferentDisplay()) { + for (int i : slots) { + setItem(item.display(generated, i), i, percentage); + } + } else { + ItemStack itemStack = item.display(generated); + for (int i : slots) { + setItem(itemStack, i, percentage); + } + } + + + } + + private void setItem(ItemStack item, int n, double percentage) { + Location location = getLocation(n, percentage); + //We create the armorStand corresponding to display the item + ArmorStand armorStand = (ArmorStand) generated.getPlayer().getWorld().spawnEntity(location, EntityType.ARMOR_STAND); + armorStand.setVisible(false); + armorStand.setSmall(false); + armorStand.setArms(true); + armorStand.setGravity(false); + armorStand.getEquipment().setItem(EquipmentSlot.HEAD, item); + if (item.hasItemMeta() && item.getItemMeta().getDisplayName() != null) { + armorStand.setCustomName(item.getItemMeta().getDisplayName()); + } + armorStand.setCustomNameVisible(true); + + //We add properties to the PersistentDataContainer of the armor stand + PersistentDataContainer container = armorStand.getPersistentDataContainer(); + container.set(new NamespacedKey(MMOCore.plugin, "slot"), PersistentDataType.INTEGER, n); + + + //Makes the ArmorStand look at you + //armorStand.setBodyPose(new EulerAngle(-direction.getX(),0,-direction.getZ())); + + armorStands.put(n, armorStand); + } + + + public void displayLore(int n) { + ArmorStand armorStand = armorStands.get(n); + ItemStack itemStack = armorStand.getEquipment().getItem(EquipmentSlot.HEAD); + + Location initalLocation = getLocation(n, 1); + + for (ArmorStand armorStand1 : armorStands.values()) { + armorStand1.setCustomNameVisible(false); + } + + Vector xAxis = initalLocation.clone().toVector().subtract(generated.getPlayer().getLocation().toVector()).setY(0).normalize(); + Vector yAxis = new Vector(0, 1, 0); + Vector zAxis = xAxis.clone().rotateAroundAxis(yAxis, -Math.PI / 2); + + + //Empiric height of a line: 0.25 + //Empiric size of a char: 0.13 + double lineHeight = 0.25; + double charSize = 0.09; + //We search the biggest line in the lore + int max = 0; + for (String line : itemStack.getItemMeta().getLore()) { + if (line.length() > max) + max = line.length(); + } + + + initalLocation.add(zAxis.clone().multiply(max * charSize / 2 + 0.8)).add(yAxis.clone().multiply(2 + 0.125 * itemStack.getItemMeta().getLore().size())); + for (String line : itemStack.getItemMeta().getLore()) { + if (line.length() != 0) { + ArmorStand as = (ArmorStand) initalLocation.getWorld().spawnEntity(initalLocation, EntityType.ARMOR_STAND); + as.setSmall(false); + as.setMarker(true); + as.setVisible(false); + as.setCustomNameVisible(true); + as.setCustomName(line); + loreArmorStand.add(as); + } + + initalLocation.add(yAxis.clone().multiply(-lineHeight)); + + } + + double totalHeight = lineHeight * itemStack.getItemMeta().getLore().size(); + double totalLength = max * charSize; + Location topCorner = getLocation(n, 1).add(yAxis.clone().multiply(armorStand.getHeight() * 0.25 + totalHeight / 2)); + + //We remove the items that can be in the field of vision + for (int slot : armorStands.keySet()) { + ArmorStand otherArmorStand = armorStands.get(slot); + if (!otherArmorStand.equals(armorStand)) { + //Calculates the direction between the player and otherArmorStand + Vector direction = otherArmorStand.getLocation().add(new Vector(0, 0.25 * otherArmorStand.getHeight(), 0)).subtract(generated.getPlayer().getLocation()).toVector().normalize(); + //The vector between the plan and the player. + //The plane normal is the xAxis + + double t = (xAxis.clone().dot(topCorner.clone().subtract(generated.getPlayer().getLocation()).toVector())) / xAxis.clone().dot(direction); + Vector relativeProjection = generated.getPlayer().getLocation().toVector().add(direction.multiply(t)).subtract(topCorner.toVector()); + + + //The intersection between 'direction' and the plane + //Vector projection=generated.getPlayer().getLocation().toVector().add(direction.clone().multiply(1/vector.dot(direction))); + //Vector relativeProjection=projection.subtract(topCorner.toVector()); + double z = zAxis.dot(relativeProjection); + double y = (n / 9 - slot / 9) * lineHeight + totalHeight / 2; + if (z > 0 && z < totalLength && y > 0 && y < totalHeight) { + hideArmorStand(otherArmorStand); + } + + + } + } + } + + + /** + * Hide the item corrseponding to a certain armor stand if it hides the lore + */ + public void hideArmorStand(ArmorStand armorStand) { + hiddenArmorStand.put(armorStand.getEquipment().getItem(EquipmentSlot.HEAD), armorStand); + armorStand.getEquipment().setItem(EquipmentSlot.HEAD, null); + } + + + /** + * Reestablishes all the item for armor stand + */ + public void reestablishHiddenArmorStand() { + for (ItemStack item : hiddenArmorStand.keySet()) { + hiddenArmorStand.get(item).getEquipment().setItem(EquipmentSlot.HEAD, item); + } + hiddenArmorStand.clear(); + } + + + public void removeLore() { + for (ArmorStand armorStand : loreArmorStand) { + armorStand.remove(); + } + loreArmorStand.clear(); + + for (ArmorStand armorStand1 : armorStands.values()) { + armorStand1.setCustomNameVisible(true); + } + reestablishHiddenArmorStand(); + } + + + public Location getLocation(int n, double percentage) { + //Determines the location at which the ArmorStand will spawn + + Location cloneLocation = location.clone(); + Vector cloneDirection = direction.clone().rotateAroundAxis(new Vector(0, 1, 0), + -((n % 9) - 4) * generated.getEditable().getAngleGap() * Math.PI / 180); + + //Curvature of 1: r=cst Curvature of 1: r=R/cos(angle) (a plane) + double radius = percentage * generated.getEditable().getRadius() / Math.cos((1 - generated.getEditable().getCurvature()) + * -((n % 9) - 4) * generated.getEditable().getAngleGap() * Math.PI / 180); + cloneDirection = cloneDirection.normalize().multiply(radius); + cloneDirection.add(new Vector(0, percentage * generated.getEditable().getVerticalGap() * ((generated.getEditable().getSlots() - n - 1) / 9), 1)); + //We get the final direction + cloneLocation.add(cloneDirection); + + cloneLocation.setDirection(new Vector(-cloneDirection.getX(), 0, -cloneDirection.getZ())); + return cloneLocation; + } + + @Override + public void dynamicallyUpdateItem(InventoryItem item, int n, ItemStack placed, Consumer update) { + + } + + private class SpawnPacketListener extends PacketAdapter { + + + public SpawnPacketListener() { + super(MMOCore.plugin, PacketType.Play.Server.SPAWN_ENTITY_LIVING); + } + + /** + * Cancels all the packet corresponding to an armorStand of the Gui to a player that should not see it. + */ + @Override + public void onPacketSending(PacketEvent event) { + + PacketContainer packet = event.getPacket(); + Entity entity = ProtocolLibrary.getProtocolManager() + .getEntityFromID(event.getPlayer().getWorld(), packet.getIntegers().read(0)); + if (entity instanceof ArmorStand armorStand) { + if (true) { + Bukkit.broadcastMessage("IN"); + + if (armorStands.values().contains(armorStand)) { + Bukkit.broadcastMessage("CANCEL" + armorStand.getName()); + event.setCancelled(true); + } + } + } + } + + } + + + private class InteractListener extends TemporaryListener { + + public InteractListener() { + super(MMOCore.plugin, PlayerInteractAtEntityEvent.getHandlerList() + , PlayerMoveEvent.getHandlerList(), PlayerInteractEvent.getHandlerList(), PlayerInteractAtEntityEvent.getHandlerList()); + } + + @EventHandler + public void onMove(PlayerMoveEvent e) { + if (e.getPlayer().equals(generated.getPlayer())) { + if (!e.getFrom().getBlock().getLocation().equals(e.getTo().getBlock().getLocation())) + ThreeDimAdaptor.this.close(); + else { + //If the player no longer looks at the zoom as: + if (zoomed != -1 && generated.getPlayer().getLocation().getDirection().normalize().dot( + armorStands.get(zoomed).getLocation().add(new Vector(0, 0.25 * armorStands.get(zoomed).getHeight(), 0)) + .subtract(generated.getPlayer().getLocation()).toVector().normalize()) < generated.getEditable().getInteractSensitivity()) { + armorStands.get(zoomed).teleport(getLocation(zoomed, 1)); + zoomed = -1; + removeLore(); + } + if (zoomed == -1) { + for (int n : armorStands.keySet()) { + ArmorStand as = armorStands.get(n); + Location asLocation = as.getLocation().add(new Vector(0, 0.25 * as.getHeight(), 0)); + + + double scalar = generated.getPlayer().getLocation().getDirection().normalize().dot( + asLocation.subtract(generated.getPlayer().getLocation()).toVector().normalize()); + + if (scalar > generated.getEditable().getInteractSensitivity()) { + as.teleport(getLocation(n, 0.75)); + zoomed = n; + displayLore(zoomed); + } + + + } + + } + } + + } + + } + + @EventHandler + public void onInteract(PlayerInteractAtEntityEvent event) { + if (event.getPlayer().equals(generated.getPlayer())) + if (event.getRightClicked() instanceof ArmorStand armorStand) { + if (armorStands.values().contains(armorStand)) { + PersistentDataContainer container = armorStand.getPersistentDataContainer(); + int slot = container.get(new NamespacedKey(MMOCore.plugin, "slot"), PersistentDataType.INTEGER); + ClickType clickType; + if (event.getPlayer().isSneaking()) + clickType = ClickType.SHIFT_RIGHT; + else + clickType = ClickType.RIGHT; + generated.whenClicked(new InventoryClickContext(slot, armorStand.getEquipment().getItem(EquipmentSlot.HEAD), clickType, event)); + } + } + } + + @EventHandler + public void onInteract(PlayerInteractEvent event) { + if (event.getPlayer().equals(generated.getPlayer())) { + Player player = event.getPlayer(); + for (ArmorStand armorStand : armorStands.values()) { + //Little offset for the armorStand to have the location match the location of the itemstack + if (player.getLocation().getDirection().normalize() + .dot(armorStand.getLocation().add(new Vector(0, 0.25 * armorStand.getHeight(), 0)).subtract(player.getLocation()).toVector().normalize()) > 0.96) { + + PersistentDataContainer container = armorStand.getPersistentDataContainer(); + int slot = container.get(new NamespacedKey(MMOCore.plugin, "slot"), PersistentDataType.INTEGER); + ClickType clickType; + if (event.getAction() == Action.LEFT_CLICK_AIR) { + if (event.getPlayer().isSneaking()) + clickType = ClickType.SHIFT_LEFT; + else + clickType = ClickType.LEFT; + + } else if (event.getAction() == Action.RIGHT_CLICK_AIR) { + + if (event.getPlayer().isSneaking()) + clickType = ClickType.SHIFT_RIGHT; + else + clickType = ClickType.RIGHT; + } else { + return; + } + generated.whenClicked(new InventoryClickContext(slot, armorStand.getEquipment().getItem(EquipmentSlot.HEAD), clickType, event)); + return; + } + + } + } + } + + + @EventHandler + public void onDamage(EntityDamageByEntityEvent event) { + + if (event.getDamager() instanceof Player player) { + if (player.equals(generated.getPlayer())) + if (event.getEntity() instanceof ArmorStand armorStand) { + if (armorStands.values().contains(armorStand)) { + PersistentDataContainer container = armorStand.getPersistentDataContainer(); + int slot = container.get(new NamespacedKey(MMOCore.plugin, "slot"), PersistentDataType.INTEGER); + ClickType clickType; + if (player.isSneaking()) + clickType = ClickType.SHIFT_LEFT; + else + clickType = ClickType.LEFT; + + ItemStack itemStack = armorStand.getEquipment().getItem(EquipmentSlot.HEAD); + generated.whenClicked(new InventoryClickContext(slot, itemStack, clickType, event)); + } + } + } + + } + + @Override + public void whenClosed() { + + + } + + } +} diff --git a/src/main/java/net/Indyuce/mmocore/gui/eco/DepositMenu.java b/src/main/java/net/Indyuce/mmocore/gui/eco/DepositMenu.java index cc1f64e8..be348222 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/eco/DepositMenu.java +++ b/src/main/java/net/Indyuce/mmocore/gui/eco/DepositMenu.java @@ -4,6 +4,7 @@ import io.lumine.mythic.lib.api.item.NBTItem; import io.lumine.mythic.lib.api.util.SmartGive; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.util.MMOCoreUtils; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; import net.Indyuce.mmocore.gui.api.PluginInventory; import net.Indyuce.mmocore.util.item.SimpleItemBuilder; import net.milkbowl.vault.economy.EconomyResponse; @@ -41,11 +42,11 @@ public class DepositMenu extends PluginInventory { } @Override - public void whenClicked(InventoryClickEvent event) { - if (event.getCurrentItem() == null || event.getCurrentItem().getType() == Material.AIR) + public void whenClicked(InventoryClickContext event) { + if (event.getItemStack() == null || event.getItemStack().getType() == Material.AIR) return; - if (event.getCurrentItem().isSimilar(depositItem)) { + if (event.getItemStack().isSimilar(depositItem)) { event.setCancelled(true); updateDeposit(event.getInventory()); @@ -63,7 +64,7 @@ public class DepositMenu extends PluginInventory { return; } - int worth = NBTItem.get(event.getCurrentItem()).getInteger("RpgWorth"); + int worth = NBTItem.get(event.getItemStack()).getInteger("RpgWorth"); if (worth < 1) event.setCancelled(true); else diff --git a/src/main/java/net/Indyuce/mmocore/gui/eco/GoldPouch.java b/src/main/java/net/Indyuce/mmocore/gui/eco/GoldPouch.java index 0d553637..1045f873 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/eco/GoldPouch.java +++ b/src/main/java/net/Indyuce/mmocore/gui/eco/GoldPouch.java @@ -1,90 +1,90 @@ package net.Indyuce.mmocore.gui.eco; +import io.lumine.mythic.lib.api.item.ItemTag; +import io.lumine.mythic.lib.api.item.NBTItem; +import net.Indyuce.mmocore.api.util.MMOCoreUtils; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; +import net.Indyuce.mmocore.gui.api.PluginInventory; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import net.Indyuce.mmocore.api.util.MMOCoreUtils; -import net.Indyuce.mmocore.gui.api.PluginInventory; -import io.lumine.mythic.lib.api.item.ItemTag; -import io.lumine.mythic.lib.api.item.NBTItem; - public class GoldPouch extends PluginInventory { - private final boolean mob; - private final NBTItem nbt; + private final boolean mob; + private final NBTItem nbt; - public GoldPouch(Player player, NBTItem nbt) { - super(player); - this.nbt = nbt; - this.mob = nbt.getBoolean("RpgPouchMob"); - } + public GoldPouch(Player player, NBTItem nbt) { + super(player); - @Override - public Inventory getInventory() { - Inventory inv = Bukkit.createInventory(this, 18, ChatColor.UNDERLINE + "Gold Pouch"); - inv.setContents(MMOCoreUtils.itemStackArrayFromBase64(nbt.getString("RpgPouchInventory"))); - return inv; - } + this.nbt = nbt; + this.mob = nbt.getBoolean("RpgPouchMob"); + } - @Override - public void whenClicked(InventoryClickEvent event) { + @Override + public Inventory getInventory() { + Inventory inv = Bukkit.createInventory(this, 18, ChatColor.UNDERLINE + "Gold Pouch"); + inv.setContents(MMOCoreUtils.itemStackArrayFromBase64(nbt.getString("RpgPouchInventory"))); + return inv; + } - ItemStack item = event.getCurrentItem(); - NBTItem nbt = NBTItem.get(item); - if (!nbt.hasTag("RpgWorth")) { - event.setCancelled(true); - return; - } + @Override + public void whenClicked(InventoryClickContext context) { - if (mob) { - event.setCancelled(true); + ItemStack item = context.getItemStack(); + NBTItem nbt = NBTItem.get(item); + if (!nbt.hasTag("RpgWorth")) { + context.setCancelled(true); + return; + } - // in deposit menu - if (event.getRawSlot() < 18) { - int empty = player.getInventory().firstEmpty(); - if (empty < 0) - return; + if (mob) { + context.setCancelled(true); - player.playSound(player.getLocation(), Sound.ENTITY_SHULKER_TELEPORT, 1, 2); - player.getInventory().addItem(event.getCurrentItem()); - event.setCurrentItem(null); - } + // in deposit menu + if (context.getSlot() < 18) { + int empty = player.getInventory().firstEmpty(); + if (empty < 0) + return; - return; - } + player.playSound(player.getLocation(), Sound.ENTITY_SHULKER_TELEPORT, 1, 2); + player.getInventory().addItem(context.getItemStack()); + context.getInventory().setItem(context.getSlot(), null); + } - /* - * Player cannot interact with a backpack item while - * interacting with a backpack inventory. This fixes a - * huge glitch where the player would lose the backpack - * contents - */ - if (nbt.hasTag("RpgPouchInventory")) - event.setCancelled(true); - } + return; + } - @Override - public void whenClosed(InventoryCloseEvent event) { - Player player = (Player) event.getPlayer(); - if (mob && isEmpty(event.getInventory())) { - player.getEquipment().setItemInMainHand(null); - return; - } + /* + * Player cannot interact with a backpack item while + * interacting with a backpack inventory. This fixes a + * huge glitch where the player would lose the backpack + * contents + */ + if (nbt.hasTag("RpgPouchInventory")) + context.setCancelled(true); + } - ItemStack updated = NBTItem.get(player.getEquipment().getItemInMainHand()).addTag(new ItemTag("RpgPouchInventory", MMOCoreUtils.toBase64(event.getInventory().getContents()))).toItem(); - player.getEquipment().setItemInMainHand(updated); - } + @Override + public void whenClosed(InventoryCloseEvent event) { + Player player = (Player) event.getPlayer(); + if (mob && isEmpty(event.getInventory())) { + player.getEquipment().setItemInMainHand(null); + return; + } - private boolean isEmpty(Inventory inv) { - for (ItemStack item : inv.getContents()) - if (item != null && item.getType() != Material.AIR) - return false; - return true; - } + ItemStack updated = NBTItem.get(player.getEquipment().getItemInMainHand()).addTag(new ItemTag("RpgPouchInventory", MMOCoreUtils.toBase64(event.getInventory().getContents()))).toItem(); + player.getEquipment().setItemInMainHand(updated); + } + + private boolean isEmpty(Inventory inv) { + for (ItemStack item : inv.getContents()) + if (item != null && item.getType() != Material.AIR) + return false; + return true; + } } diff --git a/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendList.java b/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendList.java index aed946e9..a17d99b9 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendList.java +++ b/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendList.java @@ -8,6 +8,7 @@ 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.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; @@ -19,8 +20,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.Sound; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryAction; -import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.SkullMeta; @@ -170,7 +170,7 @@ public class EditableFriendList extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("previous")) { page--; open(); @@ -222,8 +222,8 @@ public class EditableFriendList extends EditableInventory { }); } - if (item.getFunction().equals("friend") && event.getAction() == InventoryAction.PICKUP_HALF) { - String tag = event.getCurrentItem().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING); + if (item.getFunction().equals("friend") && context.getClickType() == ClickType.RIGHT) { + String tag = context.getItemStack().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING); if (tag == null || tag.isEmpty()) return; diff --git a/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendRemoval.java b/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendRemoval.java index e0ae0bea..0e6950b8 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendRemoval.java +++ b/src/main/java/net/Indyuce/mmocore/gui/social/friend/EditableFriendRemoval.java @@ -2,6 +2,7 @@ package net.Indyuce.mmocore.gui.social.friend; 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 net.Indyuce.mmocore.api.player.OfflinePlayerData; import net.Indyuce.mmocore.api.player.PlayerData; @@ -47,7 +48,7 @@ public class EditableFriendRemoval extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("yes")) { playerData.removeFriend(friend.getUniqueId()); OfflinePlayerData.get(friend.getUniqueId()).removeFriend(playerData.getUniqueId()); diff --git a/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildAdmin.java b/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildAdmin.java index 4f6a145f..7153c614 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildAdmin.java +++ b/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildAdmin.java @@ -4,6 +4,7 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.util.input.ChatInput; import net.Indyuce.mmocore.api.util.input.PlayerInput; import net.Indyuce.mmocore.gui.api.GeneratedInventory; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.api.player.PlayerData; @@ -17,6 +18,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.Sound; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; @@ -135,7 +137,7 @@ public class EditableGuildAdmin extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("leave")) { playerData.getGuild().removeMember(playerData.getUniqueId()); @@ -184,11 +186,11 @@ public class EditableGuildAdmin extends EditableInventory { }); } - if (item.getFunction().equals("member") && event.getAction() == InventoryAction.PICKUP_HALF) { + if (item.getFunction().equals("member") && context.getClickType() == ClickType.RIGHT) { if (!playerData.getGuild().getOwner().equals(playerData.getUniqueId())) return; - OfflinePlayer target = Bukkit.getOfflinePlayer(UUID.fromString(event.getCurrentItem().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING))); + OfflinePlayer target = Bukkit.getOfflinePlayer(UUID.fromString(context.getItemStack().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING))); if (target.equals(player)) return; diff --git a/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildCreation.java b/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildCreation.java index 1e3d9c1b..86f66565 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildCreation.java +++ b/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildCreation.java @@ -4,6 +4,7 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.util.input.ChatInput; import net.Indyuce.mmocore.api.util.input.PlayerInput; import net.Indyuce.mmocore.gui.api.GeneratedInventory; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.api.player.PlayerData; @@ -35,10 +36,8 @@ public class EditableGuildCreation extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { - if (event.getInventory() != event.getClickedInventory()) - return; - + public void whenClicked(InventoryClickContext context, InventoryItem item) { + if (item.getFunction().equals("create")) { new ChatInput(player, PlayerInput.InputType.GUILD_CREATION_TAG, (input) -> { if(MMOCore.plugin.dataProvider.getGuildManager().getConfig().shouldUppercaseTags()) diff --git a/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildView.java b/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildView.java index cc87f854..79f032da 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildView.java +++ b/src/main/java/net/Indyuce/mmocore/gui/social/guild/EditableGuildView.java @@ -4,6 +4,7 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.util.input.ChatInput; import net.Indyuce.mmocore.api.util.input.PlayerInput; import net.Indyuce.mmocore.gui.api.GeneratedInventory; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.api.player.OfflinePlayerData; @@ -15,6 +16,7 @@ import org.apache.commons.lang.Validate; import org.bukkit.*; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; @@ -161,7 +163,7 @@ public class EditableGuildView extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + 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); @@ -232,11 +234,11 @@ public class EditableGuildView extends EditableInventory { }); } - if (item.getFunction().equals("member") && event.getAction() == InventoryAction.PICKUP_HALF) { + if (item.getFunction().equals("member") && context.getClickType() == ClickType.RIGHT) { if (!playerData.getGuild().getOwner().equals(playerData.getUniqueId())) return; - String tag = event.getCurrentItem().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING); + String tag = context.getItemStack().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING); if (tag == null || tag.isEmpty()) return; diff --git a/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyCreation.java b/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyCreation.java index 5cfdb14f..588ec384 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyCreation.java +++ b/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyCreation.java @@ -2,6 +2,7 @@ package net.Indyuce.mmocore.gui.social.party; 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 net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.api.player.PlayerData; @@ -32,9 +33,7 @@ public class EditablePartyCreation extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { - if (event.getInventory() != event.getClickedInventory()) - return; + public void whenClicked(InventoryClickContext context, InventoryItem item) { if (item.getFunction().equals("create")) { ((MMOCorePartyModule) MMOCore.plugin.partyModule).newRegisteredParty(playerData); diff --git a/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyView.java b/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyView.java index ea4fc39a..c2074cd3 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyView.java +++ b/src/main/java/net/Indyuce/mmocore/gui/social/party/EditablePartyView.java @@ -1,20 +1,22 @@ package net.Indyuce.mmocore.gui.social.party; import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.util.input.ChatInput; import net.Indyuce.mmocore.api.util.input.PlayerInput; +import net.Indyuce.mmocore.gui.api.GeneratedInventory; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; +import net.Indyuce.mmocore.gui.api.item.InventoryItem; +import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; +import net.Indyuce.mmocore.api.player.PlayerData; 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.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; -import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.party.provided.Party; import org.apache.commons.lang.Validate; import org.bukkit.*; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; @@ -131,7 +133,7 @@ public class EditablePartyView extends EditableInventory { } @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { + public void whenClicked(InventoryClickContext context, InventoryItem item) { Party party = (Party) playerData.getParty(); if (item.getFunction().equals("leave")) { @@ -188,11 +190,11 @@ public class EditablePartyView extends EditableInventory { }); } - if (item.getFunction().equals("member") && event.getAction() == InventoryAction.PICKUP_HALF) { + if (item.getFunction().equals("member") && context.getClickType() == ClickType.RIGHT) { if (!party.getOwner().equals(playerData)) return; - OfflinePlayer target = Bukkit.getOfflinePlayer(UUID.fromString(event.getCurrentItem().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING))); + OfflinePlayer target = Bukkit.getOfflinePlayer(UUID.fromString(context.getItemStack().getItemMeta().getPersistentDataContainer().get(UUID_NAMESPACEDKEY, PersistentDataType.STRING))); if (target.equals(player)) return; diff --git a/src/main/java/net/Indyuce/mmocore/listener/PlayerListener.java b/src/main/java/net/Indyuce/mmocore/listener/PlayerListener.java index c3b074f3..a5225c0b 100644 --- a/src/main/java/net/Indyuce/mmocore/listener/PlayerListener.java +++ b/src/main/java/net/Indyuce/mmocore/listener/PlayerListener.java @@ -7,6 +7,7 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource; +import net.Indyuce.mmocore.gui.api.InventoryClickContext; import net.Indyuce.mmocore.gui.api.PluginInventory; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -38,8 +39,15 @@ public class PlayerListener implements Listener { // Register custom inventory clicks @EventHandler public void b(InventoryClickEvent event) { - if (event.getInventory().getHolder() instanceof PluginInventory) - ((PluginInventory) event.getInventory().getHolder()).whenClicked(event); + if (event.getInventory().getHolder() instanceof PluginInventory) { + int slot = event.getRawSlot(); + if (event.getCurrentItem() != null && event.getCurrentItem().getItemMeta() != null) + + + ((PluginInventory) event.getInventory().getHolder()) + .whenClicked(new InventoryClickContext(slot,event.getCurrentItem(),event.getClick(),event)); + + } } // Register custom inventory close effect diff --git a/src/main/java/net/Indyuce/mmocore/listener/bungee/GetMMOCorePlayerListener.java b/src/main/java/net/Indyuce/mmocore/listener/bungee/GetMMOCorePlayerListener.java deleted file mode 100644 index 81e40242..00000000 --- a/src/main/java/net/Indyuce/mmocore/listener/bungee/GetMMOCorePlayerListener.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.Indyuce.mmocore.listener.bungee; - -import com.google.common.io.ByteArrayDataInput; -import com.google.common.io.ByteStreams; -import org.bukkit.entity.Player; -import org.bukkit.plugin.messaging.PluginMessageListener; - -import java.util.UUID; - -public class GetMMOCorePlayerListener implements PluginMessageListener { - @Override - public void onPluginMessageReceived( String channel, Player player, byte[] bytes) { - if(!channel.equals("give_mmocore_player")) - return; - ByteArrayDataInput input= ByteStreams.newDataInput(bytes); - UUID uuid=UUID.fromString(input.readUTF()); - String Json=input.readUTF(); - } - - -} diff --git a/src/main/java/net/Indyuce/mmocore/loot/droptable/DropTable.java b/src/main/java/net/Indyuce/mmocore/loot/droptable/DropTable.java index ffc90a61..4e37479d 100644 --- a/src/main/java/net/Indyuce/mmocore/loot/droptable/DropTable.java +++ b/src/main/java/net/Indyuce/mmocore/loot/droptable/DropTable.java @@ -11,6 +11,7 @@ import net.Indyuce.mmocore.loot.chest.condition.Condition; import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance; import org.apache.commons.lang.Validate; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.ArmorStand; import org.bukkit.inventory.ItemStack; import net.Indyuce.mmocore.loot.LootBuilder; @@ -30,7 +31,7 @@ public class DropTable extends PostLoadObject { public DropTable(String id) { super(null); - + ArmorStand armorStand; this.id = id; } diff --git a/src/main/java/net/Indyuce/mmocore/loot/droptable/dropitem/DropItem.java b/src/main/java/net/Indyuce/mmocore/loot/droptable/dropitem/DropItem.java index 17f10cb6..e33d778e 100644 --- a/src/main/java/net/Indyuce/mmocore/loot/droptable/dropitem/DropItem.java +++ b/src/main/java/net/Indyuce/mmocore/loot/droptable/dropitem/DropItem.java @@ -6,6 +6,7 @@ import net.Indyuce.mmocore.api.util.math.formula.RandomAmount; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.loot.LootBuilder; import io.lumine.mythic.lib.api.MMOLineConfig; +import org.bukkit.Bukkit; public abstract class DropItem { protected static final Random random = new Random(); @@ -14,6 +15,8 @@ public abstract class DropItem { private final double chance, weight; private final RandomAmount amount; + private static final double CHANCE_COEFFICIENT = 7. / 100; + public DropItem(MMOLineConfig config) { chance = config.args().length > 0 ? Double.parseDouble(config.args()[0]) : 1; amount = config.args().length > 1 ? new RandomAmount(config.args()[1]) : new RandomAmount(1, 1); @@ -36,6 +39,15 @@ public abstract class DropItem { return amount.calculateInt(); } + + + /** + * CHANCE stat = 0 | tier chances are unchanged + * CHANCE stat = +inf | uniform law for any drop item + * CHANCE stat = 100 | all tier chances are taken their square root + * + * @return The real weight of an item considering the player's CHANCE stat. + */ /** * CHANCE stat = 0 | tier chances are unchanged * CHANCE stat = +inf | uniform law for any drop item diff --git a/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java b/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java index 018c9a19..a835c594 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java @@ -133,6 +133,7 @@ public class MySQLPlayerDataManager extends PlayerDataManager { } } catch (SQLException e) { e.printStackTrace(); + cancel(); } }); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 0516bd3a..1fe51576 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,7 +5,7 @@ author: Indyuce description: ${project.description} loadbefore: [MMOItems] depend: [MythicLib] -softdepend: [Vault,MythicMobs,PlaceholderAPI,Residence,Citizens] +softdepend: [Vault,MythicMobs,PlaceholderAPI,Residence,Citizens,ProtocolLib] api-version: 1.13 commands: mmocore: