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

View File

@ -26,7 +26,7 @@ public final class VillagerCache {
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());
return wrappedVillager == null ? this.add(new WrappedVillager(villager)) : this.add(wrappedVillager);
}

View File

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

View File

@ -30,7 +30,7 @@ public class OptVillagersRadius implements VillagerOptimizerCommand {
private final int max_radius;
public OptVillagersRadius() {
Config config = VillagerOptimizer.getConfiguration();
Config config = VillagerOptimizer.config();
this.max_radius = config.getInt("optimization-methods.commands.optimizevillagers.max-block-radius", 100);
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" +
@ -100,7 +100,7 @@ public class OptVillagersRadius implements VillagerOptimizerCommand {
Villager.Profession profession = villager.getProfession();
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)) {
VillagerOptimizeEvent optimizeEvent = new VillagerOptimizeEvent(wVillager, OptimizationType.COMMAND, player);

View File

@ -28,7 +28,7 @@ public class UnOptVillagersRadius implements VillagerOptimizerCommand {
private final int max_radius;
public UnOptVillagersRadius() {
this.max_radius = VillagerOptimizer.getConfiguration()
this.max_radius = VillagerOptimizer.config()
.getInt("optimization-methods.commands.unoptimizevillagers.max-block-radius", 100);
}
@ -93,7 +93,7 @@ public class UnOptVillagersRadius implements VillagerOptimizerCommand {
Villager.Profession profession = villager.getProfession();
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()) {
VillagerUnoptimizeEvent unOptimizeEvent = new VillagerUnoptimizeEvent(wVillager, player, OptimizationType.COMMAND);

View File

@ -23,22 +23,25 @@ public class Config {
this.default_lang = Locale.forLanguageTag(
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("_", "-"));
this.auto_lang = getBoolean("general.auto-language", true,
"If set to true, will display messages based on client language");
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.");
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" +
"Tries to read pre-existing info like optimization state so players don't need to reoptimize their villagers.");
"Enable if you have previously used AntiVillagerLag\n" +
"(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() {
try {
this.config.save();
} 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
File parent = langYML.getParentFile();
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
if (!langYML.exists())
plugin.saveResource("lang/" + locale + ".yml", false);
@ -86,7 +86,7 @@ public class LanguageCache {
try {
this.lang.save();
} 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;
import com.tcoded.folialib.impl.ServerImplementation;
import com.tcoded.folialib.wrapper.task.WrappedTask;
import me.xginko.villageroptimizer.VillagerCache;
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.Util;
import org.bukkit.Chunk;
import org.bukkit.Server;
import org.bukkit.World;
@ -21,14 +18,15 @@ import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
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.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 final List<Villager.Profession> non_optimized_removal_priority, optimized_removal_priority;
private final long check_period;
@ -36,20 +34,17 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
private final boolean log_enabled, skip_unloaded_entity_chunks;
protected VillagerChunkLimit() {
shouldEnable();
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
super("villager-chunk-limit");
config.master().addComment(configPath + ".enable",
"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" +
"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.");
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.");
this.log_enabled = config.getBoolean(configPath() + ".log-removals", true);
this.non_optimized_max_per_chunk = config.getInt(configPath() + ".unoptimized.max-per-chunk", 20,
this.log_enabled = config.getBoolean(configPath + ".log-removals", true);
this.non_optimized_max_per_chunk = config.getInt(configPath + ".unoptimized.max-per-chunk", 20,
"The maximum amount of unoptimized villagers per chunk.");
final List<String> defaults = Stream.of(
"NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER",
@ -63,7 +58,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
return false;
}
}).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" +
"Use enums from https://jd.papermc.io/paper/1.20/org/bukkit/entity/Villager.Profession.html")
.stream()
@ -79,9 +74,9 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
})
.filter(Objects::nonNull)
.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.");
this.optimized_removal_priority = config.getList(configPath() + ".optimized.removal-priority", defaults)
this.optimized_removal_priority = config.getList(configPath + ".optimized.removal-priority", defaults)
.stream()
.map(configuredProfession -> {
try {
@ -97,11 +92,6 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
.collect(Collectors.toList());
}
@Override
public String configPath() {
return "villager-chunk-limit";
}
@Override
public void enable() {
final VillagerOptimizer plugin = VillagerOptimizer.getInstance();
@ -121,7 +111,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
@Override
public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false);
return VillagerOptimizer.config().getBoolean(configPath + ".enable", false);
}
@Override
@ -152,7 +142,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
for (Entity entity : chunk.getEntities()) {
if (entity.getType().equals(EntityType.VILLAGER)) {
Villager villager = (Villager) entity;
if (villagerCache.getOrAdd(villager).isOptimized()) {
if (villagerCache.createIfAbsent(villager).isOptimized()) {
optimized_villagers.add(villager);
} else {
not_optimized_villagers.add(villager);

View File

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

View File

@ -1,9 +1,5 @@
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.utils.LocationUtil;
import org.bukkit.GameMode;
@ -19,32 +15,21 @@ import org.bukkit.event.entity.PlayerLeashEntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
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;
public EnableLeashingVillagers() {
shouldEnable();
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
super("gameplay.villagers-can-be-leashed");
config.master().addComment(configPath + ".enable",
"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.");
this.log_enabled = config.getBoolean(configPath() + ".log", false);
}
@Override
public String configPath() {
return "gameplay.villagers-can-be-leashed";
this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -55,7 +40,7 @@ public class EnableLeashingVillagers implements VillagerOptimizerModule, Listene
@Override
public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false);
return config.getBoolean(configPath + ".enable", false);
}
@SuppressWarnings("deprecation")
@ -68,7 +53,7 @@ public class EnableLeashingVillagers implements VillagerOptimizerModule, Listene
final Villager villager = (Villager) event.getRightClicked();
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

View File

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

View File

@ -1,13 +1,11 @@
package me.xginko.villageroptimizer.modules.gameplay;
import com.tcoded.folialib.impl.ServerImplementation;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
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 org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
@ -23,37 +21,27 @@ import org.bukkit.potion.PotionEffectType;
import java.time.Duration;
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 long cooldown_millis;
public LevelOptimizedProfession() {
shouldEnable();
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath(),
super("gameplay.level-optimized-profession");
Config config = VillagerOptimizer.config();
config.master().addComment(configPath,
"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.");
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" +
"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.");
}
@Override
public String configPath() {
return "gameplay.level-optimized-profession";
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -74,7 +62,7 @@ public class LevelOptimizedProfession implements VillagerOptimizerModule, Listen
&& event.getInventory().getHolder() instanceof Villager
) {
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.canLevelUp(cooldown_millis)) {

View File

@ -1,6 +1,5 @@
package me.xginko.villageroptimizer.modules.gameplay;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Villager;
@ -10,18 +9,19 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
public class MakeVillagersSpawnAdult implements VillagerOptimizerModule, Listener {
public class MakeVillagersSpawnAdult extends VillagerOptimizerModule implements Listener {
public MakeVillagersSpawnAdult() {}
@Override
public String configPath() {
return "gameplay.villagers-spawn-as-adults";
public MakeVillagersSpawnAdult() {
super("gameplay.villagers-spawn-as-adults");
config.master().addComment(configPath + ".enable",
"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.");
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -32,11 +32,7 @@ public class MakeVillagersSpawnAdult implements VillagerOptimizerModule, Listene
@Override
public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().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.");
return config.getBoolean(configPath + ".enable", false);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)

View File

@ -1,11 +1,7 @@
package me.xginko.villageroptimizer.modules.gameplay;
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 org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
@ -14,24 +10,24 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
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;
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 boolean cancel_knockback;
public PreventOptimizedDamage() {
shouldEnable();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
super("gameplay.prevent-damage-to-optimized");
config.master().addComment(configPath + ".enable",
"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");
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()),
"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" +
@ -50,14 +46,8 @@ public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener
.collect(Collectors.toCollection(() -> EnumSet.noneOf(EntityDamageEvent.DamageCause.class)));
}
@Override
public String configPath() {
return "gameplay.prevent-damage-to-optimized";
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -68,7 +58,7 @@ public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener
@Override
public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", true);
return config.getBoolean(configPath + ".enable", true);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -76,7 +66,7 @@ public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener
if (
event.getEntityType().equals(EntityType.VILLAGER)
&& damage_causes_to_cancel.contains(event.getCause())
&& villagerCache.getOrAdd((Villager) event.getEntity()).isOptimized()
&& villagerCache.createIfAbsent((Villager) event.getEntity()).isOptimized()
) {
event.setCancelled(true);
}
@ -87,7 +77,7 @@ public class PreventOptimizedDamage implements VillagerOptimizerModule, Listener
if (
cancel_knockback
&& event.getEntityType().equals(EntityType.VILLAGER)
&& villagerCache.getOrAdd((Villager) event.getEntity()).isOptimized()
&& villagerCache.createIfAbsent((Villager) event.getEntity()).isOptimized()
) {
event.setCancelled(true);
}

View File

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

View File

@ -1,8 +1,6 @@
package me.xginko.villageroptimizer.modules.gameplay;
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.modules.VillagerOptimizerModule;
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.TradeSelectEvent;
public class PreventUnoptimizedTrading implements VillagerOptimizerModule, Listener {
public class PreventUnoptimizedTrading extends VillagerOptimizerModule implements Listener {
private final VillagerCache villagerCache;
private final boolean notify_player;
public PreventUnoptimizedTrading() {
shouldEnable();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
super("gameplay.prevent-trading-with-unoptimized");
config.master().addComment(configPath + ".enable",
"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" +
"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.");
}
@Override
public String configPath() {
return "gameplay.prevent-trading-with-unoptimized";
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -51,7 +40,7 @@ public class PreventUnoptimizedTrading implements VillagerOptimizerModule, Liste
@Override
public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false);
return config.getBoolean(configPath + ".enable", false);
}
@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.getWhoClicked().hasPermission(Permissions.Bypass.TRADE_PREVENTION.get())) 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);
if (notify_player) {
Player player = (Player) event.getWhoClicked();
VillagerOptimizer.getLang(player.locale()).optimize_for_trading
.forEach(line -> KyoriUtil.sendMessage(player, line));
VillagerOptimizer.getLang(player.locale()).optimize_for_trading.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.getWhoClicked().hasPermission(Permissions.Bypass.TRADE_PREVENTION.get())) 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);
if (notify_player) {
Player player = (Player) event.getWhoClicked();
VillagerOptimizer.getLang(player.locale()).optimize_for_trading
.forEach(line -> KyoriUtil.sendMessage(player, line));
VillagerOptimizer.getLang(player.locale()).optimize_for_trading.forEach(line -> KyoriUtil.sendMessage(player, line));
}
}
}

View File

@ -1,14 +1,12 @@
package me.xginko.villageroptimizer.modules.gameplay;
import me.xginko.villageroptimizer.VillagerCache;
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.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
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 org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
@ -21,34 +19,25 @@ import org.bukkit.event.player.PlayerInteractEntityEvent;
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 boolean log_enabled, notify_player;
public RestockOptimizedTrades() {
shouldEnable();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath(),
super("gameplay.restock-optimized-trades");
config.master().addComment(configPath,
"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.");
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;
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.");
this.log_enabled = config.getBoolean(configPath() + ".log", false);
}
@Override
public String configPath() {
return "gameplay.restock-optimized-trades";
this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -66,7 +55,7 @@ public class RestockOptimizedTrades implements VillagerOptimizerModule, Listener
private void onInteract(PlayerInteractEntityEvent event) {
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;
final Player player = event.getPlayer();

View File

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

View File

@ -1,8 +1,5 @@
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.VillagerUnoptimizeEvent;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
@ -12,26 +9,16 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
public class VisuallyHighlightOptimized implements VillagerOptimizerModule, Listener {
private final ServerImplementation scheduler;
public class VisuallyHighlightOptimized extends VillagerOptimizerModule implements Listener {
public VisuallyHighlightOptimized() {
shouldEnable();
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
Config config = VillagerOptimizer.getConfiguration();
super("gameplay.outline-optimized-villagers");
config.master().addComment("gameplay.outline-optimized-villagers.enable",
"Will make optimized villagers glow.");
}
@Override
public String configPath() {
return "gameplay.outline-optimized-villagers";
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -42,7 +29,7 @@ public class VisuallyHighlightOptimized implements VillagerOptimizerModule, List
@Override
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)

View File

@ -1,16 +1,14 @@
package me.xginko.villageroptimizer.modules.optimization;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.OptimizationType;
import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
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 org.bukkit.Location;
@ -33,22 +31,19 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
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 long cooldown_millis;
private final double search_radius;
private final boolean only_while_sneaking, notify_player, log_enabled;
public OptimizeByBlock() {
shouldEnable();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
super("optimization-methods.block-optimization");
config.master().addComment(configPath + ".enable",
"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.");
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"
), "Values here need to be valid bukkit Material enums for your server version.")
.stream()
@ -64,27 +59,21 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
.filter(Objects::nonNull)
.collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class)));
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" +
"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 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.");
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.");
this.log_enabled = config.getBoolean(configPath() + ".log", false);
}
@Override
public String configPath() {
return "optimization-methods.block-optimization";
this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -95,7 +84,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
@Override
public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false);
return config.getBoolean(configPath + ".enable", false);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -117,7 +106,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
final double distance = LocationUtil.relDistance3DSquared(villager.getLocation(), blockLoc);
if (distance >= closestDistance) continue;
final WrappedVillager wVillager = villagerCache.getOrAdd(villager);
final WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (wVillager.canOptimize(cooldown_millis)) {
closestOptimizableVillager = wVillager;
closestDistance = distance;
@ -184,7 +173,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
final double distance = LocationUtil.relDistance3DSquared(villager.getLocation(), blockLoc);
if (distance >= closestDistance) continue;
final WrappedVillager wVillager = villagerCache.getOrAdd(villager);
final WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (wVillager.isOptimized()) {
closestOptimizedVillager = wVillager;
closestDistance = distance;

View File

@ -1,17 +1,15 @@
package me.xginko.villageroptimizer.modules.optimization;
import me.xginko.villageroptimizer.VillagerCache;
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.Permissions;
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
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 org.bukkit.ChatColor;
import org.bukkit.Material;
@ -33,42 +31,33 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
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 long cooldown;
private final boolean consume_nametag, notify_player, log_enabled;
public OptimizeByNametag() {
shouldEnable();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
super("optimization-methods.nametag-optimization");
config.master().addComment(configPath + ".enable",
"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.");
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.")
.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.");
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" +
"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.");
this.log_enabled = config.getBoolean(configPath() + ".log", false);
}
@Override
public String configPath() {
return "optimization-methods.nametag-optimization";
this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -79,7 +68,7 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener {
@Override
public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", true);
return config.getBoolean(configPath + ".enable", true);
}
@SuppressWarnings("deprecation")
@ -97,7 +86,7 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener {
final String nameTagPlainText = ChatColor.stripColor(meta.getDisplayName());
final Villager villager = (Villager) event.getRightClicked();
final WrappedVillager wVillager = villagerCache.getOrAdd(villager);
final WrappedVillager wVillager = villagerCache.createIfAbsent(villager);
if (nametags.contains(nameTagPlainText.toLowerCase())) {
if (wVillager.canOptimize(cooldown) || player.hasPermission(Permissions.Bypass.NAMETAG_COOLDOWN.get())) {

View File

@ -1,18 +1,15 @@
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.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.Permissions;
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.Util;
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 org.bukkit.Location;
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.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 double search_radius;
private final int check_duration_ticks;
private final boolean only_while_sneaking, log_enabled, notify_player;
public OptimizeByWorkstation() {
shouldEnable();
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment(configPath() + ".enable",
super("optimization-methods.workstation-optimization");
config.master().addComment(configPath + ".enable",
"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.");
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" +
"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 closest unoptimized villager to the player will be optimized.");
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" +
"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.");
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.");
this.log_enabled = config.getBoolean(configPath() + ".log", false);
}
@Override
public String configPath() {
return "optimization-methods.workstation-optimization";
this.log_enabled = config.getBoolean(configPath + ".log", false);
}
@Override
public void enable() {
VillagerOptimizer plugin = VillagerOptimizer.getInstance();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@ -82,7 +68,7 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
@Override
public boolean shouldEnable() {
return VillagerOptimizer.getConfiguration().getBoolean(configPath() + ".enable", false);
return config.getBoolean(configPath + ".enable", false);
}
@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)) {
if (villager.getProfession() != workstationProfession) continue;
WrappedVillager wrapped = villagerCache.getOrAdd(villager);
WrappedVillager wrapped = villagerCache.createIfAbsent(villager);
if (wrapped.getJobSite() == null) continue;
if (wrapped.getJobSite().getWorld().getUID() != workstationLoc.getWorld().getUID()) 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);
if (distance >= closestDistance) continue;
WrappedVillager wrapped = villagerCache.getOrAdd(villager);
WrappedVillager wrapped = villagerCache.createIfAbsent(villager);
if (wrapped.isOptimized()) {
closestOptimized = wrapped;

View File

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