use abstract class instead of interface

This commit is contained in:
xGinko 2024-06-12 15:21:43 +02:00
parent 5fecedf658
commit e01b8b0462
23 changed files with 226 additions and 351 deletions

11
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>me.xginko</groupId> <groupId>me.xginko</groupId>
<artifactId>VillagerOptimizer</artifactId> <artifactId>VillagerOptimizer</artifactId>
<version>1.5.5</version> <version>1.6.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>VillagerOptimizer</name> <name>VillagerOptimizer</name>
@ -61,6 +61,10 @@
<pattern>io.github.thatsmusic99.configurationmaster</pattern> <pattern>io.github.thatsmusic99.configurationmaster</pattern>
<shadedPattern>me.xginko.villageroptimizer.libs.configmaster</shadedPattern> <shadedPattern>me.xginko.villageroptimizer.libs.configmaster</shadedPattern>
</relocation> </relocation>
<relocation>
<pattern>org.reflections</pattern>
<shadedPattern>me.xginko.villageroptimizer.libs.reflections</shadedPattern>
</relocation>
</relocations> </relocations>
<filters> <filters>
<filter> <filter>
@ -112,6 +116,11 @@
<version>1.20.4-R0.1-SNAPSHOT</version> <version>1.20.4-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
<!-- Adventure API for easier cross-version compatibility --> <!-- Adventure API for easier cross-version compatibility -->
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>

View File

@ -26,7 +26,7 @@ public final class VillagerCache {
this.villagerCache.asMap().clear(); this.villagerCache.asMap().clear();
} }
public @NotNull WrappedVillager getOrAdd(@NotNull Villager villager) { public @NotNull WrappedVillager createIfAbsent(@NotNull Villager villager) {
WrappedVillager wrappedVillager = this.villagerCache.getIfPresent(villager.getUniqueId()); WrappedVillager wrappedVillager = this.villagerCache.getIfPresent(villager.getUniqueId());
return wrappedVillager == null ? this.add(new WrappedVillager(villager)) : this.add(wrappedVillager); return wrappedVillager == null ? this.add(new WrappedVillager(villager)) : this.add(wrappedVillager);
} }

View File

@ -94,8 +94,8 @@ public final class VillagerOptimizer extends JavaPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
VillagerOptimizerModule.MODULES.forEach(VillagerOptimizerModule::disable); VillagerOptimizerModule.ENABLED_MODULES.forEach(VillagerOptimizerModule::disable);
VillagerOptimizerModule.MODULES.clear(); VillagerOptimizerModule.ENABLED_MODULES.clear();
if (foliaLib != null) { if (foliaLib != null) {
foliaLib.getImpl().cancelAllTasks(); foliaLib.getImpl().cancelAllTasks();
foliaLib = null; foliaLib = null;
@ -121,7 +121,7 @@ public final class VillagerOptimizer extends JavaPlugin {
public static @NotNull VillagerOptimizer getInstance() { public static @NotNull VillagerOptimizer getInstance() {
return instance; return instance;
} }
public static @NotNull Config getConfiguration() { public static @NotNull Config config() {
return config; return config;
} }
public static @NotNull VillagerCache getCache() { public static @NotNull VillagerCache getCache() {
@ -130,7 +130,7 @@ public final class VillagerOptimizer extends JavaPlugin {
public static @NotNull FoliaLib getFoliaLib() { public static @NotNull FoliaLib getFoliaLib() {
return foliaLib; return foliaLib;
} }
public static @NotNull ComponentLogger getPrefixedLogger() { public static @NotNull ComponentLogger logger() {
return logger; return logger;
} }
public static @NotNull BukkitAudiences getAudiences() { public static @NotNull BukkitAudiences getAudiences() {

View File

@ -30,7 +30,7 @@ public class OptVillagersRadius implements VillagerOptimizerCommand {
private final int max_radius; private final int max_radius;
public OptVillagersRadius() { public OptVillagersRadius() {
Config config = VillagerOptimizer.getConfiguration(); Config config = VillagerOptimizer.config();
this.max_radius = config.getInt("optimization-methods.commands.optimizevillagers.max-block-radius", 100); this.max_radius = config.getInt("optimization-methods.commands.optimizevillagers.max-block-radius", 100);
this.cooldown = config.getInt("optimization-methods.commands.optimizevillagers.cooldown-seconds", 600, this.cooldown = config.getInt("optimization-methods.commands.optimizevillagers.cooldown-seconds", 600,
"Cooldown in seconds until a villager can be optimized again using the command.\n" + "Cooldown in seconds until a villager can be optimized again using the command.\n" +
@ -100,7 +100,7 @@ public class OptVillagersRadius implements VillagerOptimizerCommand {
Villager.Profession profession = villager.getProfession(); Villager.Profession profession = villager.getProfession();
if (profession.equals(Villager.Profession.NITWIT) || profession.equals(Villager.Profession.NONE)) continue; if (profession.equals(Villager.Profession.NITWIT) || profession.equals(Villager.Profession.NONE)) continue;
WrappedVillager wVillager = villagerCache.getOrAdd(villager); WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (player_has_cooldown_bypass || wVillager.canOptimize(cooldown)) { if (player_has_cooldown_bypass || wVillager.canOptimize(cooldown)) {
VillagerOptimizeEvent optimizeEvent = new VillagerOptimizeEvent(wVillager, OptimizationType.COMMAND, player); VillagerOptimizeEvent optimizeEvent = new VillagerOptimizeEvent(wVillager, OptimizationType.COMMAND, player);

View File

@ -28,7 +28,7 @@ public class UnOptVillagersRadius implements VillagerOptimizerCommand {
private final int max_radius; private final int max_radius;
public UnOptVillagersRadius() { public UnOptVillagersRadius() {
this.max_radius = VillagerOptimizer.getConfiguration() this.max_radius = VillagerOptimizer.config()
.getInt("optimization-methods.commands.unoptimizevillagers.max-block-radius", 100); .getInt("optimization-methods.commands.unoptimizevillagers.max-block-radius", 100);
} }
@ -93,7 +93,7 @@ public class UnOptVillagersRadius implements VillagerOptimizerCommand {
Villager.Profession profession = villager.getProfession(); Villager.Profession profession = villager.getProfession();
if (profession.equals(Villager.Profession.NITWIT) || profession.equals(Villager.Profession.NONE)) continue; if (profession.equals(Villager.Profession.NITWIT) || profession.equals(Villager.Profession.NONE)) continue;
WrappedVillager wVillager = villagerCache.getOrAdd(villager); WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (wVillager.isOptimized()) { if (wVillager.isOptimized()) {
VillagerUnoptimizeEvent unOptimizeEvent = new VillagerUnoptimizeEvent(wVillager, player, OptimizationType.COMMAND); VillagerUnoptimizeEvent unOptimizeEvent = new VillagerUnoptimizeEvent(wVillager, player, OptimizationType.COMMAND);

View File

@ -23,22 +23,25 @@ public class Config {
this.default_lang = Locale.forLanguageTag( this.default_lang = Locale.forLanguageTag(
getString("general.default-language", "en_us", getString("general.default-language", "en_us",
"The default language that will be used if auto-language is false or no matching language file was found.") "The default language that will be used if auto-language is false\n" +
"or no matching language file was found.")
.replace("_", "-")); .replace("_", "-"));
this.auto_lang = getBoolean("general.auto-language", true, this.auto_lang = getBoolean("general.auto-language", true,
"If set to true, will display messages based on client language"); "If set to true, will display messages based on client language");
this.cache_keep_time_seconds = getInt("general.cache-keep-time-seconds", 30, this.cache_keep_time_seconds = getInt("general.cache-keep-time-seconds", 30,
"The amount of time in seconds a villager will be kept in the plugin's cache."); "The amount of time in seconds a villager will be kept in the plugin's cache.");
this.support_other_plugins = getBoolean("general.support-avl-villagers", false, this.support_other_plugins = getBoolean("general.support-avl-villagers", false,
"Enable if you have previously used AntiVillagerLag (https://www.spigotmc.org/resources/antivillagerlag.102949/).\n" + "Enable if you have previously used AntiVillagerLag\n" +
"Tries to read pre-existing info like optimization state so players don't need to reoptimize their villagers."); "(https://www.spigotmc.org/resources/antivillagerlag.102949/).\n" +
"Tries to read pre-existing info like optimization state so players\n" +
"don't need to reoptimize their villagers.");
} }
public void saveConfig() { public void saveConfig() {
try { try {
this.config.save(); this.config.save();
} catch (Throwable throwable) { } catch (Throwable throwable) {
VillagerOptimizer.getPrefixedLogger().error("Failed to save config file!", throwable); VillagerOptimizer.logger().error("Failed to save config file!", throwable);
} }
} }

View File

@ -30,7 +30,7 @@ public class LanguageCache {
// Check if the lang folder has already been created // Check if the lang folder has already been created
File parent = langYML.getParentFile(); File parent = langYML.getParentFile();
if (!parent.exists() && !parent.mkdir()) if (!parent.exists() && !parent.mkdir())
VillagerOptimizer.getPrefixedLogger().error("Failed to create lang directory."); VillagerOptimizer.logger().error("Failed to create lang directory.");
// Check if the file already exists and save the one from the plugin's resources folder if it does not // Check if the file already exists and save the one from the plugin's resources folder if it does not
if (!langYML.exists()) if (!langYML.exists())
plugin.saveResource("lang/" + locale + ".yml", false); plugin.saveResource("lang/" + locale + ".yml", false);
@ -86,7 +86,7 @@ public class LanguageCache {
try { try {
this.lang.save(); this.lang.save();
} catch (Throwable throwable) { } catch (Throwable throwable) {
VillagerOptimizer.getPrefixedLogger().error("Failed to save language file: " + langYML.getName(), throwable); VillagerOptimizer.logger().error("Failed to save language file: " + langYML.getName(), throwable);
} }
} }

View File

@ -1,12 +1,9 @@
package me.xginko.villageroptimizer.modules; package me.xginko.villageroptimizer.modules;
import com.tcoded.folialib.impl.ServerImplementation;
import com.tcoded.folialib.wrapper.task.WrappedTask; import com.tcoded.folialib.wrapper.task.WrappedTask;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.utils.LocationUtil; import me.xginko.villageroptimizer.utils.LocationUtil;
import me.xginko.villageroptimizer.utils.Util;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.World; import org.bukkit.World;
@ -21,14 +18,15 @@ import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
public class VillagerChunkLimit implements VillagerOptimizerModule, Listener { public class VillagerChunkLimit extends VillagerOptimizerModule implements Listener {
private final ServerImplementation scheduler;
private final VillagerCache villagerCache;
private WrappedTask periodic_chunk_check; private WrappedTask periodic_chunk_check;
private final List<Villager.Profession> non_optimized_removal_priority, optimized_removal_priority; private final List<Villager.Profession> non_optimized_removal_priority, optimized_removal_priority;
private final long check_period; private final long check_period;
@ -36,20 +34,17 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
private final boolean log_enabled, skip_unloaded_entity_chunks; private final boolean log_enabled, skip_unloaded_entity_chunks;
protected VillagerChunkLimit() { protected VillagerChunkLimit() {
shouldEnable(); super("villager-chunk-limit");
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl(); config.master().addComment(configPath + ".enable",
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
"Checks chunks for too many villagers and removes excess villagers based on priority."); "Checks chunks for too many villagers and removes excess villagers based on priority.");
this.check_period = config.getInt(configPath() + ".check-period-in-ticks", 600, this.check_period = config.getInt(configPath + ".check-period-in-ticks", 600,
"Check all loaded chunks every X ticks. 1 second = 20 ticks\n" + "Check all loaded chunks every X ticks. 1 second = 20 ticks\n" +
"A shorter delay in between checks is more efficient but is also more resource intense.\n" + "A shorter delay in between checks is more efficient but is also more resource intense.\n" +
"A larger delay is less resource intense but could become inefficient."); "A larger delay is less resource intense but could become inefficient.");
this.skip_unloaded_entity_chunks = config.getBoolean(configPath() + ".skip-if-chunk-has-not-loaded-entities", true, this.skip_unloaded_entity_chunks = config.getBoolean(configPath + ".skip-if-chunk-has-not-loaded-entities", true,
"Does not check chunks that don't have their entities loaded."); "Does not check chunks that don't have their entities loaded.");
this.log_enabled = config.getBoolean(configPath() + ".log-removals", true); this.log_enabled = config.getBoolean(configPath + ".log-removals", true);
this.non_optimized_max_per_chunk = config.getInt(configPath() + ".unoptimized.max-per-chunk", 20, this.non_optimized_max_per_chunk = config.getInt(configPath + ".unoptimized.max-per-chunk", 20,
"The maximum amount of unoptimized villagers per chunk."); "The maximum amount of unoptimized villagers per chunk.");
final List<String> defaults = Stream.of( final List<String> defaults = Stream.of(
"NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER", "NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER",
@ -63,7 +58,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
return false; return false;
} }
}).collect(Collectors.toList()); }).collect(Collectors.toList());
this.non_optimized_removal_priority = config.getList(configPath() + ".unoptimized.removal-priority", defaults, this.non_optimized_removal_priority = config.getList(configPath + ".unoptimized.removal-priority", defaults,
"Professions that are in the top of the list are going to be scheduled for removal first.\n" + "Professions that are in the top of the list are going to be scheduled for removal first.\n" +
"Use enums from https://jd.papermc.io/paper/1.20/org/bukkit/entity/Villager.Profession.html") "Use enums from https://jd.papermc.io/paper/1.20/org/bukkit/entity/Villager.Profession.html")
.stream() .stream()
@ -79,9 +74,9 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
}) })
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.toList()); .collect(Collectors.toList());
this.optimized_max_per_chunk = config.getInt(configPath() + ".optimized.max-per-chunk", 60, this.optimized_max_per_chunk = config.getInt(configPath + ".optimized.max-per-chunk", 60,
"The maximum amount of optimized villagers per chunk."); "The maximum amount of optimized villagers per chunk.");
this.optimized_removal_priority = config.getList(configPath() + ".optimized.removal-priority", defaults) this.optimized_removal_priority = config.getList(configPath + ".optimized.removal-priority", defaults)
.stream() .stream()
.map(configuredProfession -> { .map(configuredProfession -> {
try { try {
@ -97,11 +92,6 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public String configPath() {
return "villager-chunk-limit";
}
@Override @Override
public void enable() { public void enable() {
final VillagerOptimizer plugin = VillagerOptimizer.getInstance(); final VillagerOptimizer plugin = VillagerOptimizer.getInstance();
@ -121,7 +111,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false); return VillagerOptimizer.config().getBoolean(configPath + ".enable", false);
} }
@Override @Override
@ -152,7 +142,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
for (Entity entity : chunk.getEntities()) { for (Entity entity : chunk.getEntities()) {
if (entity.getType().equals(EntityType.VILLAGER)) { if (entity.getType().equals(EntityType.VILLAGER)) {
Villager villager = (Villager) entity; Villager villager = (Villager) entity;
if (villagerCache.getOrAdd(villager).isOptimized()) { if (villagerCache.createIfAbsent(villager).isOptimized()) {
optimized_villagers.add(villager); optimized_villagers.add(villager);
} else { } else {
not_optimized_villagers.add(villager); not_optimized_villagers.add(villager);

View File

@ -1,73 +1,83 @@
package me.xginko.villageroptimizer.modules; package me.xginko.villageroptimizer.modules;
import com.tcoded.folialib.impl.ServerImplementation;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.modules.gameplay.*; import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.modules.optimization.OptimizeByBlock; import org.reflections.Reflections;
import me.xginko.villageroptimizer.modules.optimization.OptimizeByNametag; import org.reflections.scanners.Scanners;
import me.xginko.villageroptimizer.modules.optimization.OptimizeByWorkstation;
import me.xginko.villageroptimizer.utils.Util;
import net.kyori.adventure.text.Component;
import java.lang.reflect.Modifier;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set;
public interface VillagerOptimizerModule { public abstract class VillagerOptimizerModule {
String configPath(); private static final Reflections MODULES_PACKAGE = new Reflections(VillagerOptimizerModule.class.getPackage().getName());
void enable(); public static final Set<VillagerOptimizerModule> ENABLED_MODULES = new HashSet<>();
void disable();
boolean shouldEnable();
HashSet<VillagerOptimizerModule> MODULES = new HashSet<>(14); public abstract void enable();
public abstract void disable();
public abstract boolean shouldEnable();
static void reloadModules() { protected final VillagerOptimizer plugin;
MODULES.forEach(VillagerOptimizerModule::disable); protected final Config config;
MODULES.clear(); protected final VillagerCache villagerCache;
protected final ServerImplementation scheduler;
public final String configPath;
private final String logFormat;
MODULES.add(new OptimizeByNametag()); public VillagerOptimizerModule(String configPath) {
MODULES.add(new OptimizeByBlock()); this.plugin = VillagerOptimizer.getInstance();
MODULES.add(new OptimizeByWorkstation()); this.config = VillagerOptimizer.config();
this.villagerCache = VillagerOptimizer.getCache();
MODULES.add(new EnableLeashingVillagers()); this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
MODULES.add(new FixOptimisationAfterCure()); this.configPath = configPath;
MODULES.add(new RestockOptimizedTrades()); shouldEnable(); // Ensure enable option is always first
MODULES.add(new LevelOptimizedProfession()); String[] paths = configPath.split("\\.");
MODULES.add(new VisuallyHighlightOptimized()); if (paths.length <= 2) {
MODULES.add(new MakeVillagersSpawnAdult()); this.logFormat = "<" + configPath + "> {}";
MODULES.add(new PreventUnoptimizedTrading()); } else {
MODULES.add(new PreventOptimizedTargeting()); this.logFormat = "<" + paths[paths.length - 2] + "." + paths[paths.length - 1] + "> {}";
MODULES.add(new PreventOptimizedDamage()); }
MODULES.add(new UnoptimizeOnJobLoose());
MODULES.add(new VillagerChunkLimit());
MODULES.forEach(module -> {
if (module.shouldEnable()) module.enable();
});
} }
default void trace(String prefix, String message, Throwable t) { public static void reloadModules() {
VillagerOptimizer.getPrefixedLogger().trace("<{}> {}", prefix, message, t); ENABLED_MODULES.forEach(VillagerOptimizerModule::disable);
ENABLED_MODULES.clear();
for (Class<?> clazz : MODULES_PACKAGE.get(Scanners.SubTypes.of(VillagerOptimizerModule.class).asClass())) {
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) continue;
try {
VillagerOptimizerModule module = (VillagerOptimizerModule) clazz.getDeclaredConstructor().newInstance();
if (module.shouldEnable()) {
module.enable();
ENABLED_MODULES.add(module);
}
} catch (Throwable t) {
VillagerOptimizer.logger().error("Failed to load module {}", clazz.getSimpleName(), t);
}
}
} }
default void error(String message, Throwable t) { protected void error(String message, Throwable throwable) {
VillagerOptimizer.getPrefixedLogger().error("<{}> {}", logPrefix(), message, t); VillagerOptimizer.logger().error(logFormat, message, throwable);
} }
default void error(String message) { protected void error(String message) {
VillagerOptimizer.getPrefixedLogger().error("<{}> {}", logPrefix(), message); VillagerOptimizer.logger().error(logFormat, message);
} }
default void warn(String message) { protected void warn(String message) {
VillagerOptimizer.getPrefixedLogger().warn("<{}> {}", logPrefix(), message); VillagerOptimizer.logger().warn(logFormat, message);
} }
default void info(String message) { protected void info(String message) {
VillagerOptimizer.getPrefixedLogger().info(Component.text("<" + logPrefix() + "> " + message).color(Util.PL_COLOR)); VillagerOptimizer.logger().info(logFormat, message);
} }
default String logPrefix() { protected void notRecognized(Class<?> clazz, String unrecognized) {
String[] split = configPath().split("\\."); warn("Unable to parse " + clazz.getSimpleName() + " at '" + unrecognized + "'. Please check your configuration.");
if (split.length <= 2) return configPath();
return split[split.length - 2] + "." + split[split.length - 1];
} }
} }

View File

@ -1,9 +1,5 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import com.tcoded.folialib.impl.ServerImplementation;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.LocationUtil; import me.xginko.villageroptimizer.utils.LocationUtil;
import org.bukkit.GameMode; import org.bukkit.GameMode;
@ -19,32 +15,21 @@ import org.bukkit.event.entity.PlayerLeashEntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class EnableLeashingVillagers implements VillagerOptimizerModule, Listener { public class EnableLeashingVillagers extends VillagerOptimizerModule implements Listener {
private final ServerImplementation scheduler;
private final VillagerCache villagerCache;
private final boolean only_optimized, log_enabled; private final boolean only_optimized, log_enabled;
public EnableLeashingVillagers() { public EnableLeashingVillagers() {
shouldEnable(); super("gameplay.villagers-can-be-leashed");
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl(); config.master().addComment(configPath + ".enable",
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
"Enable leashing of villagers, enabling players to easily move villagers to where they want them to be."); "Enable leashing of villagers, enabling players to easily move villagers to where they want them to be.");
this.only_optimized = config.getBoolean(configPath() + ".only-optimized", false, this.only_optimized = config.getBoolean(configPath + ".only-optimized", false,
"If set to true, only optimized villagers can be leashed."); "If set to true, only optimized villagers can be leashed.");
this.log_enabled = config.getBoolean(configPath() + ".log", false); this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public String configPath() {
return "gameplay.villagers-can-be-leashed";
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -55,7 +40,7 @@ public class EnableLeashingVillagers implements VillagerOptimizerModule, Listene
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false); return config.getBoolean(configPath + ".enable", false);
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -68,7 +53,7 @@ public class EnableLeashingVillagers implements VillagerOptimizerModule, Listene
final Villager villager = (Villager) event.getRightClicked(); final Villager villager = (Villager) event.getRightClicked();
if (villager.isLeashed()) return; if (villager.isLeashed()) return;
if (only_optimized && !villagerCache.getOrAdd(villager).isOptimized()) return; if (only_optimized && !villagerCache.createIfAbsent(villager).isOptimized()) return;
event.setCancelled(true); // Cancel the event, so we don't interact with the villager event.setCancelled(true); // Cancel the event, so we don't interact with the villager

View File

@ -1,8 +1,7 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Villager; import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -13,18 +12,14 @@ import org.bukkit.event.entity.EntityTransformEvent;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class FixOptimisationAfterCure implements VillagerOptimizerModule, Listener { public class FixOptimisationAfterCure extends VillagerOptimizerModule implements Listener {
public FixOptimisationAfterCure() {} public FixOptimisationAfterCure() {
super("post-cure-optimization-fix");
@Override
public String configPath() {
return "post-cure-optimization-fix";
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -45,8 +40,8 @@ public class FixOptimisationAfterCure implements VillagerOptimizerModule, Listen
&& event.getTransformedEntity().getType().equals(EntityType.VILLAGER) && event.getTransformedEntity().getType().equals(EntityType.VILLAGER)
) { ) {
Villager villager = (Villager) event.getTransformedEntity(); Villager villager = (Villager) event.getTransformedEntity();
VillagerOptimizer.getFoliaLib().getImpl().runAtEntityLater(villager, () -> { scheduler.runAtEntityLater(villager, () -> {
WrappedVillager wVillager = VillagerOptimizer.getCache().getOrAdd(villager); WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
wVillager.setOptimizationType(wVillager.getOptimizationType()); wVillager.setOptimizationType(wVillager.getOptimizationType());
}, 2, TimeUnit.SECONDS); }, 2, TimeUnit.SECONDS);
} }

View File

@ -1,13 +1,11 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import com.tcoded.folialib.impl.ServerImplementation;
import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.config.Config; import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.utils.KyoriUtil; import me.xginko.villageroptimizer.utils.KyoriUtil;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Villager; import org.bukkit.entity.Villager;
@ -23,37 +21,27 @@ import org.bukkit.potion.PotionEffectType;
import java.time.Duration; import java.time.Duration;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class LevelOptimizedProfession implements VillagerOptimizerModule, Listener { public class LevelOptimizedProfession extends VillagerOptimizerModule implements Listener {
private final ServerImplementation scheduler;
private final VillagerCache villagerCache;
private final boolean notify_player; private final boolean notify_player;
private final long cooldown_millis; private final long cooldown_millis;
public LevelOptimizedProfession() { public LevelOptimizedProfession() {
shouldEnable(); super("gameplay.level-optimized-profession");
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl(); Config config = VillagerOptimizer.config();
this.villagerCache = VillagerOptimizer.getCache(); config.master().addComment(configPath,
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath(),
"This is needed to allow optimized villagers to level up.\n" + "This is needed to allow optimized villagers to level up.\n" +
"Temporarily enables the villagers AI to allow it to level up and then disables it again."); "Temporarily enables the villagers AI to allow it to level up and then disables it again.");
this.cooldown_millis = TimeUnit.SECONDS.toMillis( this.cooldown_millis = TimeUnit.SECONDS.toMillis(
config.getInt(configPath() + ".level-check-cooldown-seconds", 5, config.getInt(configPath + ".level-check-cooldown-seconds", 5,
"Cooldown in seconds until the level of a villager will be checked and updated again.\n" + "Cooldown in seconds until the level of a villager will be checked and updated again.\n" +
"Recommended to leave as is.")); "Recommended to leave as is."));
this.notify_player = config.getBoolean(configPath() + ".notify-player", true, this.notify_player = config.getBoolean(configPath + ".notify-player", true,
"Tell players to wait when a villager is leveling up."); "Tell players to wait when a villager is leveling up.");
} }
@Override
public String configPath() {
return "gameplay.level-optimized-profession";
}
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -74,7 +62,7 @@ public class LevelOptimizedProfession implements VillagerOptimizerModule, Listen
&& event.getInventory().getHolder() instanceof Villager && event.getInventory().getHolder() instanceof Villager
) { ) {
final Villager villager = (Villager) event.getInventory().getHolder(); final Villager villager = (Villager) event.getInventory().getHolder();
final WrappedVillager wVillager = villagerCache.getOrAdd(villager); final WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (!wVillager.isOptimized()) return; if (!wVillager.isOptimized()) return;
if (wVillager.canLevelUp(cooldown_millis)) { if (wVillager.canLevelUp(cooldown_millis)) {

View File

@ -1,6 +1,5 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Villager; import org.bukkit.entity.Villager;
@ -10,18 +9,19 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
public class MakeVillagersSpawnAdult implements VillagerOptimizerModule, Listener { public class MakeVillagersSpawnAdult extends VillagerOptimizerModule implements Listener {
public MakeVillagersSpawnAdult() {} public MakeVillagersSpawnAdult() {
super("gameplay.villagers-spawn-as-adults");
@Override config.master().addComment(configPath + ".enable",
public String configPath() { "Spawned villagers will immediately be adults.\n" +
return "gameplay.villagers-spawn-as-adults"; "This is to save some more resources as players don't have to keep unoptimized\n" +
"villagers loaded because they have to wait for them to turn into adults before they can\n" +
"optimize them.");
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -32,11 +32,7 @@ public class MakeVillagersSpawnAdult implements VillagerOptimizerModule, Listene
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false, return config.getBoolean(configPath + ".enable", false);
"Spawned villagers will immediately be adults.\n" +
"This is to save some more resources as players don't have to keep unoptimized\n" +
"villagers loaded because they have to wait for them to turn into adults before they can\n" +
"optimize them.");
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)

View File

@ -1,11 +1,7 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent; import com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import org.bukkit.Material;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Villager; import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -14,24 +10,24 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent;
import java.util.*; import java.util.Arrays;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener { public class PreventOptimizedDamage extends VillagerOptimizerModule implements Listener {
private final VillagerCache villagerCache;
private final Set<EntityDamageEvent.DamageCause> damage_causes_to_cancel; private final Set<EntityDamageEvent.DamageCause> damage_causes_to_cancel;
private final boolean cancel_knockback; private final boolean cancel_knockback;
public PreventOptimizedDamage() { public PreventOptimizedDamage() {
shouldEnable(); super("gameplay.prevent-damage-to-optimized");
this.villagerCache = VillagerOptimizer.getCache(); config.master().addComment(configPath + ".enable",
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
"Configure what kind of damage you want to cancel for optimized villagers here."); "Configure what kind of damage you want to cancel for optimized villagers here.");
this.cancel_knockback = config.getBoolean(configPath() + ".prevent-knockback-from-entity", true, this.cancel_knockback = config.getBoolean(configPath + ".prevent-knockback-from-entity", true,
"Prevents optimized villagers from getting knocked back by an attacking entity"); "Prevents optimized villagers from getting knocked back by an attacking entity");
this.damage_causes_to_cancel = config.getList(configPath() + ".damage-causes-to-cancel", this.damage_causes_to_cancel = config.getList(configPath + ".damage-causes-to-cancel",
Arrays.stream(EntityDamageEvent.DamageCause.values()).map(Enum::name).sorted().collect(Collectors.toList()), Arrays.stream(EntityDamageEvent.DamageCause.values()).map(Enum::name).sorted().collect(Collectors.toList()),
"These are all current entries in the game. Remove what you do not need blocked.\n" + "These are all current entries in the game. Remove what you do not need blocked.\n" +
"If you want a description or need to add a previously removed type, refer to:\n" + "If you want a description or need to add a previously removed type, refer to:\n" +
@ -50,14 +46,8 @@ public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener
.collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityDamageEvent.DamageCause.class))); .collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityDamageEvent.DamageCause.class)));
} }
@Override
public String configPath() {
return "gameplay.prevent-damage-to-optimized";
}
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -68,7 +58,7 @@ public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", true); return config.getBoolean(configPath + ".enable", true);
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -76,7 +66,7 @@ public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener
if ( if (
event.getEntityType().equals(EntityType.VILLAGER) event.getEntityType().equals(EntityType.VILLAGER)
&& damage_causes_to_cancel.contains(event.getCause()) && damage_causes_to_cancel.contains(event.getCause())
&& villagerCache.getOrAdd((Villager) event.getEntity()).isOptimized() && villagerCache.createIfAbsent((Villager) event.getEntity()).isOptimized()
) { ) {
event.setCancelled(true); event.setCancelled(true);
} }
@ -87,7 +77,7 @@ public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener
if ( if (
cancel_knockback cancel_knockback
&& event.getEntityType().equals(EntityType.VILLAGER) && event.getEntityType().equals(EntityType.VILLAGER)
&& villagerCache.getOrAdd((Villager) event.getEntity()).isOptimized() && villagerCache.createIfAbsent((Villager) event.getEntity()).isOptimized()
) { ) {
event.setCancelled(true); event.setCancelled(true);
} }

View File

@ -1,8 +1,6 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import com.destroystokyo.paper.event.entity.EntityPathfindEvent; import com.destroystokyo.paper.event.entity.EntityPathfindEvent;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
@ -15,22 +13,16 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.entity.EntityTargetEvent;
public class PreventOptimizedTargeting implements VillagerOptimizerModule, Listener { public class PreventOptimizedTargeting extends VillagerOptimizerModule implements Listener {
private final VillagerCache villagerCache;
public PreventOptimizedTargeting() { public PreventOptimizedTargeting() {
this.villagerCache = VillagerOptimizer.getCache(); super("gameplay.prevent-entities-from-targeting-optimized");
} config.master().addComment(configPath + ".enable",
"Prevents hostile entities from targeting optimized villagers.");
@Override
public String configPath() {
return "gameplay.prevent-entities-from-targeting-optimized";
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -41,8 +33,7 @@ public class PreventOptimizedTargeting implements VillagerOptimizerModule, Liste
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", true, return config.getBoolean(configPath + ".enable", true);
"Prevents hostile entities from targeting optimized villagers.");
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -51,7 +42,7 @@ public class PreventOptimizedTargeting implements VillagerOptimizerModule, Liste
if ( if (
target != null target != null
&& target.getType().equals(EntityType.VILLAGER) && target.getType().equals(EntityType.VILLAGER)
&& villagerCache.getOrAdd((Villager) target).isOptimized() && villagerCache.createIfAbsent((Villager) target).isOptimized()
) { ) {
event.setTarget(null); event.setTarget(null);
event.setCancelled(true); event.setCancelled(true);
@ -64,7 +55,7 @@ public class PreventOptimizedTargeting implements VillagerOptimizerModule, Liste
if ( if (
target != null target != null
&& target.getType().equals(EntityType.VILLAGER) && target.getType().equals(EntityType.VILLAGER)
&& villagerCache.getOrAdd((Villager) target).isOptimized() && villagerCache.createIfAbsent((Villager) target).isOptimized()
) { ) {
event.setCancelled(true); event.setCancelled(true);
} }
@ -75,7 +66,7 @@ public class PreventOptimizedTargeting implements VillagerOptimizerModule, Liste
if ( if (
event.getEntityType().equals(EntityType.VILLAGER) event.getEntityType().equals(EntityType.VILLAGER)
&& event.getDamager() instanceof Mob && event.getDamager() instanceof Mob
&& villagerCache.getOrAdd((Villager) event.getEntity()).isOptimized() && villagerCache.createIfAbsent((Villager) event.getEntity()).isOptimized()
) { ) {
((Mob) event.getDamager()).setTarget(null); ((Mob) event.getDamager()).setTarget(null);
} }

View File

@ -1,8 +1,6 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.Permissions; import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.KyoriUtil; import me.xginko.villageroptimizer.utils.KyoriUtil;
@ -16,31 +14,22 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.inventory.TradeSelectEvent; import org.bukkit.event.inventory.TradeSelectEvent;
public class PreventUnoptimizedTrading implements VillagerOptimizerModule, Listener { public class PreventUnoptimizedTrading extends VillagerOptimizerModule implements Listener {
private final VillagerCache villagerCache;
private final boolean notify_player; private final boolean notify_player;
public PreventUnoptimizedTrading() { public PreventUnoptimizedTrading() {
shouldEnable(); super("gameplay.prevent-trading-with-unoptimized");
this.villagerCache = VillagerOptimizer.getCache(); config.master().addComment(configPath + ".enable",
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
"Will prevent players from selecting and using trades of unoptimized villagers.\n" + "Will prevent players from selecting and using trades of unoptimized villagers.\n" +
"Use this if you have a lot of villagers and therefore want to force your players to optimize them.\n" + "Use this if you have a lot of villagers and therefore want to force your players to optimize them.\n" +
"Inventories can still be opened so players can move villagers around."); "Inventories can still be opened so players can move villagers around.");
this.notify_player = config.getBoolean(configPath() + ".notify-player", true, this.notify_player = config.getBoolean(configPath + ".notify-player", true,
"Sends players a message when they try to trade with an unoptimized villager."); "Sends players a message when they try to trade with an unoptimized villager.");
} }
@Override
public String configPath() {
return "gameplay.prevent-trading-with-unoptimized";
}
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -51,7 +40,7 @@ public class PreventUnoptimizedTrading implements VillagerOptimizerModule, Liste
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false); return config.getBoolean(configPath + ".enable", false);
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -59,14 +48,13 @@ public class PreventUnoptimizedTrading implements VillagerOptimizerModule, Liste
if (!event.getInventory().getType().equals(InventoryType.MERCHANT)) return; if (!event.getInventory().getType().equals(InventoryType.MERCHANT)) return;
if (event.getWhoClicked().hasPermission(Permissions.Bypass.TRADE_PREVENTION.get())) return; if (event.getWhoClicked().hasPermission(Permissions.Bypass.TRADE_PREVENTION.get())) return;
if (!(event.getInventory().getHolder() instanceof Villager)) return; if (!(event.getInventory().getHolder() instanceof Villager)) return;
if (villagerCache.getOrAdd((Villager) event.getInventory().getHolder()).isOptimized()) return; if (villagerCache.createIfAbsent((Villager) event.getInventory().getHolder()).isOptimized()) return;
event.setCancelled(true); event.setCancelled(true);
if (notify_player) { if (notify_player) {
Player player = (Player) event.getWhoClicked(); Player player = (Player) event.getWhoClicked();
VillagerOptimizer.getLang(player.locale()).optimize_for_trading VillagerOptimizer.getLang(player.locale()).optimize_for_trading.forEach(line -> KyoriUtil.sendMessage(player, line));
.forEach(line -> KyoriUtil.sendMessage(player, line));
} }
} }
@ -75,14 +63,13 @@ public class PreventUnoptimizedTrading implements VillagerOptimizerModule, Liste
if (!event.getInventory().getType().equals(InventoryType.MERCHANT)) return; if (!event.getInventory().getType().equals(InventoryType.MERCHANT)) return;
if (event.getWhoClicked().hasPermission(Permissions.Bypass.TRADE_PREVENTION.get())) return; if (event.getWhoClicked().hasPermission(Permissions.Bypass.TRADE_PREVENTION.get())) return;
if (!(event.getInventory().getHolder() instanceof Villager)) return; if (!(event.getInventory().getHolder() instanceof Villager)) return;
if (villagerCache.getOrAdd((Villager) event.getInventory().getHolder()).isOptimized()) return; if (villagerCache.createIfAbsent((Villager) event.getInventory().getHolder()).isOptimized()) return;
event.setCancelled(true); event.setCancelled(true);
if (notify_player) { if (notify_player) {
Player player = (Player) event.getWhoClicked(); Player player = (Player) event.getWhoClicked();
VillagerOptimizer.getLang(player.locale()).optimize_for_trading VillagerOptimizer.getLang(player.locale()).optimize_for_trading.forEach(line -> KyoriUtil.sendMessage(player, line));
.forEach(line -> KyoriUtil.sendMessage(player, line));
} }
} }
} }

View File

@ -1,14 +1,12 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.utils.LocationUtil;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.Permissions; import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.utils.KyoriUtil; import me.xginko.villageroptimizer.utils.KyoriUtil;
import me.xginko.villageroptimizer.utils.LocationUtil;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -21,34 +19,25 @@ import org.bukkit.event.player.PlayerInteractEntityEvent;
import java.time.Duration; import java.time.Duration;
public class RestockOptimizedTrades implements VillagerOptimizerModule, Listener { public class RestockOptimizedTrades extends VillagerOptimizerModule implements Listener {
private final VillagerCache villagerCache;
private final long restock_delay_millis; private final long restock_delay_millis;
private final boolean log_enabled, notify_player; private final boolean log_enabled, notify_player;
public RestockOptimizedTrades() { public RestockOptimizedTrades() {
shouldEnable(); super("gameplay.restock-optimized-trades");
this.villagerCache = VillagerOptimizer.getCache(); config.master().addComment(configPath,
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath(),
"This is for automatic restocking of trades for optimized villagers. Optimized Villagers\n" + "This is for automatic restocking of trades for optimized villagers. Optimized Villagers\n" +
"don't have enough AI to restock their trades naturally, so this is here as a workaround."); "don't have enough AI to restock their trades naturally, so this is here as a workaround.");
this.restock_delay_millis = config.getInt(configPath() + ".delay-in-ticks", 1000, this.restock_delay_millis = config.getInt(configPath + ".delay-in-ticks", 1000,
"1 second = 20 ticks. There are 24.000 ticks in a single minecraft day.") * 50L; "1 second = 20 ticks. There are 24.000 ticks in a single minecraft day.") * 50L;
this.notify_player = config.getBoolean(configPath() + ".notify-player", true, this.notify_player = config.getBoolean(configPath + ".notify-player", true,
"Sends the player a message when the trades were restocked on a clicked villager."); "Sends the player a message when the trades were restocked on a clicked villager.");
this.log_enabled = config.getBoolean(configPath() + ".log", false); this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public String configPath() {
return "gameplay.restock-optimized-trades";
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -66,7 +55,7 @@ public class RestockOptimizedTrades implements VillagerOptimizerModule, Listener
private void onInteract(PlayerInteractEntityEvent event) { private void onInteract(PlayerInteractEntityEvent event) {
if (!event.getRightClicked().getType().equals(EntityType.VILLAGER)) return; if (!event.getRightClicked().getType().equals(EntityType.VILLAGER)) return;
final WrappedVillager wVillager = villagerCache.getOrAdd((Villager) event.getRightClicked()); final WrappedVillager wVillager = villagerCache.createIfAbsent((Villager) event.getRightClicked());
if (!wVillager.isOptimized()) return; if (!wVillager.isOptimized()) return;
final Player player = event.getPlayer(); final Player player = event.getPlayer();

View File

@ -1,32 +1,24 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import me.xginko.villageroptimizer.enums.OptimizationType; import me.xginko.villageroptimizer.enums.OptimizationType;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.VillagerCareerChangeEvent; import org.bukkit.event.entity.VillagerCareerChangeEvent;
public class UnoptimizeOnJobLoose implements VillagerOptimizerModule, Listener { public class UnoptimizeOnJobLoose extends VillagerOptimizerModule implements Listener {
private final VillagerCache villagerCache;
public UnoptimizeOnJobLoose() { public UnoptimizeOnJobLoose() {
this.villagerCache = VillagerOptimizer.getCache(); super("gameplay.unoptimize-on-job-loose");
} config.master().addComment(configPath + ".enable",
"Villagers that get their jobs reset will become unoptimized again.");
@Override
public String configPath() {
return "gameplay.unoptimize-on-job-loose";
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -37,14 +29,13 @@ public class UnoptimizeOnJobLoose implements VillagerOptimizerModule, Listener {
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", true, return config.getBoolean(configPath + ".enable", true);
"Villagers that get their jobs reset will become unoptimized again.");
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onJobReset(VillagerCareerChangeEvent event) { private void onJobReset(VillagerCareerChangeEvent event) {
if (!event.getReason().equals(VillagerCareerChangeEvent.ChangeReason.LOSING_JOB)) return; if (!event.getReason().equals(VillagerCareerChangeEvent.ChangeReason.LOSING_JOB)) return;
final WrappedVillager wrappedVillager = villagerCache.getOrAdd(event.getEntity()); final WrappedVillager wrappedVillager = villagerCache.createIfAbsent(event.getEntity());
if (wrappedVillager.isOptimized()) { if (wrappedVillager.isOptimized()) {
wrappedVillager.setOptimizationType(OptimizationType.NONE); wrappedVillager.setOptimizationType(OptimizationType.NONE);
} }

View File

@ -1,8 +1,5 @@
package me.xginko.villageroptimizer.modules.gameplay; package me.xginko.villageroptimizer.modules.gameplay;
import com.tcoded.folialib.impl.ServerImplementation;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent; import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent; import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
@ -12,26 +9,16 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
public class VisuallyHighlightOptimized implements VillagerOptimizerModule, Listener { public class VisuallyHighlightOptimized extends VillagerOptimizerModule implements Listener {
private final ServerImplementation scheduler;
public VisuallyHighlightOptimized() { public VisuallyHighlightOptimized() {
shouldEnable(); super("gameplay.outline-optimized-villagers");
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment("gameplay.outline-optimized-villagers.enable", config.master().addComment("gameplay.outline-optimized-villagers.enable",
"Will make optimized villagers glow."); "Will make optimized villagers glow.");
} }
@Override
public String configPath() {
return "gameplay.outline-optimized-villagers";
}
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -42,7 +29,7 @@ public class VisuallyHighlightOptimized implements VillagerOptimizerModule, List
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean("gameplay.outline-optimized-villagers.enable", false); return config.getBoolean("gameplay.outline-optimized-villagers.enable", false);
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)

View File

@ -1,16 +1,14 @@
package me.xginko.villageroptimizer.modules.optimization; package me.xginko.villageroptimizer.modules.optimization;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.OptimizationType; import me.xginko.villageroptimizer.enums.OptimizationType;
import me.xginko.villageroptimizer.enums.Permissions; import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent; import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent; import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.utils.KyoriUtil; import me.xginko.villageroptimizer.utils.KyoriUtil;
import me.xginko.villageroptimizer.utils.LocationUtil; import me.xginko.villageroptimizer.utils.LocationUtil;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.wrapper.WrappedVillager; import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.Location; import org.bukkit.Location;
@ -33,22 +31,19 @@ import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class OptimizeByBlock implements VillagerOptimizerModule, Listener { public class OptimizeByBlock extends VillagerOptimizerModule implements Listener {
private final VillagerCache villagerCache;
private final Set<Material> blocks_that_disable; private final Set<Material> blocks_that_disable;
private final long cooldown_millis; private final long cooldown_millis;
private final double search_radius; private final double search_radius;
private final boolean only_while_sneaking, notify_player, log_enabled; private final boolean only_while_sneaking, notify_player, log_enabled;
public OptimizeByBlock() { public OptimizeByBlock() {
shouldEnable(); super("optimization-methods.block-optimization");
this.villagerCache = VillagerOptimizer.getCache(); config.master().addComment(configPath + ".enable",
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
"When enabled, the closest villager standing near a configured block being placed will be optimized.\n" + "When enabled, the closest villager standing near a configured block being placed will be optimized.\n" +
"If a configured block is broken nearby, the closest villager will become unoptimized again."); "If a configured block is broken nearby, the closest villager will become unoptimized again.");
this.blocks_that_disable = config.getList(configPath() + ".materials", Arrays.asList( this.blocks_that_disable = config.getList(configPath + ".materials", Arrays.asList(
"LAPIS_BLOCK", "GLOWSTONE", "IRON_BLOCK" "LAPIS_BLOCK", "GLOWSTONE", "IRON_BLOCK"
), "Values here need to be valid bukkit Material enums for your server version.") ), "Values here need to be valid bukkit Material enums for your server version.")
.stream() .stream()
@ -64,27 +59,21 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
.filter(Objects::nonNull) .filter(Objects::nonNull)
.collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class)));
this.cooldown_millis = TimeUnit.SECONDS.toMillis( this.cooldown_millis = TimeUnit.SECONDS.toMillis(
config.getInt(configPath() + ".optimize-cooldown-seconds", 600, config.getInt(configPath + ".optimize-cooldown-seconds", 600,
"Cooldown in seconds until a villager can be optimized again by using specific blocks.\n" + "Cooldown in seconds until a villager can be optimized again by using specific blocks.\n" +
"Here for configuration freedom. Recommended to leave as is to not enable any exploitable behavior.")); "Here for configuration freedom. Recommended to leave as is to not enable any exploitable behavior."));
this.search_radius = config.getDouble(configPath() + ".search-radius-in-blocks", 2.0, this.search_radius = config.getDouble(configPath + ".search-radius-in-blocks", 2.0,
"The radius in blocks a villager can be away from the player when he places an optimize block.\n" + "The radius in blocks a villager can be away from the player when he places an optimize block.\n" +
"The closest unoptimized villager to the player will be optimized.") / 2; "The closest unoptimized villager to the player will be optimized.") / 2;
this.only_while_sneaking = config.getBoolean(configPath() + ".only-when-sneaking", true, this.only_while_sneaking = config.getBoolean(configPath + ".only-when-sneaking", true,
"Only optimize/unoptimize by block when player is sneaking during place or break."); "Only optimize/unoptimize by block when player is sneaking during place or break.");
this.notify_player = config.getBoolean(configPath() + ".notify-player", true, this.notify_player = config.getBoolean(configPath + ".notify-player", true,
"Sends players a message when they successfully optimized or unoptimized a villager."); "Sends players a message when they successfully optimized or unoptimized a villager.");
this.log_enabled = config.getBoolean(configPath() + ".log", false); this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public String configPath() {
return "optimization-methods.block-optimization";
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -95,7 +84,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false); return config.getBoolean(configPath + ".enable", false);
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -117,7 +106,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
final double distance = LocationUtil.relDistance3DSquared(villager.getLocation(), blockLoc); final double distance = LocationUtil.relDistance3DSquared(villager.getLocation(), blockLoc);
if (distance >= closestDistance) continue; if (distance >= closestDistance) continue;
final WrappedVillager wVillager = villagerCache.getOrAdd(villager); final WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (wVillager.canOptimize(cooldown_millis)) { if (wVillager.canOptimize(cooldown_millis)) {
closestOptimizableVillager = wVillager; closestOptimizableVillager = wVillager;
closestDistance = distance; closestDistance = distance;
@ -184,7 +173,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
final double distance = LocationUtil.relDistance3DSquared(villager.getLocation(), blockLoc); final double distance = LocationUtil.relDistance3DSquared(villager.getLocation(), blockLoc);
if (distance >= closestDistance) continue; if (distance >= closestDistance) continue;
final WrappedVillager wVillager = villagerCache.getOrAdd(villager); final WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (wVillager.isOptimized()) { if (wVillager.isOptimized()) {
closestOptimizedVillager = wVillager; closestOptimizedVillager = wVillager;
closestDistance = distance; closestDistance = distance;

View File

@ -1,17 +1,15 @@
package me.xginko.villageroptimizer.modules.optimization; package me.xginko.villageroptimizer.modules.optimization;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.utils.LocationUtil;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.OptimizationType; import me.xginko.villageroptimizer.enums.OptimizationType;
import me.xginko.villageroptimizer.enums.Permissions; import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent; import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent; import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.utils.KyoriUtil; import me.xginko.villageroptimizer.utils.KyoriUtil;
import me.xginko.villageroptimizer.utils.LocationUtil;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
@ -33,42 +31,33 @@ import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class OptimizeByNametag implements VillagerOptimizerModule, Listener { public class OptimizeByNametag extends VillagerOptimizerModule implements Listener {
private final VillagerCache villagerCache;
private final Set<String> nametags; private final Set<String> nametags;
private final long cooldown; private final long cooldown;
private final boolean consume_nametag, notify_player, log_enabled; private final boolean consume_nametag, notify_player, log_enabled;
public OptimizeByNametag() { public OptimizeByNametag() {
shouldEnable(); super("optimization-methods.nametag-optimization");
this.villagerCache = VillagerOptimizer.getCache(); config.master().addComment(configPath + ".enable",
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
"Enable optimization by naming villagers to one of the names configured below.\n" + "Enable optimization by naming villagers to one of the names configured below.\n" +
"Nametag optimized villagers will be unoptimized again when they are renamed to something else."); "Nametag optimized villagers will be unoptimized again when they are renamed to something else.");
this.nametags = config.getList(configPath() + ".names", Arrays.asList("Optimize", "DisableAI"), this.nametags = config.getList(configPath + ".names", Arrays.asList("Optimize", "DisableAI"),
"Names are case insensitive, capital letters won't matter.") "Names are case insensitive, capital letters won't matter.")
.stream().map(String::toLowerCase).collect(Collectors.toCollection(HashSet::new)); .stream().map(String::toLowerCase).collect(Collectors.toCollection(HashSet::new));
this.consume_nametag = config.getBoolean(configPath() + ".nametags-get-consumed", true, this.consume_nametag = config.getBoolean(configPath + ".nametags-get-consumed", true,
"Enable or disable consumption of the used nametag item."); "Enable or disable consumption of the used nametag item.");
this.cooldown = TimeUnit.SECONDS.toMillis( this.cooldown = TimeUnit.SECONDS.toMillis(
config.getInt(configPath() + ".optimize-cooldown-seconds", 600, config.getInt(configPath + ".optimize-cooldown-seconds", 600,
"Cooldown in seconds until a villager can be optimized again using a nametag.\n" + "Cooldown in seconds until a villager can be optimized again using a nametag.\n" +
"Here for configuration freedom. Recommended to leave as is to not enable any exploitable behavior.")); "Here for configuration freedom. Recommended to leave as is to not enable any exploitable behavior."));
this.notify_player = config.getBoolean(configPath() + ".notify-player", true, this.notify_player = config.getBoolean(configPath + ".notify-player", true,
"Sends players a message when they successfully optimized a villager."); "Sends players a message when they successfully optimized a villager.");
this.log_enabled = config.getBoolean(configPath() + ".log", false); this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public String configPath() {
return "optimization-methods.nametag-optimization";
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -79,7 +68,7 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener {
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", true); return config.getBoolean(configPath + ".enable", true);
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -97,7 +86,7 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener {
final String nameTagPlainText = ChatColor.stripColor(meta.getDisplayName()); final String nameTagPlainText = ChatColor.stripColor(meta.getDisplayName());
final Villager villager = (Villager) event.getRightClicked(); final Villager villager = (Villager) event.getRightClicked();
final WrappedVillager wVillager = villagerCache.getOrAdd(villager); final WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (nametags.contains(nameTagPlainText.toLowerCase())) { if (nametags.contains(nameTagPlainText.toLowerCase())) {
if (wVillager.canOptimize(cooldown) || player.hasPermission(Permissions.Bypass.NAMETAG_COOLDOWN.get())) { if (wVillager.canOptimize(cooldown) || player.hasPermission(Permissions.Bypass.NAMETAG_COOLDOWN.get())) {

View File

@ -1,18 +1,15 @@
package me.xginko.villageroptimizer.modules.optimization; package me.xginko.villageroptimizer.modules.optimization;
import com.tcoded.folialib.impl.ServerImplementation;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer; import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.utils.LocationUtil;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.OptimizationType; import me.xginko.villageroptimizer.enums.OptimizationType;
import me.xginko.villageroptimizer.enums.Permissions; import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent; import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent; import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule; import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.utils.KyoriUtil; import me.xginko.villageroptimizer.utils.KyoriUtil;
import me.xginko.villageroptimizer.utils.LocationUtil;
import me.xginko.villageroptimizer.utils.Util;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -30,48 +27,37 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener { public class OptimizeByWorkstation extends VillagerOptimizerModule implements Listener {
private final ServerImplementation scheduler;
private final VillagerCache villagerCache;
private final long cooldown_millis; private final long cooldown_millis;
private final double search_radius; private final double search_radius;
private final int check_duration_ticks; private final int check_duration_ticks;
private final boolean only_while_sneaking, log_enabled, notify_player; private final boolean only_while_sneaking, log_enabled, notify_player;
public OptimizeByWorkstation() { public OptimizeByWorkstation() {
shouldEnable(); super("optimization-methods.workstation-optimization");
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl(); config.master().addComment(configPath + ".enable",
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
"When enabled, villagers that have a job and have been traded with at least once will become optimized,\n" + "When enabled, villagers that have a job and have been traded with at least once will become optimized,\n" +
"if near their workstation. If the workstation is broken, the villager will become unoptimized again."); "if near their workstation. If the workstation is broken, the villager will become unoptimized again.");
this.check_duration_ticks = Math.max(config.getInt(configPath() + ".check-linger-duration-ticks", 100, this.check_duration_ticks = Math.max(config.getInt(configPath + ".check-linger-duration-ticks", 100,
"After a workstation has been placed, the plugin will wait for the configured amount of time in ticks\n" + "After a workstation has been placed, the plugin will wait for the configured amount of time in ticks\n" +
"for a villager to claim that workstation. Not recommended to go below 100 ticks."), 1); "for a villager to claim that workstation. Not recommended to go below 100 ticks."), 1);
this.search_radius = config.getDouble(configPath() + ".search-radius-in-blocks", 2.0, this.search_radius = config.getDouble(configPath + ".search-radius-in-blocks", 2.0,
"The radius in blocks a villager can be away from the player when he places a workstation.\n" + "The radius in blocks a villager can be away from the player when he places a workstation.\n" +
"The closest unoptimized villager to the player will be optimized."); "The closest unoptimized villager to the player will be optimized.");
this.cooldown_millis = TimeUnit.SECONDS.toMillis( this.cooldown_millis = TimeUnit.SECONDS.toMillis(
Math.max(1, config.getInt(configPath() + ".optimize-cooldown-seconds", 600, Math.max(1, config.getInt(configPath + ".optimize-cooldown-seconds", 600,
"Cooldown in seconds until a villager can be optimized again using a workstation.\n" + "Cooldown in seconds until a villager can be optimized again using a workstation.\n" +
"Here for configuration freedom. Recommended to leave as is to not enable any exploitable behavior."))); "Here for configuration freedom. Recommended to leave as is to not enable any exploitable behavior.")));
this.only_while_sneaking = config.getBoolean(configPath() + ".only-when-sneaking", true, this.only_while_sneaking = config.getBoolean(configPath + ".only-when-sneaking", true,
"Only optimize/unoptimize by workstation when player is sneaking during place or break. Useful for villager rolling."); "Only optimize/unoptimize by workstation when player is sneaking during place or break. Useful for villager rolling.");
this.notify_player = config.getBoolean(configPath() + ".notify-player", true, this.notify_player = config.getBoolean(configPath + ".notify-player", true,
"Sends players a message when they successfully optimized a villager."); "Sends players a message when they successfully optimized a villager.");
this.log_enabled = config.getBoolean(configPath() + ".log", false); this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public String configPath() {
return "optimization-methods.workstation-optimization";
} }
@Override @Override
public void enable() { public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin); plugin.getServer().getPluginManager().registerEvents(this, plugin);
} }
@ -82,7 +68,7 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
@Override @Override
public boolean shouldEnable() { public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false); return config.getBoolean(configPath + ".enable", false);
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -107,7 +93,7 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
for (Villager villager : workstationLoc.getNearbyEntitiesByType(Villager.class, search_radius)) { for (Villager villager : workstationLoc.getNearbyEntitiesByType(Villager.class, search_radius)) {
if (villager.getProfession() != workstationProfession) continue; if (villager.getProfession() != workstationProfession) continue;
WrappedVillager wrapped = villagerCache.getOrAdd(villager); WrappedVillager wrapped = villagerCache.createIfAbsent(villager);
if (wrapped.getJobSite() == null) continue; if (wrapped.getJobSite() == null) continue;
if (wrapped.getJobSite().getWorld().getUID() != workstationLoc.getWorld().getUID()) continue; if (wrapped.getJobSite().getWorld().getUID() != workstationLoc.getWorld().getUID()) continue;
if (LocationUtil.relDistance3DSquared(wrapped.getJobSite(), workstationLoc) > 1) continue; if (LocationUtil.relDistance3DSquared(wrapped.getJobSite(), workstationLoc) > 1) continue;
@ -181,7 +167,7 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
final double distance = LocationUtil.relDistance3DSquared(villager.getLocation(), workstationLoc); final double distance = LocationUtil.relDistance3DSquared(villager.getLocation(), workstationLoc);
if (distance >= closestDistance) continue; if (distance >= closestDistance) continue;
WrappedVillager wrapped = villagerCache.getOrAdd(villager); WrappedVillager wrapped = villagerCache.createIfAbsent(villager);
if (wrapped.isOptimized()) { if (wrapped.isOptimized()) {
closestOptimized = wrapped; closestOptimized = wrapped;

View File

@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
public interface VillagerDataHandler { public interface VillagerDataHandler {
static VillagerDataHandler[] forVillager(Villager villager) { static VillagerDataHandler[] forVillager(Villager villager) {
if (VillagerOptimizer.getConfiguration().support_other_plugins) { if (VillagerOptimizer.config().support_other_plugins) {
return new VillagerDataHandler[]{ return new VillagerDataHandler[]{
new MainVillagerDataHandlerImpl(villager), new MainVillagerDataHandlerImpl(villager),
new AVLVillagerDataHandlerImpl(villager) new AVLVillagerDataHandlerImpl(villager)