From 5f0c4e2f0034aefe84adfcc9adc65a16496f3955 Mon Sep 17 00:00:00 2001 From: xGinko Date: Tue, 5 Sep 2023 13:38:36 +0200 Subject: [PATCH] better villagercache --- .../villageroptimizer/VillagerCache.java | 52 ++++++++++ .../villageroptimizer/VillagerManager.java | 65 ------------- .../villageroptimizer/VillagerOptimizer.java | 96 +++++++++++++++---- .../villageroptimizer/config/Config.java | 67 +++++++++---- .../models/WrappedVillager.java | 5 + 5 files changed, 180 insertions(+), 105 deletions(-) create mode 100644 src/main/java/me/xginko/villageroptimizer/VillagerCache.java delete mode 100644 src/main/java/me/xginko/villageroptimizer/VillagerManager.java 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..125a51e --- /dev/null +++ b/src/main/java/me/xginko/villageroptimizer/VillagerCache.java @@ -0,0 +1,52 @@ +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.entity.Villager; +import org.jetbrains.annotations.Nullable; + +import java.time.Duration; +import java.util.Collection; +import java.util.UUID; + +public class VillagerCache { + + private final Cache villagerCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(30)).build(); + + protected VillagerCache() {} + + public Collection getAll() { + return this.villagerCache.asMap().values(); + } + + public @Nullable WrappedVillager get(UUID uuid) { + return villagerCache.getIfPresent(uuid); + } + + public WrappedVillager getOrAddIfAbsent(Villager villager) { + WrappedVillager wrappedVillager = villagerCache.getIfPresent(villager.getUniqueId()); + if (wrappedVillager == null) wrappedVillager = new WrappedVillager(villager); + this.villagerCache.put(villager.getUniqueId(), wrappedVillager); // refresh cache + return wrappedVillager; + } + + public WrappedVillager add(WrappedVillager villager) { + villagerCache.put(villager.villager().getUniqueId(), villager); + return villager; + } + + public WrappedVillager add(Villager villager) { + WrappedVillager wrapped = new WrappedVillager(villager); + villagerCache.put(villager.getUniqueId(), wrapped); + return wrapped; + } + + public boolean contains(WrappedVillager villager) { + return villagerCache.getIfPresent(villager.villager().getUniqueId()) != null; + } + + public boolean contains(Villager villager) { + return villagerCache.getIfPresent(villager.getUniqueId()) != null; + } +} diff --git a/src/main/java/me/xginko/villageroptimizer/VillagerManager.java b/src/main/java/me/xginko/villageroptimizer/VillagerManager.java deleted file mode 100644 index e51aa69..0000000 --- a/src/main/java/me/xginko/villageroptimizer/VillagerManager.java +++ /dev/null @@ -1,65 +0,0 @@ -package me.xginko.villageroptimizer; - -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; -import me.xginko.villageroptimizer.config.Config; -import me.xginko.villageroptimizer.enums.OptimizationType; -import me.xginko.villageroptimizer.models.WrappedVillager; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Villager; -import org.bukkit.entity.memory.MemoryKey; -import org.bukkit.plugin.java.JavaPlugin; - -import java.time.Duration; -import java.util.Collection; -import java.util.UUID; - -public class VillagerManager { - - private final Cache villagerCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(30)).build(); - private final Config config; - - protected VillagerManager(JavaPlugin plugin) { - this.config = VillagerOptimizer.getConfiguration(); - plugin.getServer().getGlobalRegionScheduler().run(plugin, reCache -> { - for (World world : plugin.getServer().getWorlds()) { - for (Villager villager : world.getEntitiesByClass(Villager.class)) { - this.villagerCache.put(villager.getUniqueId(), new WrappedVillager(villager)); - } - } - }); - } - - public Collection getCachedVillagers() { - return this.villagerCache.asMap().values(); - } - - public WrappedVillager wrap(Villager villager) { - WrappedVillager wrappedVillager = villagerCache.getIfPresent(villager.getUniqueId()); - if (wrappedVillager == null) wrappedVillager = new WrappedVillager(villager); - this.villagerCache.put(villager.getUniqueId(), wrappedVillager); - return wrappedVillager; - } - - public OptimizationType computeOptimization(WrappedVillager wrapped) { - Component nameTag = wrapped.villager().customName(); - if (nameTag != null && config.names_that_disable.contains(PlainTextComponentSerializer.plainText().serialize(nameTag).toLowerCase())) { - return OptimizationType.NAMETAG; - } - - if (config.blocks_that_disable.contains(wrapped.villager().getLocation().getBlock().getRelative(BlockFace.DOWN).getType())) { - return OptimizationType.BLOCK; - } - - final Location jobSite = wrapped.villager().getMemory(MemoryKey.JOB_SITE); - if (jobSite != null && config.workstations_that_disable.contains(jobSite.getBlock().getType())) { - return OptimizationType.WORKSTATION; - } - - return wrapped.getOptimizationType(); - } -} diff --git a/src/main/java/me/xginko/villageroptimizer/VillagerOptimizer.java b/src/main/java/me/xginko/villageroptimizer/VillagerOptimizer.java index 70e863c..2639237 100644 --- a/src/main/java/me/xginko/villageroptimizer/VillagerOptimizer.java +++ b/src/main/java/me/xginko/villageroptimizer/VillagerOptimizer.java @@ -2,10 +2,18 @@ package me.xginko.villageroptimizer; import me.xginko.villageroptimizer.config.Config; import me.xginko.villageroptimizer.config.LanguageCache; +import me.xginko.villageroptimizer.enums.OptimizationType; +import me.xginko.villageroptimizer.models.WrappedVillager; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.Location; import org.bukkit.NamespacedKey; +import org.bukkit.block.BlockFace; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.entity.memory.MemoryKey; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; @@ -24,7 +32,7 @@ public final class VillagerOptimizer extends JavaPlugin { private static Logger logger; private static Config config; private static HashMap languageCacheMap; - private static VillagerManager villagerManager; + private static VillagerCache villagerCache; @Override public void onEnable() { @@ -45,31 +53,60 @@ public final class VillagerOptimizer extends JavaPlugin { // Plugin shutdown logic } - public static LanguageCache getLang(String lang) { - lang = lang.replace("-", "_"); - if (config.auto_lang) { - return languageCacheMap.getOrDefault(lang, languageCacheMap.get(config.default_lang.toString().toLowerCase())); - } else { - return languageCacheMap.get(config.default_lang.toString().toLowerCase()); + public static OptimizationType computeOptimization(WrappedVillager wrapped) { + if (config.enable_nametag_optimization) { + Component name = wrapped.villager().customName(); + if (name != null && config.nametags.contains(PlainTextComponentSerializer.plainText().serialize(name).toLowerCase())) { + return OptimizationType.NAMETAG; + } } + if (config.enable_block_optimization) { + if (config.blocks_that_disable.contains(wrapped.villager().getLocation().getBlock().getRelative(BlockFace.DOWN).getType())) { + return OptimizationType.BLOCK; + } + } + if (config.enable_workstation_optimization) { + final Location jobSite = wrapped.villager().getMemory(MemoryKey.JOB_SITE); + if ( + jobSite != null + && config.workstations_that_disable.contains(jobSite.getBlock().getType()) + && wrapped.villager().getLocation().distance(jobSite) <= config.workstation_max_distance + ) { + return OptimizationType.WORKSTATION; + } + } + return wrapped.getOptimizationType(); } - public static LanguageCache getLang(Locale locale) { - return getLang(locale.toString().toLowerCase()); - } - - public static LanguageCache getLang(CommandSender commandSender) { - if (commandSender instanceof Player player) { - return getLang(player.locale()); - } else { - return getLang(config.default_lang); + public static OptimizationType computeOptimization(Villager villager) { + if (config.enable_nametag_optimization) { + Component name = villager.customName(); + if (name != null && config.nametags.contains(PlainTextComponentSerializer.plainText().serialize(name).toLowerCase())) { + return OptimizationType.NAMETAG; + } } + if (config.enable_block_optimization) { + if (config.blocks_that_disable.contains(villager.getLocation().getBlock().getRelative(BlockFace.DOWN).getType())) { + return OptimizationType.BLOCK; + } + } + if (config.enable_workstation_optimization) { + final Location jobSite = villager.getMemory(MemoryKey.JOB_SITE); + if ( + jobSite != null + && config.workstations_that_disable.contains(jobSite.getBlock().getType()) + && villager.getLocation().distance(jobSite) <= config.workstation_max_distance + ) { + return OptimizationType.WORKSTATION; + } + } + return villagerCache.getOrAddIfAbsent(villager).getOptimizationType(); } public void reloadPlugin() { + villagerCache = new VillagerCache(); reloadLang(); reloadConfiguration(); - villagerManager = new VillagerManager(this); } private void reloadConfiguration() { @@ -129,6 +166,27 @@ public final class VillagerOptimizer extends JavaPlugin { return languageFiles; } + public static LanguageCache getLang(String lang) { + lang = lang.replace("-", "_"); + if (config.auto_lang) { + return languageCacheMap.getOrDefault(lang, languageCacheMap.get(config.default_lang.toString().toLowerCase())); + } else { + return languageCacheMap.get(config.default_lang.toString().toLowerCase()); + } + } + + public static LanguageCache getLang(Locale locale) { + return getLang(locale.toString().toLowerCase()); + } + + public static LanguageCache getLang(CommandSender commandSender) { + if (commandSender instanceof Player player) { + return getLang(player.locale()); + } else { + return getLang(config.default_lang); + } + } + public static VillagerOptimizer getInstance() { return instance; } @@ -144,7 +202,7 @@ public final class VillagerOptimizer extends JavaPlugin { public static Logger getLog() { return logger; } - public static VillagerManager getVillagerManager() { - return villagerManager; + public static VillagerCache getVillagerCache() { + return villagerCache; } } diff --git a/src/main/java/me/xginko/villageroptimizer/config/Config.java b/src/main/java/me/xginko/villageroptimizer/config/Config.java index 45edb0c..8522320 100644 --- a/src/main/java/me/xginko/villageroptimizer/config/Config.java +++ b/src/main/java/me/xginko/villageroptimizer/config/Config.java @@ -17,32 +17,41 @@ public class Config { private final ConfigFile config; public final Locale default_lang; - public final boolean auto_lang; + public final boolean auto_lang, enable_nametag_optimization, enable_workstation_optimization, enable_block_optimization; + public final double workstation_max_distance; - public final HashSet names_that_disable = new HashSet<>(2); + public final HashSet nametags = new HashSet<>(2); public final HashSet blocks_that_disable = new HashSet<>(2); public final HashSet workstations_that_disable = new HashSet<>(13); public Config() throws Exception { this.config = loadConfig(new File(VillagerOptimizer.getInstance().getDataFolder(), "config.yml")); structureConfig(); - - // Language Settings - this.default_lang = Locale.forLanguageTag(getString("language.default-language", "en_us", "The default language that will be used if auto-language is false or no matching language file was found.").replace("_", "-")); + /** + * Language + */ + this.default_lang = Locale.forLanguageTag( + getString("language.default-language", "en_us", + "The default language that will be used if auto-language is false or no matching language file was found.") + .replace("_", "-")); this.auto_lang = getBoolean("language.auto-language", true, "If set to true, will display messages based on client language"); - - - // AI-Disabling - this.names_that_disable.addAll(getList("ai-disabling.names-that-disable", List.of("Optimize", "DisableAI")).stream().map(String::toLowerCase).toList()); - getList("ai-disabling.blocks-that-disable", List.of("EMERALD_BLOCK", "COBBLESTONE")).forEach(configuredMaterial -> { - try { - Material disableBlock = Material.valueOf(configuredMaterial); - this.blocks_that_disable.add(disableBlock); - } catch (IllegalArgumentException e) { - LogUtils.materialNotRecognized("blocks-that-disable", configuredMaterial); - } - }); - getList("ai-disabling.workstations-that-disable", List.of( + /** + * Optimization + */ + // Nametags + this.enable_nametag_optimization = getBoolean("optimization.by-nametag.enable", true); + this.nametags.addAll(getList("optimization.by-nametag.names", List.of("Optimize", "DisableAI"), "Names are case insensitive") + .stream().map(String::toLowerCase).toList()); + // Workstations + this.enable_workstation_optimization = getBoolean("optimization.by-workstation.enable", true, + """ + Optimize villagers that are standing near their acquired workstations /s + Values here need to be valid bukkit Material enums for your server version. + """ + ); + this.workstation_max_distance = getDouble("optimization.by-workstation.", 4.0, + "How close in blocks a villager needs to be to get optimized by its workstation"); + this.getList("optimization.by-workstation.workstation-materials", List.of( "COMPOSTER", "SMOKER", "BARREL", "LOOM", "BLAST_FURNACE", "BREWING_STAND", "CAULDRON", "FLETCHING_TABLE", "CARTOGRAPHY_TABLE", "LECTERN", "SMITHING_TABLE", "STONECUTTER", "GRINDSTONE" )).forEach(configuredMaterial -> { @@ -50,7 +59,24 @@ public class Config { Material disableBlock = Material.valueOf(configuredMaterial); this.blocks_that_disable.add(disableBlock); } catch (IllegalArgumentException e) { - LogUtils.materialNotRecognized("workstations-that-disable", configuredMaterial); + LogUtils.materialNotRecognized("optimization.by-workstation", configuredMaterial); + } + }); + // Blocks + this.enable_block_optimization = getBoolean("optimization.by-specific-block.enable", true, + """ + Optimize villagers that are standing on these specific block materials /s + Values here need to be valid bukkit Material enums for your server version. + """ + ); + this.getList("optimization.by-specific-block.materials", List.of( + "LAPIS_BLOCK", "GLOWSTONE", "IRON_BLOCK" + )).forEach(configuredMaterial -> { + try { + Material disableBlock = Material.valueOf(configuredMaterial); + this.blocks_that_disable.add(disableBlock); + } catch (IllegalArgumentException e) { + LogUtils.materialNotRecognized("optimization.by-specific-block", configuredMaterial); } }); } @@ -76,8 +102,7 @@ public class Config { private void structureConfig() { config.addDefault("config-version", 1.00); createTitledSection("Language", "language"); - createTitledSection("AI Disabling", "ai-disabling"); - + createTitledSection("Optimization", "optimization"); } public void createTitledSection(String title, String path) { diff --git a/src/main/java/me/xginko/villageroptimizer/models/WrappedVillager.java b/src/main/java/me/xginko/villageroptimizer/models/WrappedVillager.java index fdd1bd1..5de3b33 100644 --- a/src/main/java/me/xginko/villageroptimizer/models/WrappedVillager.java +++ b/src/main/java/me/xginko/villageroptimizer/models/WrappedVillager.java @@ -1,5 +1,6 @@ package me.xginko.villageroptimizer.models; +import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.enums.NamespacedKeys; import me.xginko.villageroptimizer.enums.OptimizationType; import org.bukkit.entity.Villager; @@ -8,6 +9,10 @@ import org.bukkit.persistence.PersistentDataType; public record WrappedVillager(Villager villager) { + public static WrappedVillager fromVillager(Villager villager) { + return VillagerOptimizer.getVillagerCache().getOrAddIfAbsent(villager); + } + public boolean isOptimized() { return villager.getPersistentDataContainer().has(NamespacedKeys.OPTIMIZED.key()); }