diff --git a/build.gradle b/build.gradle index f3185b02..7cdcca31 100644 --- a/build.gradle +++ b/build.gradle @@ -46,12 +46,17 @@ allprojects { onlyIf { !sourceSets.main.allSource.files.isEmpty() } } + shadowJar { + relocate('com.willfp.libreforge', 'com.willfp.ecoenchants.libreforge') + } + compileJava { onlyIf { !sourceSets.main.allSource.files.isEmpty() } } dependencies { compileOnly 'com.willfp:eco:6.17.1' + implementation 'com.willfp:libreforge:2.13.0' compileOnly 'org.jetbrains:annotations:19.0.0' diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/EcoEnchantsPlugin.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/EcoEnchantsPlugin.java index 2c40c304..8fb2d612 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/EcoEnchantsPlugin.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/EcoEnchantsPlugin.java @@ -8,12 +8,15 @@ import com.willfp.eco.core.integrations.IntegrationLoader; import com.willfp.eco.util.TelekinesisUtils; import com.willfp.ecoenchants.command.CommandEcoEnchants; import com.willfp.ecoenchants.command.CommandEnchantinfo; +import com.willfp.ecoenchants.config.CustomEnchantsYml; import com.willfp.ecoenchants.config.RarityYml; import com.willfp.ecoenchants.config.TargetYml; import com.willfp.ecoenchants.config.VanillaEnchantsYml; import com.willfp.ecoenchants.display.EnchantDisplay; import com.willfp.ecoenchants.enchantments.EcoEnchant; import com.willfp.ecoenchants.enchantments.EcoEnchants; +import com.willfp.ecoenchants.enchantments.custom.CustomEnchantEnableListeners; +import com.willfp.ecoenchants.enchantments.custom.CustomEnchantLookup; import com.willfp.ecoenchants.enchantments.support.merging.anvil.AnvilListeners; import com.willfp.ecoenchants.enchantments.support.merging.grindstone.GrindstoneListeners; import com.willfp.ecoenchants.enchantments.support.obtaining.EnchantingListeners; @@ -26,6 +29,7 @@ import com.willfp.ecoenchants.integrations.mythicmobs.MythicMobsManager; import com.willfp.ecoenchants.integrations.mythicmobs.plugins.IntegrationMythicMobs; import com.willfp.ecoenchants.integrations.registration.RegistrationManager; import com.willfp.ecoenchants.integrations.registration.plugins.IntegrationEssentials; +import com.willfp.libreforge.LibReforge; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.event.HandlerList; @@ -33,6 +37,7 @@ import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -59,20 +64,30 @@ public class EcoEnchantsPlugin extends EcoPlugin { */ private final VanillaEnchantsYml vanillaEnchantsYml; + /** + * CustomEnchants.yml. + */ + private final CustomEnchantsYml customEnchantsYml; + /** * Internal constructor called by bukkit on plugin load. */ public EcoEnchantsPlugin() { super(490, 7666, "com.willfp.ecoenchants.proxy", "&a", true); + LibReforge.init(this); instance = this; rarityYml = new RarityYml(this); targetYml = new TargetYml(this); vanillaEnchantsYml = new VanillaEnchantsYml(this); + customEnchantsYml = new CustomEnchantsYml(this); + + LibReforge.registerJavaHolderProvider(player -> new ArrayList<>(CustomEnchantLookup.provideLevels(player))); } @Override protected void handleEnable() { + LibReforge.enable(this); this.getLogger().info(EcoEnchants.values().size() + " Enchantments Loaded"); TelekinesisUtils.registerTest(player -> FastItemStack.wrap(player.getInventory().getItemInMainHand()).getLevelOnItem(EcoEnchants.TELEKINESIS, false) > 0); @@ -80,6 +95,7 @@ public class EcoEnchantsPlugin extends EcoPlugin { @Override protected void handleDisable() { + LibReforge.disable(this); for (World world : Bukkit.getServer().getWorlds()) { world.getPopulators().removeIf(blockPopulator -> blockPopulator instanceof LootPopulator); } @@ -87,6 +103,7 @@ public class EcoEnchantsPlugin extends EcoPlugin { @Override protected void handleReload() { + LibReforge.reload(this); this.getDisplayModule().update(); for (EcoEnchant enchant : EcoEnchants.values()) { HandlerList.unregisterAll(enchant); @@ -142,7 +159,8 @@ public class EcoEnchantsPlugin extends EcoPlugin { new AnvilListeners(this), new WatcherTriggers(this), new VillagerListeners(this), - new ItemConversions(this) + new ItemConversions(this), + new CustomEnchantEnableListeners(this) ); } @@ -200,4 +218,13 @@ public class EcoEnchantsPlugin extends EcoPlugin { public VanillaEnchantsYml getVanillaEnchantsYml() { return this.vanillaEnchantsYml; } + + /** + * Get customenchants.yml + * + * @return customenchants.yml. + */ + public CustomEnchantsYml getCustomEnchantsYml() { + return customEnchantsYml; + } } diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/CustomEnchantsYml.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/CustomEnchantsYml.java new file mode 100644 index 00000000..eaf5720b --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/CustomEnchantsYml.java @@ -0,0 +1,17 @@ +package com.willfp.ecoenchants.config; + +import com.willfp.eco.core.EcoPlugin; +import com.willfp.eco.core.config.BaseConfig; +import com.willfp.eco.core.config.ConfigType; +import org.jetbrains.annotations.NotNull; + +public class CustomEnchantsYml extends BaseConfig { + /** + * Instantiate target.yml. + * + * @param plugin Instance of EcoEnchants. + */ + public CustomEnchantsYml(@NotNull final EcoPlugin plugin) { + super("customenchants", plugin, true, ConfigType.YAML); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/TargetYml.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/TargetYml.java index 185ea490..dd62ed8f 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/TargetYml.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/TargetYml.java @@ -3,6 +3,7 @@ package com.willfp.ecoenchants.config; import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.config.BaseConfig; import com.willfp.eco.core.config.ConfigType; +import com.willfp.ecoenchants.enchantments.meta.EnchantmentTarget; import org.bukkit.Material; import org.jetbrains.annotations.NotNull; @@ -46,4 +47,22 @@ public class TargetYml extends BaseConfig { return materials; } + + /** + * Get the slot for a target name. + * + * @param target The target. + * @return The slot, or {@link com.willfp.ecoenchants.enchantments.meta.EnchantmentTarget.Slot#ANY} + */ + public EnchantmentTarget.Slot getSlot(@NotNull final String target) { + for (String str : this.getStrings("targets." + target)) { + if (str.startsWith("slot:")) { + return EnchantmentTarget.Slot.valueOf( + str.replace("slot:", "").toUpperCase() + ); + } + } + + return EnchantmentTarget.Slot.ANY; + } } diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/configs/BaseEnchantmentConfig.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/configs/BaseEnchantmentConfig.java new file mode 100644 index 00000000..760ee7d8 --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/configs/BaseEnchantmentConfig.java @@ -0,0 +1,24 @@ +package com.willfp.ecoenchants.config.configs; + +import com.willfp.eco.core.EcoPlugin; +import com.willfp.eco.core.config.ConfigType; +import com.willfp.eco.core.config.ExtendableConfig; +import com.willfp.ecoenchants.enchantments.EcoEnchant; +import org.jetbrains.annotations.NotNull; + +public class BaseEnchantmentConfig extends ExtendableConfig { + /** + * Instantiate a new config for an enchantment. + * + * @param name The name of the config. + * @param source The class in the jar where the config is contained. + * @param plugin The provider of the enchantment. + * @param enchant The enchantment. + */ + public BaseEnchantmentConfig(@NotNull final String name, + @NotNull final Class source, + @NotNull final EcoEnchant enchant, + @NotNull final EcoPlugin plugin) { + super(name, true, plugin, source, "enchants/" + enchant.getType().getName() + "/", ConfigType.YAML); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/configs/EnchantmentConfig.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/configs/EnchantmentConfig.java index ab8fe9d1..3b6b25d5 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/configs/EnchantmentConfig.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/config/configs/EnchantmentConfig.java @@ -1,8 +1,9 @@ package com.willfp.ecoenchants.config.configs; import com.willfp.eco.core.EcoPlugin; -import com.willfp.eco.core.config.ConfigType; -import com.willfp.eco.core.config.ExtendableConfig; +import com.willfp.eco.core.config.interfaces.Config; +import com.willfp.eco.core.config.interfaces.LoadableConfig; +import com.willfp.eco.core.config.wrapper.ConfigWrapper; import com.willfp.ecoenchants.enchantments.EcoEnchant; import com.willfp.ecoenchants.enchantments.EcoEnchants; import com.willfp.ecoenchants.enchantments.meta.EnchantmentRarity; @@ -18,7 +19,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -public class EnchantmentConfig extends ExtendableConfig { +public class EnchantmentConfig extends ConfigWrapper { /** * The name of the config. */ @@ -40,16 +41,16 @@ public class EnchantmentConfig extends ExtendableConfig { /** * Instantiate a new config for an enchantment. * - * @param name The name of the config. - * @param source The class in the jar where the config is contained. - * @param plugin The provider of the enchantment. - * @param enchant The enchantment. + * @param handle The handle. + * @param name The config name. + * @param enchant The enchant. + * @param plugin Instance of EcoEnchants. */ - public EnchantmentConfig(@NotNull final String name, - @NotNull final Class source, + public EnchantmentConfig(@NotNull final Config handle, + @NotNull final String name, @NotNull final EcoEnchant enchant, @NotNull final EcoPlugin plugin) { - super(name, true, plugin, source, "enchants/" + enchant.getType().getName() + "/", ConfigType.YAML); + super(handle); this.name = name; this.enchant = enchant; this.plugin = plugin; @@ -119,7 +120,9 @@ public class EnchantmentConfig extends ExtendableConfig { this.getPlugin().getLangYml().set("enchantments." + this.getEnchant().getKey().getKey(), null); try { - this.save(); + if (this.getHandle() instanceof LoadableConfig loadableConfig) { + loadableConfig.save(); + } this.getPlugin().getLangYml().save(); this.getPlugin().getLangYml().clearCache(); } catch (IOException e) { diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchant.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchant.java index 6c06a442..a8eb1613 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchant.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchant.java @@ -6,6 +6,7 @@ import com.willfp.eco.core.requirement.Requirement; import com.willfp.eco.core.requirement.Requirements; import com.willfp.eco.util.StringUtils; import com.willfp.ecoenchants.EcoEnchantsPlugin; +import com.willfp.ecoenchants.config.configs.BaseEnchantmentConfig; import com.willfp.ecoenchants.config.configs.EnchantmentConfig; import com.willfp.ecoenchants.display.EnchantmentCache; import com.willfp.ecoenchants.enchantments.meta.EnchantmentRarity; @@ -189,7 +190,7 @@ public abstract class EcoEnchant extends Enchantment implements Listener, Watche this.type = type; this.permissionName = key.replace("_", ""); - this.config = new EnchantmentConfig(this.permissionName, this.getClass(), this, this.getPlugin()); + this.config = generateConfig(); if (Bukkit.getPluginManager().getPermission("ecoenchants.fromtable." + permissionName) == null) { Permission permission = new Permission( @@ -209,7 +210,7 @@ public abstract class EcoEnchant extends Enchantment implements Listener, Watche return; } - enabled = config.getBool("enabled"); + enabled = Objects.requireNonNullElse(config.getBoolOrNull("enabled"), true); if (!this.isEnabled() && this.getPlugin().getConfigYml().getBool("advanced.hard-disable.enabled")) { return; @@ -220,6 +221,20 @@ public abstract class EcoEnchant extends Enchantment implements Listener, Watche EcoEnchants.addNewEcoEnchant(this); } + protected EnchantmentConfig generateConfig() { + return new EnchantmentConfig( + new BaseEnchantmentConfig( + this.permissionName, + this.getClass(), + this, + this.getPlugin() + ), + this.permissionName, + this, + this.getPlugin() + ); + } + /** * Update the enchantment based off config values. * This can be overridden but may lead to unexpected behavior. diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchants.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchants.java index ee3e33f3..e83161e9 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchants.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchants.java @@ -6,6 +6,7 @@ import com.google.common.collect.ImmutableList; import com.willfp.eco.core.config.updating.ConfigUpdater; import com.willfp.eco.core.fast.FastItemStack; import com.willfp.ecoenchants.EcoEnchantsPlugin; +import com.willfp.ecoenchants.enchantments.custom.CustomEcoEnchants; import com.willfp.ecoenchants.enchantments.ecoenchants.artifact.AngerArtifact; import com.willfp.ecoenchants.enchantments.ecoenchants.artifact.AshArtifact; import com.willfp.ecoenchants.enchantments.ecoenchants.artifact.CloudsArtifact; @@ -565,6 +566,8 @@ public class EcoEnchants { */ @ConfigUpdater public static void update(@NotNull final EcoEnchantsPlugin plugin) { + CustomEcoEnchants.update(plugin); + for (EcoEnchant ecoEnchant : new HashSet<>(values())) { ecoEnchant.update(); } diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchant.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchant.java new file mode 100644 index 00000000..37401823 --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchant.java @@ -0,0 +1,78 @@ +package com.willfp.ecoenchants.enchantments.custom; + +import com.willfp.eco.core.config.interfaces.Config; +import com.willfp.ecoenchants.config.configs.EnchantmentConfig; +import com.willfp.ecoenchants.enchantments.EcoEnchant; +import com.willfp.ecoenchants.enchantments.meta.EnchantmentType; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class CustomEcoEnchant extends EcoEnchant { + /** + * The config. + */ + private final Config config; + + /** + * The levels. + */ + private final Map levels; + + /** + * Create custom EcoEnchant. + * + * @param config The config. + */ + public CustomEcoEnchant(@NotNull final Config config) { + super( + config.getString("id"), EnchantmentType.getByName(config.getString("type")) + ); + this.config = config; + + this.levels = new HashMap<>(); + + int i = 1; + for (Config levelConfig : this.config.getSubsections("levels")) { + levels.put(i, new CustomEcoEnchantLevel(this, levelConfig)); + i++; + } + } + + /** + * Get the level. + * + * @param level The level. + * @return The level. + */ + public CustomEcoEnchantLevel getLevel(final int level) { + return levels.get(level); + } + + /** + * Get the levels. + * + * @return The levels. + */ + public Set getLevels() { + return new HashSet<>(levels.values()); + } + + @Override + protected EnchantmentConfig generateConfig() { + return new EnchantmentConfig( + this.config, + this.getPermissionName(), + this, + this.getPlugin() + ); + } + + @Override + public int getMaxLevel() { + return this.levels.size(); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchantLevel.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchantLevel.java new file mode 100644 index 00000000..b1bb368c --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchantLevel.java @@ -0,0 +1,63 @@ +package com.willfp.ecoenchants.enchantments.custom; + +import com.willfp.eco.core.config.interfaces.Config; +import com.willfp.ecoenchants.enchantments.EcoEnchant; +import com.willfp.libreforge.Holder; +import com.willfp.libreforge.conditions.Conditions; +import com.willfp.libreforge.conditions.ConfiguredCondition; +import com.willfp.libreforge.effects.ConfiguredEffect; +import com.willfp.libreforge.effects.Effects; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +public class CustomEcoEnchantLevel implements Holder { + /** + * The parent EcoEnchant. + */ + @Getter + private final EcoEnchant parent; + + /** + * The conditions. + */ + private final Set conditions = new HashSet<>(); + + /** + * The effects. + */ + private final Set effects = new HashSet<>(); + + /** + * Create custom EcoEnchant level. + * + * @param parent The parent. + * @param config The config. + */ + public CustomEcoEnchantLevel(@NotNull final EcoEnchant parent, + @NotNull final Config config) { + this.parent = parent; + + for (Config cfg : config.getSubsections("effects")) { + effects.add(Effects.compile(cfg, "Custom EcoEnchant ID " + parent.getKey().getKey())); + } + + for (Config cfg : config.getSubsections("conditions")) { + conditions.add(Conditions.compile(cfg, "Custom EcoEnchant ID " + parent.getKey().getKey())); + } + } + + @NotNull + @Override + public Set getConditions() { + return conditions; + } + + @NotNull + @Override + public Set getEffects() { + return effects; + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchants.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchants.java new file mode 100644 index 00000000..9e49a59d --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEcoEnchants.java @@ -0,0 +1,36 @@ +package com.willfp.ecoenchants.enchantments.custom; + +import com.willfp.eco.core.config.interfaces.Config; +import com.willfp.ecoenchants.EcoEnchantsPlugin; +import com.willfp.ecoenchants.enchantments.EcoEnchant; +import com.willfp.ecoenchants.enchantments.EcoEnchants; +import com.willfp.ecoenchants.enchantments.util.EnchantmentUtils; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +@UtilityClass +public class CustomEcoEnchants { + /** + * Custom EcoEnchants. + */ + private static final Set VALUES = new HashSet<>(); + + /** + * Update the map. + * + * @param plugin Instance of EcoEnchants. + */ + public static void update(@NotNull final EcoEnchantsPlugin plugin) { + for (EcoEnchant enchant : VALUES) { + EcoEnchants.removeEcoEnchant(enchant); + EnchantmentUtils.unregister(enchant); + } + + for (Config cfg : plugin.getCustomEnchantsYml().getSubsections("enchants")) { + VALUES.add(new CustomEcoEnchant(cfg)); + } + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEnchantEnableListeners.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEnchantEnableListeners.java new file mode 100644 index 00000000..c5bb62a6 --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEnchantEnableListeners.java @@ -0,0 +1,147 @@ +package com.willfp.ecoenchants.enchantments.custom; + +import com.willfp.eco.core.EcoPlugin; +import com.willfp.eco.core.PluginDependent; +import com.willfp.eco.core.events.ArmorChangeEvent; +import com.willfp.ecoenchants.enchantments.EcoEnchant; +import com.willfp.ecoenchants.enchantments.EcoEnchants; +import com.willfp.ecoenchants.enchantments.meta.EnchantmentTarget; +import com.willfp.libreforge.LibReforgeUtils; +import com.willfp.libreforge.effects.ConfiguredEffect; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityPickupItemEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.jetbrains.annotations.NotNull; + +public class CustomEnchantEnableListeners extends PluginDependent implements Listener { + /** + * Initialize new listeners and link them to a plugin. + * + * @param plugin The plugin to link to. + */ + public CustomEnchantEnableListeners(@NotNull final EcoPlugin plugin) { + super(plugin); + } + + /** + * Called on item pickup. + * + * @param event The event to listen for. + */ + @EventHandler + public void onItemPickup(@NotNull final EntityPickupItemEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + + if (!EnchantmentTarget.ALL.getMaterials().contains(event.getItem().getItemStack().getType())) { + return; + } + + refreshPlayer(player); + } + + /** + * Called on player join. + * + * @param event The event to listen for. + */ + @EventHandler + public void onPlayerJoin(@NotNull final PlayerJoinEvent event) { + refresh(); + } + + /** + * Called on player leave. + * + * @param event The event to listen for. + */ + @EventHandler + public void onPlayerLeave(@NotNull final PlayerQuitEvent event) { + refresh(); + + Player player = event.getPlayer(); + + for (EcoEnchant value : EcoEnchants.values()) { + if (!(value instanceof CustomEcoEnchant enchant)) { + continue; + } + + for (CustomEcoEnchantLevel level : enchant.getLevels()) { + for (ConfiguredEffect effect : level.getEffects()) { + effect.getEffect().disableForPlayer(player); + } + } + } + } + + /** + * Called on item drop. + * + * @param event The event to listen for. + */ + @EventHandler + public void onInventoryDrop(@NotNull final PlayerDropItemEvent event) { + if (!EnchantmentTarget.ALL.getMaterials().contains(event.getItemDrop().getItemStack().getType())) { + return; + } + + refreshPlayer(event.getPlayer()); + } + + /** + * Called on slot change. + * + * @param event The event to listen for. + */ + @EventHandler + public void onChangeSlot(@NotNull final PlayerItemHeldEvent event) { + refreshPlayer(event.getPlayer()); + + this.getPlugin().getScheduler().run(() -> refreshPlayer(event.getPlayer())); + } + + /** + * Called on armor change. + * + * @param event The event to listen for. + */ + @EventHandler + public void onArmorChange(@NotNull final ArmorChangeEvent event) { + refreshPlayer(event.getPlayer()); + } + + /** + * Called on inventory click. + * + * @param event The event to listen for. + */ + @EventHandler + public void onInventoryClick(@NotNull final InventoryClickEvent event) { + if (!(event.getWhoClicked() instanceof Player)) { + return; + } + + refreshPlayer((Player) event.getWhoClicked()); + } + + /** + * Force refresh all online players. + *

+ * This is a very expensive method. + */ + public void refresh() { + this.getPlugin().getServer().getOnlinePlayers().forEach(this::refreshPlayer); + } + + private void refreshPlayer(@NotNull final Player player) { + CustomEnchantLookup.clearCache(player); + LibReforgeUtils.updateEffects(player); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEnchantLookup.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEnchantLookup.java new file mode 100644 index 00000000..1e189411 --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/custom/CustomEnchantLookup.java @@ -0,0 +1,155 @@ +package com.willfp.ecoenchants.enchantments.custom; + +import com.willfp.eco.core.EcoPlugin; +import com.willfp.ecoenchants.EcoEnchantsPlugin; +import com.willfp.ecoenchants.enchantments.EcoEnchant; +import com.willfp.ecoenchants.enchantments.meta.EnchantmentTarget; +import com.willfp.ecoenchants.enchantments.util.EnchantChecks; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.WeakHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class CustomEnchantLookup { + /** + * All registered providers. + */ + private static final Set>> PROVIDERS = new HashSet<>(); + + /** + * Cached items. + */ + private static final Map> ITEM_CACHE = new WeakHashMap<>(); + + /** + * Cached enchant levels. + */ + private static final Map> ENCHANT_LEVELS_CACHE = new WeakHashMap<>(); + + /** + * Instance of EcoEnchants. + */ + private static final EcoPlugin PLUGIN = EcoEnchantsPlugin.getInstance(); + + /** + * Register provider. + * + * @param provider The provider. + */ + public static void registerProvider(@NotNull final Function> provider) { + PROVIDERS.add(provider); + } + + /** + * Provide ItemStacks. + * + * @param player The player. + * @return The ItemStacks. + */ + public static Map provide(@NotNull final Player player) { + if (ITEM_CACHE.containsKey(player.getUniqueId())) { + return new HashMap<>(ITEM_CACHE.get(player.getUniqueId())); + } + + Map found = new HashMap<>(); + for (Function> provider : PROVIDERS) { + found.putAll(provider.apply(player)); + } + found.keySet().removeIf(Objects::isNull); + + ITEM_CACHE.put(player.getUniqueId(), found); + PLUGIN.getScheduler().runLater(() -> ITEM_CACHE.remove(player.getUniqueId()), 40); + + return found; + } + + /** + * Provide levels. + * + * @param player The player. + * @return The levels. + */ + public static List provideLevels(@NotNull final Player player) { + if (ENCHANT_LEVELS_CACHE.containsKey(player.getUniqueId())) { + return new ArrayList<>(ENCHANT_LEVELS_CACHE.get(player.getUniqueId())); + } + + List found = new ArrayList<>(); + + for (Map.Entry entry : provide(player).entrySet()) { + ItemStack itemStack = entry.getKey(); + EnchantmentTarget.Slot slot = entry.getValue(); + if (itemStack == null) { + continue; + } + + Map enchants = EnchantChecks.getEnchantsOnItem(itemStack); + + if (enchants.isEmpty()) { + continue; + } + + for (Map.Entry enchantEntry : enchants.entrySet()) { + if (!(enchantEntry.getKey() instanceof CustomEcoEnchant enchant)) { + continue; + } + + if (slot != EnchantmentTarget.Slot.ANY) { + if (!enchant.getTargets().stream() + .map(EnchantmentTarget::getSlot) + .collect(Collectors.toList()) + .contains(slot)) { + continue; + } + } + + found.add(enchant.getLevel(enchantEntry.getValue())); + } + } + + ENCHANT_LEVELS_CACHE.put(player.getUniqueId(), found); + PLUGIN.getScheduler().runLater(() -> ENCHANT_LEVELS_CACHE.remove(player.getUniqueId()), 40); + + return found; + } + + /** + * Clear cache. + * + * @param player The player. + */ + public static void clearCache(@NotNull final Player player) { + ITEM_CACHE.remove(player.getUniqueId()); + ENCHANT_LEVELS_CACHE.remove(player.getUniqueId()); + } + + static { + registerProvider(player -> Map.of( + player.getInventory().getItemInMainHand(), + EnchantmentTarget.Slot.HANDS + )); + registerProvider(player -> Map.of( + player.getInventory().getItemInOffHand(), + EnchantmentTarget.Slot.HANDS + )); + registerProvider(player -> { + Map items = new HashMap<>(); + for (ItemStack stack : player.getInventory().getArmorContents()) { + items.put(stack, EnchantmentTarget.Slot.ARMOR); + } + return items; + }); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/EnchantmentTarget.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/EnchantmentTarget.java index 4ce201eb..c3835b62 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/EnchantmentTarget.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/EnchantmentTarget.java @@ -17,7 +17,7 @@ public class EnchantmentTarget { /** * Target containing the materials from all other targets. */ - public static final EnchantmentTarget ALL = new EnchantmentTarget("all", new HashSet<>()); + public static final EnchantmentTarget ALL = new EnchantmentTarget("all", new HashSet<>(), Slot.ANY); /** * All registered targets. */ @@ -33,12 +33,19 @@ public class EnchantmentTarget { */ @Getter private final String name; + /** * The materials of the target. */ @Getter private final Set materials; + /** + * The slot to check for custom enchants. + */ + @Getter + private final Slot slot; + /** * Create new rarity. * @@ -46,10 +53,12 @@ public class EnchantmentTarget { * @param materials The items for the target */ public EnchantmentTarget(@NotNull final String name, - @NotNull final Set materials) { + @NotNull final Set materials, + @NotNull final Slot slot) { this.name = name; materials.removeIf(Objects::isNull); this.materials = materials; + this.slot = slot; } /** @@ -74,7 +83,7 @@ public class EnchantmentTarget { ALL.materials.clear(); targetNames.forEach(name -> { Set materials = plugin.getTargetYml().getTargetMaterials(name); - new EnchantmentTarget(name, materials).register(); + new EnchantmentTarget(name, materials, plugin.getTargetYml().getSlot(name)).register(); }); } @@ -94,4 +103,24 @@ public class EnchantmentTarget { REGISTERED.add(this); ALL.getMaterials().addAll(this.getMaterials()); } + + /** + * Enchant slots. + */ + public enum Slot { + /** + * In hands. + */ + HANDS, + + /** + * In armor. + */ + ARMOR, + + /** + * In inventory. + */ + ANY + } } diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/util/EnchantmentUtils.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/util/EnchantmentUtils.java index 78b38968..f8a42eff 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/util/EnchantmentUtils.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/util/EnchantmentUtils.java @@ -143,6 +143,41 @@ public class EnchantmentUtils { } } + /** + * Unregister enchantment with the server. + * + * @param enchantment The enchantment. + */ + public static void unregister(@NotNull final Enchantment enchantment) { + try { + Field byIdField = Enchantment.class.getDeclaredField("byKey"); + Field byNameField = Enchantment.class.getDeclaredField("byName"); + byIdField.setAccessible(true); + byNameField.setAccessible(true); + Map byKey = (Map) byIdField.get(null); + Map byName = (Map) byNameField.get(null); + byKey.remove(enchantment.getKey()); + byName.remove(enchantment.getName()); + + if (enchantment instanceof EcoEnchant) { + byName.remove(((EcoEnchant) enchantment).getDisplayName()); + } + + Map byNameClone = new HashMap<>(byName); + for (Map.Entry entry : byNameClone.entrySet()) { + if (entry.getValue().getKey().equals(enchantment.getKey())) { + byName.remove(entry.getKey()); + } + } + + Field f = Enchantment.class.getDeclaredField("acceptingNew"); + f.setAccessible(true); + f.set(null, true); + f.setAccessible(false); + } catch (NoSuchFieldException | IllegalAccessException ignored) { + } + } + /** * Rehandle breaking in a fast way that doesn't call Player#updateInventory. * diff --git a/eco-core/core-plugin/src/main/resources/customenchants.yml b/eco-core/core-plugin/src/main/resources/customenchants.yml new file mode 100644 index 00000000..9b654133 --- /dev/null +++ b/eco-core/core-plugin/src/main/resources/customenchants.yml @@ -0,0 +1,28 @@ +enchants: + - id: demo + name: "Demo Custom Enchantment" + description: Damages your opponents armor by &a%value%&r. + + obtaining: + table: true + villager: true + loot: true + rarity: legendary + + general-config: + flags: [ ] + targets: + - sword + - axe + grindstoneable: true + disabled-in-worlds: [ ] + requirements: + list: [ ] + not-met-lore: [ ] + conflicts: [ ] + + levels: + - effects: [ ] + conditions: [ ] + - effects: [ ] + conditions: [ ] \ No newline at end of file diff --git a/eco-core/core-plugin/src/main/resources/plugin.yml b/eco-core/core-plugin/src/main/resources/plugin.yml index 83707df8..7802691a 100644 --- a/eco-core/core-plugin/src/main/resources/plugin.yml +++ b/eco-core/core-plugin/src/main/resources/plugin.yml @@ -11,6 +11,10 @@ depend: softdepend: - Essentials - MythicMobs + - EcoSkills + - AureliumSkills +libraries: + - 'org.jetbrains.kotlin:kotlin-stdlib:1.6.0' commands: enchantinfo: diff --git a/eco-core/core-plugin/src/main/resources/target.yml b/eco-core/core-plugin/src/main/resources/target.yml index ab55f41b..83b34ffb 100644 --- a/eco-core/core-plugin/src/main/resources/target.yml +++ b/eco-core/core-plugin/src/main/resources/target.yml @@ -8,6 +8,7 @@ extra-enchantable-items: targets: axe: + - target:hands - wooden_axe - stone_axe - iron_axe @@ -20,6 +21,7 @@ targets: - enchanted_book pickaxe: + - target:hands - wooden_pickaxe - stone_pickaxe - iron_pickaxe @@ -28,6 +30,7 @@ targets: - netherite_pickaxe hoe: + - target:hands - wooden_hoe - stone_hoe - iron_hoe @@ -36,6 +39,7 @@ targets: - netherite_hoe shovel: + - target:hands - wooden_shovel - stone_shovel - iron_shovel @@ -44,6 +48,7 @@ targets: - netherite_shovel sword: + - target:hands - wooden_sword - stone_sword - iron_sword @@ -52,6 +57,7 @@ targets: - netherite_sword helmet: + - target:armor - turtle_helmet - leather_helmet - chainmail_helmet @@ -61,6 +67,7 @@ targets: - netherite_helmet chestplate: + - target:armor - leather_chestplate - chainmail_chestplate - iron_chestplate @@ -69,6 +76,7 @@ targets: - netherite_chestplate leggings: + - target:armor - leather_leggings - chainmail_leggings - iron_leggings @@ -77,6 +85,7 @@ targets: - netherite_leggings boots: + - target:armor - leather_boots - chainmail_boots - iron_boots @@ -85,28 +94,37 @@ targets: - netherite_boots elytra: + - target:armor - elytra bow: + - target:hands - bow crossbow: + - target:hands - crossbow shears: + - target:hands - shears trident: + - target:hands - trident shield: + - target:hands - shield rod: + - target:hands - fishing_rod flintandsteel: + - target:hands - flint_and_steel carrot_stick: + - target:hands - carrot_on_a_stick diff --git a/settings.gradle b/settings.gradle index f6d41df4..5c85006c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ include ':eco-core' include ':eco-core:core-nms' include ':eco-core:core-nms:v1_16_R3' include ':eco-core:core-nms:v1_17_R1' -include ':eco-core:core-nms:v1_18_R1' +//include ':eco-core:core-nms:v1_18_R1' include ':eco-core:core-proxy' include ':eco-core:core-plugin' include ':eco-core:core-stub'