From a84fe51953f5d91950d056ce310412167e97c9bb Mon Sep 17 00:00:00 2001 From: xGinko Date: Tue, 5 Sep 2023 01:56:06 +0200 Subject: [PATCH] redsign helper methods into a wrapper and utilize caching --- pom.xml | 5 + .../villageroptimizer/VillagerCache.java | 40 ++++++++ .../enums/NamespacedKeys.java | 22 +++++ .../enums/OptimizationType.java | 11 +++ .../models/OptimizedVillager.java | 17 ---- .../models/WrappedVillager.java | 67 ++++++++++++++ .../utils/CalculateLevel.java | 21 ----- .../utils/NamespacedKeys.java | 24 ----- .../utils/VillagerUtils.java | 92 +------------------ 9 files changed, 147 insertions(+), 152 deletions(-) create mode 100644 src/main/java/me/xginko/villageroptimizer/VillagerCache.java create mode 100644 src/main/java/me/xginko/villageroptimizer/enums/NamespacedKeys.java create mode 100644 src/main/java/me/xginko/villageroptimizer/enums/OptimizationType.java delete mode 100644 src/main/java/me/xginko/villageroptimizer/models/OptimizedVillager.java create mode 100644 src/main/java/me/xginko/villageroptimizer/models/WrappedVillager.java delete mode 100644 src/main/java/me/xginko/villageroptimizer/utils/CalculateLevel.java delete mode 100644 src/main/java/me/xginko/villageroptimizer/utils/NamespacedKeys.java diff --git a/pom.xml b/pom.xml index a8ddf14..2bfa0f5 100644 --- a/pom.xml +++ b/pom.xml @@ -82,5 +82,10 @@ v2.0.0-BETA-9 compile + + com.github.ben-manes.caffeine + caffeine + 3.1.8 + diff --git a/src/main/java/me/xginko/villageroptimizer/VillagerCache.java b/src/main/java/me/xginko/villageroptimizer/VillagerCache.java new file mode 100644 index 0000000..a7246e9 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/VillagerCache.java @@ -0,0 +1,40 @@ +package me.xginko.villageroptimizer; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import me.xginko.villageroptimizer.models.WrappedVillager; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Villager; +import org.bukkit.plugin.java.JavaPlugin; + +import java.time.Duration; +import java.util.Map; +import java.util.UUID; + +public class VillagerCache { + private final Cache villagerCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(30)).build(); + + public VillagerCache(JavaPlugin plugin) { + plugin.getServer().getGlobalRegionScheduler().run(plugin, populateCache -> { + for (World world : plugin.getServer().getWorlds()) { + for (Entity entity : world.getEntities()) { + if (entity instanceof Villager villager) { + this.villagerCache.put(villager.getUniqueId(), new WrappedVillager(villager)); + } + } + } + }); + } + + public WrappedVillager getVillager(Villager villager) { + WrappedVillager wrappedVillager = villagerCache.getIfPresent(villager.getUniqueId()); + if (wrappedVillager == null) wrappedVillager = new WrappedVillager(villager); + this.villagerCache.put(villager.getUniqueId(), wrappedVillager); + return wrappedVillager; + } + + public Map get() { + return this.villagerCache.asMap(); + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/enums/NamespacedKeys.java b/src/main/java/me/xginko/villageroptimizer/enums/NamespacedKeys.java new file mode 100644 index 0000000..fa428b5 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/enums/NamespacedKeys.java @@ -0,0 +1,22 @@ +package me.xginko.villageroptimizer.enums; + +import me.xginko.villageroptimizer.VillagerOptimizer; +import org.bukkit.NamespacedKey; + +public enum NamespacedKeys { + + OPTIMIZED(VillagerOptimizer.getKey("optimized")), + COOLDOWN_RESTOCK(VillagerOptimizer.getKey("restock-cooldown")), + COOLDOWN_EXPERIENCE(VillagerOptimizer.getKey("experience-cooldown")), + GAME_TIME(VillagerOptimizer.getKey("game-time")); + + private final NamespacedKey key; + + NamespacedKeys(NamespacedKey key) { + this.key = key; + } + + public NamespacedKey get() { + return key; + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/enums/OptimizationType.java b/src/main/java/me/xginko/villageroptimizer/enums/OptimizationType.java new file mode 100644 index 0000000..bbf7232 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/enums/OptimizationType.java @@ -0,0 +1,11 @@ +package me.xginko.villageroptimizer.enums; + +public enum OptimizationType { + + COMMAND, + NAMETAG, + WORKSTATION, + BLOCK, + OFF + +} diff --git a/src/main/java/me/xginko/villageroptimizer/models/OptimizedVillager.java b/src/main/java/me/xginko/villageroptimizer/models/OptimizedVillager.java deleted file mode 100644 index 232fae8..0000000 --- a/src/main/java/me/xginko/villageroptimizer/models/OptimizedVillager.java +++ /dev/null @@ -1,17 +0,0 @@ -package me.xginko.villageroptimizer.models; - -import org.bukkit.entity.Villager; - -public class OptimizedVillager { - - private final Villager villager; - - - public OptimizedVillager(Villager villager) { - this.villager = villager; - } - - public Villager villager() { - return villager; - } -} diff --git a/src/main/java/me/xginko/villageroptimizer/models/WrappedVillager.java b/src/main/java/me/xginko/villageroptimizer/models/WrappedVillager.java new file mode 100644 index 0000000..5b7cab9 --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/models/WrappedVillager.java @@ -0,0 +1,67 @@ +package me.xginko.villageroptimizer.models; + +import me.xginko.villageroptimizer.enums.NamespacedKeys; +import me.xginko.villageroptimizer.enums.OptimizationType; +import org.bukkit.entity.Villager; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +public record WrappedVillager(Villager villager) { + + public long getLevel() { + // Villager Level depending on their XP (source: https://minecraft.fandom.com/wiki/Trading#Mechanics) + final int experience = villager.getVillagerExperience(); + if (experience >= 250) return 5; + if (experience >= 150) return 4; + if (experience >= 70) return 3; + if (experience >= 10) return 2; + return 1; + } + + public boolean isOptimized() { + return villager.getPersistentDataContainer().has(NamespacedKeys.OPTIMIZED.get()); + } + + public void setOptimization(OptimizationType type) { + if (type.equals(OptimizationType.OFF) && isOptimized()) { + villager.getPersistentDataContainer().remove(NamespacedKeys.OPTIMIZED.get()); + } else { + villager.getPersistentDataContainer().set(NamespacedKeys.OPTIMIZED.get(), PersistentDataType.STRING, type.name()); + } + } + + public OptimizationType getOptimizationType() { + return isOptimized() ? OptimizationType.valueOf(villager().getPersistentDataContainer().get(NamespacedKeys.OPTIMIZED.get(), PersistentDataType.STRING)) : OptimizationType.OFF; + } + + public void setRestockCooldown(long milliseconds) { + villager.getPersistentDataContainer().set(NamespacedKeys.COOLDOWN_RESTOCK.get(), PersistentDataType.LONG, System.currentTimeMillis() + milliseconds); + } + + public boolean shouldRestock() { + PersistentDataContainer villagerData = villager.getPersistentDataContainer(); + return villagerData.has(NamespacedKeys.COOLDOWN_RESTOCK.get(), PersistentDataType.LONG) && villagerData.get(NamespacedKeys.COOLDOWN_RESTOCK.get(), PersistentDataType.LONG) <= System.currentTimeMillis(); + } + + public void restock() { + villager.getRecipes().forEach(recipe -> recipe.setUses(0)); + } + + public void setExpCooldown(long milliseconds) { + villager.getPersistentDataContainer().set(NamespacedKeys.COOLDOWN_EXPERIENCE.get(), PersistentDataType.LONG, System.currentTimeMillis() + milliseconds); + } + + public boolean isOnExpCooldown() { + PersistentDataContainer villagerData = villager.getPersistentDataContainer(); + return villagerData.has(NamespacedKeys.COOLDOWN_EXPERIENCE.get(), PersistentDataType.LONG) && villagerData.get(NamespacedKeys.COOLDOWN_EXPERIENCE.get(), PersistentDataType.LONG) <= System.currentTimeMillis(); + } + + public void saveWorldTime() { + villager.getPersistentDataContainer().set(NamespacedKeys.GAME_TIME.get(), PersistentDataType.LONG, villager.getWorld().getFullTime()); + } + + public long getSavedWorldTime() { + PersistentDataContainer villagerData = villager.getPersistentDataContainer(); + return villagerData.has(NamespacedKeys.GAME_TIME.get(), PersistentDataType.LONG) ? villagerData.get(NamespacedKeys.GAME_TIME.get(), PersistentDataType.LONG) : villager.getWorld().getFullTime(); + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/utils/CalculateLevel.java b/src/main/java/me/xginko/villageroptimizer/utils/CalculateLevel.java deleted file mode 100644 index 941b21c..0000000 --- a/src/main/java/me/xginko/villageroptimizer/utils/CalculateLevel.java +++ /dev/null @@ -1,21 +0,0 @@ -package me.xginko.villageroptimizer.utils; - -import org.bukkit.entity.Villager; - -public class CalculateLevel { - public static long villagerEXP (Villager vil) { - - int vilEXP = vil.getVillagerExperience(); - - // Villager Level depending on their XP - // source: https://minecraft.fandom.com/wiki/Trading#Mechanics - - if (vilEXP >= 250) return 5; - if (vilEXP >= 150) return 4; - if (vilEXP >= 70) return 3; - if (vilEXP >= 10) return 2; - - // default level is 1 - return 1; - } -} diff --git a/src/main/java/me/xginko/villageroptimizer/utils/NamespacedKeys.java b/src/main/java/me/xginko/villageroptimizer/utils/NamespacedKeys.java deleted file mode 100644 index 8d939e4..0000000 --- a/src/main/java/me/xginko/villageroptimizer/utils/NamespacedKeys.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.xginko.villageroptimizer.utils; - -import me.xginko.villageroptimizer.VillagerOptimizer; -import org.bukkit.NamespacedKey; - -public enum NamespacedKeys { - - COOLDOWN(VillagerOptimizer.getKey("cooldown")), - TIME(VillagerOptimizer.getKey("time")), - LEVEL_COOLDOWN(VillagerOptimizer.getKey("level-cooldown")), - NAMETAG_DISABLED(VillagerOptimizer.getKey("nametag-disabled")), - BLOCK_DISABLED(VillagerOptimizer.getKey("block-disabled")), - WORKSTATION_DISABLED(VillagerOptimizer.getKey("workstation-disabled")); - - private final NamespacedKey key; - - NamespacedKeys(NamespacedKey key) { - this.key = key; - } - - public NamespacedKey get() { - return key; - } -} diff --git a/src/main/java/me/xginko/villageroptimizer/utils/VillagerUtils.java b/src/main/java/me/xginko/villageroptimizer/utils/VillagerUtils.java index 26e2dd4..2a65b25 100644 --- a/src/main/java/me/xginko/villageroptimizer/utils/VillagerUtils.java +++ b/src/main/java/me/xginko/villageroptimizer/utils/VillagerUtils.java @@ -1,28 +1,14 @@ package me.xginko.villageroptimizer.utils; import me.xginko.villageroptimizer.VillagerOptimizer; +import me.xginko.villageroptimizer.models.WrappedVillager; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.block.BlockFace; import org.bukkit.entity.Villager; -import org.bukkit.inventory.MerchantRecipe; -import org.bukkit.persistence.PersistentDataType; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.Optional; public class VillagerUtils { - public static boolean isDisabled(Villager villager) { - return hasDisabledByBlock(villager) || hasDisabledByWorkstation(villager) || hasMarker(villager); - } - - public static void restockTrades(Villager villager) { - for (MerchantRecipe recipe : villager.getRecipes()) { - recipe.setUses(0); - } - } - public static boolean shouldDisable(Villager villager) { // Check nametag Component nameTag = villager.customName(); @@ -38,80 +24,6 @@ public class VillagerUtils { } // Check Workstation - return getDisabledByWorkstation(villager).orElse(false); - } - - /* - * - * Helper Methods for storing and reading data inside villagers using PersistentDataContainer - * - * */ - - // Disabled by Block - public static void setDisabledByBlock(Villager villager, boolean state) { - villager.getPersistentDataContainer().set(NamespacedKeys.BLOCK_DISABLED.get(), PersistentDataType.BOOLEAN, state); - } - public static boolean isDisabledByBlock(Villager villager) { - if (villager.getPersistentDataContainer().has(NamespacedKeys.BLOCK_DISABLED.get(), PersistentDataType.BOOLEAN)) { - return villager.getPersistentDataContainer().get(NamespacedKeys.BLOCK_DISABLED.get(), PersistentDataType.BOOLEAN); - } else { - setDisabledByBlock(villager, false); - return false; - } - } - - // Disabled by Workstation - public static void setDisabledByWorkstation(Villager villager, Boolean state) { - villager.getPersistentDataContainer().set(NamespacedKeys.WORKSTATION_DISABLED.get(), PersistentDataType.BOOLEAN, state); - } - public static boolean hasDisabledByWorkstation(Villager villager) { - return villager.getPersistentDataContainer().has(NamespacedKeys.WORKSTATION_DISABLED.get(), PersistentDataType.BOOLEAN); - } - public static Optional getDisabledByWorkstation(Villager villager) { - return Optional.ofNullable(villager.getPersistentDataContainer().get(NamespacedKeys.WORKSTATION_DISABLED.get(), PersistentDataType.BOOLEAN)); - } - - // Cooldown - public static void setCooldown(Villager villager, long cooldown_millis) { - villager.getPersistentDataContainer().set(NamespacedKeys.COOLDOWN.get(), PersistentDataType.LONG, System.currentTimeMillis() + cooldown_millis); - } - public static boolean hasCooldown(Villager villager) { - return villager.getPersistentDataContainer().has(NamespacedKeys.COOLDOWN.get(), PersistentDataType.LONG); - } - public static Optional getCooldown(Villager villager) { - return Optional.ofNullable(villager.getPersistentDataContainer().get(NamespacedKeys.COOLDOWN.get(), PersistentDataType.LONG)); - } - - // Time - public static void setTime(Villager villager) { - villager.getPersistentDataContainer().set(NamespacedKeys.TIME.get(), PersistentDataType.LONG, villager.getWorld().getFullTime()); - } - public static boolean hasTime(Villager villager) { - return villager.getPersistentDataContainer().has(NamespacedKeys.TIME.get(), PersistentDataType.LONG); - } - public static Optional getTime(Villager villager) { - return Optional.ofNullable(villager.getPersistentDataContainer().get(NamespacedKeys.TIME.get(), PersistentDataType.LONG)); - } - - // Level Cooldown - public static void setLevelCooldown(Villager villager, long cooldown_millis) { - villager.getPersistentDataContainer().set(NamespacedKeys.LEVEL_COOLDOWN.get(), PersistentDataType.LONG, System.currentTimeMillis() + cooldown_millis); - } - public static boolean hasLevelCooldown(Villager villager, JavaPlugin plugin) { - return villager.getPersistentDataContainer().has(NamespacedKeys.LEVEL_COOLDOWN.get(), PersistentDataType.LONG); - } - public static Optional getLevelCooldown(Villager villager) { - return Optional.ofNullable(villager.getPersistentDataContainer().get(NamespacedKeys.LEVEL_COOLDOWN.get(), PersistentDataType.LONG)); - } - - // Marker - public static void setMarker(Villager villager) { - villager.getPersistentDataContainer().set(NamespacedKeys.NAMETAG_DISABLED.get(), PersistentDataType.BYTE, (byte)1); - } - public static boolean hasMarker(Villager villager) { - return villager.getPersistentDataContainer().has(NamespacedKeys.NAMETAG_DISABLED.get(), PersistentDataType.BYTE); - } - public static void removeMarker(Villager villager) { - villager.getPersistentDataContainer().remove(NamespacedKeys.NAMETAG_DISABLED.get()); + return new WrappedVillager(villager).isOptimized(); } }