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 f2ed5051..9bb4c523 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java @@ -1,15 +1,11 @@ package net.Indyuce.mmocore.api.player; -import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.player.MMOPlayerData; import io.lumine.mythic.lib.player.TemporaryPlayerData; import io.lumine.mythic.lib.player.cooldown.CooldownMap; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.SoundEvent; -import net.Indyuce.mmocore.player.Unlockable; -import net.Indyuce.mmocore.waypoint.CostType; -import net.Indyuce.mmocore.waypoint.Waypoint; import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent; import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent; import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent; @@ -25,7 +21,6 @@ import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.quest.PlayerQuests; import net.Indyuce.mmocore.api.util.Closable; import net.Indyuce.mmocore.api.util.MMOCoreUtils; -import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; import net.Indyuce.mmocore.experience.EXPSource; import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.ExperienceTableClaimer; @@ -33,11 +28,14 @@ import net.Indyuce.mmocore.experience.PlayerProfessions; import net.Indyuce.mmocore.experience.droptable.ExperienceItem; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.guild.provided.Guild; +import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; import net.Indyuce.mmocore.party.AbstractParty; import net.Indyuce.mmocore.party.provided.Party; +import net.Indyuce.mmocore.player.Unlockable; import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.RegisteredSkill; import net.Indyuce.mmocore.skill.cast.SkillCastingHandler; +import net.Indyuce.mmocore.waypoint.Waypoint; import net.Indyuce.mmocore.waypoint.WaypointOption; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; @@ -88,8 +86,9 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc /** * Saves all the items that have been unlocked so far by - * the player. This can be used by other plugins by - * implementing the {@link Unlockable} interface + * the player. This is used for: + * - waypoints + * - skills * * @see {@link Unlockable} */ @@ -289,8 +288,11 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc return guild != null; } + /** + * @return If the item is unlocked by the player + */ public boolean hasUnlocked(Unlockable unlockable) { - throw new RuntimeException("Not implemented yet"); + return unlockedItems.contains(unlockable.getUnlockNamespacedKey()); } /** @@ -299,7 +301,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc * @return If the item was already unlocked when calling this method */ public boolean unlock(Unlockable unlockable) { - throw new RuntimeException("Not implemented yet"); + return unlockedItems.add(unlockable.getUnlockNamespacedKey()); } public void setLevel(int level) { diff --git a/src/main/java/net/Indyuce/mmocore/listener/LootableChestsListener.java b/src/main/java/net/Indyuce/mmocore/listener/LootableChestsListener.java index b7f837d3..06cdf5ad 100644 --- a/src/main/java/net/Indyuce/mmocore/listener/LootableChestsListener.java +++ b/src/main/java/net/Indyuce/mmocore/listener/LootableChestsListener.java @@ -1,22 +1,36 @@ package net.Indyuce.mmocore.listener; -import org.bukkit.block.Chest; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryCloseEvent; - import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.loot.chest.LootChest; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; public class LootableChestsListener implements Listener { - @EventHandler - public void a(InventoryCloseEvent event) { - if (!(event.getInventory().getHolder() instanceof Chest)) - return; - Chest chest = (Chest) event.getInventory().getHolder(); - LootChest lootChest = MMOCore.plugin.lootChests.getChest(chest.getLocation()); - if (lootChest != null) - lootChest.expire(true); - } + @EventHandler + public void expireOnClose(InventoryCloseEvent event) { + if (!(event.getInventory().getHolder() instanceof Chest)) + return; + + Chest chest = (Chest) event.getInventory().getHolder(); + LootChest lootChest = MMOCore.plugin.lootChests.getChest(chest.getLocation()); + if (lootChest != null) + lootChest.expire(true); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH) + public void noBreaking(BlockBreakEvent event) { + Block block = event.getBlock(); + if (block.getType() == Material.CHEST) { + LootChest lootChest = MMOCore.plugin.lootChests.getChest(block.getLocation()); + if (lootChest != null) + event.setCancelled(true); + } + } } diff --git a/src/main/java/net/Indyuce/mmocore/loot/chest/LootChest.java b/src/main/java/net/Indyuce/mmocore/loot/chest/LootChest.java index 8c6d2ed3..b5d636e7 100644 --- a/src/main/java/net/Indyuce/mmocore/loot/chest/LootChest.java +++ b/src/main/java/net/Indyuce/mmocore/loot/chest/LootChest.java @@ -2,6 +2,7 @@ package net.Indyuce.mmocore.loot.chest; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.SoundEvent; +import net.Indyuce.mmocore.util.item.HashableLocation; import org.apache.commons.lang.Validate; import org.bukkit.Location; import org.bukkit.Material; @@ -52,7 +53,7 @@ public class LootChest { public boolean hasPlayerNearby() { for (Player player : block.loc.getWorld().getPlayers()) - if (player.getLocation().distanceSquared(block.loc) < 625) + if (player.getLocation().distanceSquared(block.loc.bukkit()) < 625) return true; return false; } @@ -78,8 +79,8 @@ public class LootChest { // If a player is responsible of closing the chest, close it with sound if (player) { - MMOCore.plugin.soundManager.getSound(SoundEvent.CLOSE_LOOT_CHEST).playAt(block.loc); - block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.clone().add(.5, .5, .5), 16, 0, 0, 0, .5); + MMOCore.plugin.soundManager.getSound(SoundEvent.CLOSE_LOOT_CHEST).playAt(block.loc.bukkit()); + block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.bukkit().add(.5, .5, .5), 16, 0, 0, 0, .5); } /* @@ -87,7 +88,7 @@ public class LootChest { * off and accumulate on the ground (+during dev phase) */ else - ((Chest) block.loc.getBlock().getState()).getBlockInventory().clear(); + ((Chest) block.loc.bukkit().getBlock().getState()).getBlockInventory().clear(); block.restore(); if (effectRunnable != null) @@ -97,22 +98,28 @@ public class LootChest { public static class ReplacedBlock { private final Material material; private final BlockData data; - private final Location loc; + private final HashableLocation loc; public ReplacedBlock(Block block) { this.material = block.getType(); this.data = block.getBlockData(); - this.loc = block.getLocation(); + this.loc = new HashableLocation(block.getLocation()); } + public HashableLocation getLocation() { + return loc; + } + + @Deprecated public boolean matches(Location loc) { - return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getBlockX() == loc.getBlockX() && this.loc.getBlockY() == loc.getBlockY() - && this.loc.getBlockZ() == loc.getBlockZ(); + return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getX() == loc.getBlockX() && this.loc.getY() == loc.getBlockY() + && this.loc.getZ() == loc.getBlockZ(); } public void restore() { - loc.getBlock().setType(material); - loc.getBlock().setBlockData(data); + Block block = loc.bukkit().getBlock(); + block.setType(material); + block.setBlockData(data); } } } diff --git a/src/main/java/net/Indyuce/mmocore/manager/LootChestManager.java b/src/main/java/net/Indyuce/mmocore/manager/LootChestManager.java index 4dab3230..c0cc59bc 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/LootChestManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/LootChestManager.java @@ -1,33 +1,36 @@ package net.Indyuce.mmocore.manager; -import java.util.*; -import java.util.logging.Level; - -import org.bukkit.Location; -import org.bukkit.configuration.file.FileConfiguration; - import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.ConfigFile; import net.Indyuce.mmocore.loot.chest.LootChest; import net.Indyuce.mmocore.loot.chest.LootChestRegion; +import net.Indyuce.mmocore.util.item.HashableLocation; +import org.bukkit.Location; +import org.bukkit.configuration.file.FileConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.logging.Level; + public class LootChestManager implements MMOCoreManager { - /** - * Active loot chests in the server - */ - private final Set active = new HashSet<>(); + /** + * Active loot chests in the server + */ + private final Map active = new HashMap<>(); - /** - * Registered loot chest regions - */ - private final Map regions = new HashMap<>(); + /** + * Registered loot chest regions + */ + private final Map regions = new HashMap<>(); - public boolean hasRegion(String id) { - return regions.containsKey(id); - } + public boolean hasRegion(String id) { + return regions.containsKey(id); + } /** * @return Region with specific identifier @@ -38,48 +41,42 @@ public class LootChestManager implements MMOCoreManager { return Objects.requireNonNull(regions.get(id), "Could not find region with ID '" + id + "'"); } - public Collection getRegions() { - return regions.values(); - } + public Collection getRegions() { + return regions.values(); + } - public Set getActive() { - return active; - } + public Collection getActive() { + return active.values(); + } - public void register(LootChest chest) { - active.add(chest); - } + public void register(LootChest chest) { + active.put(chest.getBlock().getLocation(), chest); + } - public void unregister(LootChest chest) { - active.remove(chest); - } + public void unregister(LootChest chest) { + active.remove(chest.getBlock().getLocation()); + } - @Nullable - public LootChest getChest(Location loc) { + @Nullable + public LootChest getChest(Location loc) { + return active.get(new HashableLocation(loc)); + } - for (LootChest chest : active) - if (chest.getBlock().matches(loc)) - return chest; + @Override + public void initialize(boolean clearBefore) { + if (clearBefore) { + regions.values().forEach(region -> region.getRunnable().cancel()); + regions.clear(); + } - return null; - } - - @Override - public void initialize(boolean clearBefore) { - if (clearBefore) { - regions.values().forEach(region -> region.getRunnable().cancel()); - regions.clear(); - } - - FileConfiguration config = new ConfigFile("loot-chests").getConfig(); - for (String key : config.getKeys(false)) - try { - LootChestRegion region = new LootChestRegion(config.getConfigurationSection(key)); - regions.put(region.getId(), region); - } catch (IllegalArgumentException exception) { - MMOCore.plugin.getLogger().log(Level.WARNING, - "An error occured while trying to load loot chest region '" + key + "': " + exception.getMessage()); - } - - } + FileConfiguration config = new ConfigFile("loot-chests").getConfig(); + for (String key : config.getKeys(false)) + try { + LootChestRegion region = new LootChestRegion(config.getConfigurationSection(key)); + regions.put(region.getId(), region); + } catch (IllegalArgumentException exception) { + MMOCore.plugin.getLogger().log(Level.WARNING, + "An error occured while trying to load loot chest region '" + key + "': " + exception.getMessage()); + } + } } diff --git a/src/main/java/net/Indyuce/mmocore/player/Unlockable.java b/src/main/java/net/Indyuce/mmocore/player/Unlockable.java index 6940d1a1..9349f308 100644 --- a/src/main/java/net/Indyuce/mmocore/player/Unlockable.java +++ b/src/main/java/net/Indyuce/mmocore/player/Unlockable.java @@ -3,8 +3,8 @@ package net.Indyuce.mmocore.player; import net.Indyuce.mmocore.api.player.PlayerData; /** - * Some item that can be unlocked. ALl unlockable are saved in the same list in - * the player data. This useful list can be used for: + * Some item that can be unlocked. All unlockables are saved in the + * same list in the player data. This useful list can be used for: * - waypoints * - skill tree nodes * - skills using skill books? TODO @@ -15,8 +15,8 @@ import net.Indyuce.mmocore.api.player.PlayerData; public interface Unlockable { /** - * Format being used is the minecraft's default - * namespaced key format, e.g "skill_tree:strength_1_5" + * Format being used is the minecraft's default namespaced + * key format, e.g "skill_tree:strength_1_5" for readability */ String getUnlockNamespacedKey(); } diff --git a/src/main/java/net/Indyuce/mmocore/skill/ClassSkill.java b/src/main/java/net/Indyuce/mmocore/skill/ClassSkill.java index 1d72842b..841c76a2 100644 --- a/src/main/java/net/Indyuce/mmocore/skill/ClassSkill.java +++ b/src/main/java/net/Indyuce/mmocore/skill/ClassSkill.java @@ -4,6 +4,7 @@ import io.lumine.mythic.lib.api.player.EquipmentSlot; import io.lumine.mythic.lib.player.cooldown.CooldownObject; import io.lumine.mythic.lib.player.modifier.ModifierSource; import io.lumine.mythic.lib.player.skill.PassiveSkill; +import io.lumine.mythic.lib.skill.custom.condition.Condition; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue; import net.Indyuce.mmocore.api.util.math.formula.LinearValue; @@ -17,6 +18,9 @@ public class ClassSkill implements CooldownObject { private final int unlockLevel, maxSkillLevel; private final Map modifiers = new HashMap<>(); + @Deprecated + private final Set unlockConditions = new HashSet<>(); + /** * Class used to save information about skills IN A CLASS CONTEXT i.e at * which level the skill can be unlocked, etc. diff --git a/src/main/java/net/Indyuce/mmocore/skill/RegisteredSkill.java b/src/main/java/net/Indyuce/mmocore/skill/RegisteredSkill.java index 8fb2b970..0d5ada32 100644 --- a/src/main/java/net/Indyuce/mmocore/skill/RegisteredSkill.java +++ b/src/main/java/net/Indyuce/mmocore/skill/RegisteredSkill.java @@ -5,6 +5,7 @@ import io.lumine.mythic.lib.skill.handler.SkillHandler; import io.lumine.mythic.lib.skill.trigger.TriggerType; import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.math.formula.LinearValue; +import net.Indyuce.mmocore.player.Unlockable; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -15,7 +16,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; -public class RegisteredSkill { +public class RegisteredSkill implements Unlockable { private final SkillHandler handler; private final String name; private final Map defaultModifiers = new HashMap<>(); @@ -45,6 +46,11 @@ public class RegisteredSkill { this.triggerType = triggerType; } + @Override + public String getUnlockNamespacedKey() { + return "registered_skill:" + handler.getId().toLowerCase(); + } + public SkillHandler getHandler() { return handler; } diff --git a/src/main/java/net/Indyuce/mmocore/tree/modifier/UnlockSkillModifier.java b/src/main/java/net/Indyuce/mmocore/tree/modifier/UnlockSkillModifier.java new file mode 100644 index 00000000..570b8ab2 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/tree/modifier/UnlockSkillModifier.java @@ -0,0 +1,28 @@ +package net.Indyuce.mmocore.tree.modifier; + +import io.lumine.mythic.lib.api.player.EquipmentSlot; +import io.lumine.mythic.lib.api.player.MMOPlayerData; +import io.lumine.mythic.lib.player.modifier.ModifierSource; +import io.lumine.mythic.lib.player.modifier.PlayerModifier; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.skill.RegisteredSkill; +import org.apache.commons.lang.NotImplementedException; + +public class UnlockSkillModifier extends PlayerModifier { + private RegisteredSkill unlocked = null; + + public UnlockSkillModifier(String key, EquipmentSlot slot, ModifierSource source) { + super(key, slot, source); + } + + @Override + public void register(MMOPlayerData mmoPlayerData) { + PlayerData playerData = PlayerData.get(mmoPlayerData.getUniqueId()); + // playerData.unlock(unlocked); + } + + @Override + public void unregister(MMOPlayerData mmoPlayerData) { + throw new NotImplementedException(""); + } +} diff --git a/src/main/java/net/Indyuce/mmocore/util/item/HashableLocation.java b/src/main/java/net/Indyuce/mmocore/util/item/HashableLocation.java new file mode 100644 index 00000000..1e910bbd --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/util/item/HashableLocation.java @@ -0,0 +1,51 @@ +package net.Indyuce.mmocore.util.item; + +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.Objects; + +public class HashableLocation { + private final World world; + private final int x, y, z; + + public HashableLocation(Location loc) { + this.world = loc.getWorld(); + this.x = loc.getBlockX(); + this.y = loc.getBlockY(); + this.z = loc.getBlockZ(); + } + + public World getWorld() { + return world; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getZ() { + return z; + } + + public Location bukkit() { + return new Location(world, x, y, z); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HashableLocation that = (HashableLocation) o; + return x == that.x && y == that.y && z == that.z && world.equals(that.world); + } + + @Override + public int hashCode() { + return Objects.hash(world, x, y, z); + } +} \ No newline at end of file