Compare commits
No commits in common. "master" and "1.6.1" have entirely different histories.
6
pom.xml
6
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>me.xginko</groupId>
|
<groupId>me.xginko</groupId>
|
||||||
<artifactId>VillagerOptimizer</artifactId>
|
<artifactId>VillagerOptimizer</artifactId>
|
||||||
<version>1.7.0</version>
|
<version>1.6.1</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>VillagerOptimizer</name>
|
<name>VillagerOptimizer</name>
|
||||||
@ -121,7 +121,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.papermc.paper</groupId>
|
<groupId>io.papermc.paper</groupId>
|
||||||
<artifactId>paper-api</artifactId>
|
<artifactId>paper-api</artifactId>
|
||||||
<version>1.20.4-R0.1-SNAPSHOT</version>
|
<version>1.21-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -187,7 +187,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.cryptomorin</groupId>
|
<groupId>com.github.cryptomorin</groupId>
|
||||||
<artifactId>XSeries</artifactId>
|
<artifactId>XSeries</artifactId>
|
||||||
<version>11.2.1</version>
|
<version>11.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package me.xginko.villageroptimizer;
|
package me.xginko.villageroptimizer;
|
||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
|
||||||
import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand;
|
import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand;
|
||||||
import me.xginko.villageroptimizer.config.Config;
|
import me.xginko.villageroptimizer.config.Config;
|
||||||
import me.xginko.villageroptimizer.config.LanguageCache;
|
import me.xginko.villageroptimizer.config.LanguageCache;
|
||||||
import me.xginko.villageroptimizer.struct.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.Util;
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
|
||||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
@ -19,7 +16,6 @@ import org.apache.logging.log4j.core.config.Configurator;
|
|||||||
import org.bstats.bukkit.Metrics;
|
import org.bstats.bukkit.Metrics;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.entity.Villager;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import space.arim.morepaperlib.MorePaperLib;
|
import space.arim.morepaperlib.MorePaperLib;
|
||||||
@ -30,7 +26,6 @@ import java.io.File;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -46,9 +41,9 @@ import java.util.zip.ZipEntry;
|
|||||||
public final class VillagerOptimizer extends JavaPlugin {
|
public final class VillagerOptimizer extends JavaPlugin {
|
||||||
|
|
||||||
private static VillagerOptimizer instance;
|
private static VillagerOptimizer instance;
|
||||||
|
private static WrapperCache wrapperCache;
|
||||||
private static CommandRegistration commandRegistration;
|
private static CommandRegistration commandRegistration;
|
||||||
private static GracefulScheduling scheduling;
|
private static GracefulScheduling scheduling;
|
||||||
private static Cache<Villager, WrappedVillager> wrapperCache;
|
|
||||||
private static Map<String, LanguageCache> languageCacheMap;
|
private static Map<String, LanguageCache> languageCacheMap;
|
||||||
private static Config config;
|
private static Config config;
|
||||||
private static BukkitAudiences audiences;
|
private static BukkitAudiences audiences;
|
||||||
@ -72,21 +67,11 @@ public final class VillagerOptimizer extends JavaPlugin {
|
|||||||
logger = ComponentLogger.logger(getLogger().getName());
|
logger = ComponentLogger.logger(getLogger().getName());
|
||||||
bStats = new Metrics(this, 19954);
|
bStats = new Metrics(this, 19954);
|
||||||
|
|
||||||
if (getServer().getPluginManager().getPlugin("AntiVillagerLag") != null) {
|
|
||||||
logger.warn("While VillagerOptimizer can read data previously created by AVL, running");
|
|
||||||
logger.warn("both plugins at the same time is unsafe and definitely will cause issues.");
|
|
||||||
logger.warn("To protect your game from corruption, VillagerOptimizer will now disable!");
|
|
||||||
logger.warn("Please decide for one of the plugins!");
|
|
||||||
getServer().getPluginManager().disablePlugin(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getDataFolder().mkdirs();
|
getDataFolder().mkdirs();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Failed to create plugin directory! Cannot enable!", e);
|
logger.error("Failed to create plugin directory! Cannot enable!", e);
|
||||||
getServer().getPluginManager().disablePlugin(this);
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(Component.text("╭────────────────────────────────────────────────────────────╮").style(Util.PL_STYLE));
|
logger.info(Component.text("╭────────────────────────────────────────────────────────────╮").style(Util.PL_STYLE));
|
||||||
@ -135,7 +120,7 @@ public final class VillagerOptimizer extends JavaPlugin {
|
|||||||
VillagerOptimizerCommand.COMMANDS.forEach(VillagerOptimizerCommand::disable);
|
VillagerOptimizerCommand.COMMANDS.forEach(VillagerOptimizerCommand::disable);
|
||||||
VillagerOptimizerCommand.COMMANDS.clear();
|
VillagerOptimizerCommand.COMMANDS.clear();
|
||||||
if (wrapperCache != null) {
|
if (wrapperCache != null) {
|
||||||
wrapperCache.cleanUp();
|
wrapperCache.disable();
|
||||||
wrapperCache = null;
|
wrapperCache = null;
|
||||||
}
|
}
|
||||||
if (scheduling != null) {
|
if (scheduling != null) {
|
||||||
@ -160,39 +145,30 @@ public final class VillagerOptimizer extends JavaPlugin {
|
|||||||
public static @NotNull VillagerOptimizer getInstance() {
|
public static @NotNull VillagerOptimizer getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull GracefulScheduling scheduling() {
|
|
||||||
return scheduling;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @NotNull CommandRegistration commandRegistration() {
|
|
||||||
return commandRegistration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @NotNull Cache<Villager, WrappedVillager> wrappers() {
|
|
||||||
return wrapperCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @NotNull Config config() {
|
public static @NotNull Config config() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
public static @NotNull WrapperCache getCache() {
|
||||||
|
return wrapperCache;
|
||||||
|
}
|
||||||
|
public static @NotNull CommandRegistration commandRegistration() {
|
||||||
|
return commandRegistration;
|
||||||
|
}
|
||||||
|
public static @NotNull GracefulScheduling scheduling() {
|
||||||
|
return scheduling;
|
||||||
|
}
|
||||||
public static @NotNull ComponentLogger logger() {
|
public static @NotNull ComponentLogger logger() {
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
|
public static @NotNull BukkitAudiences getAudiences() {
|
||||||
public static @NotNull BukkitAudiences audiences() {
|
|
||||||
return audiences;
|
return audiences;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull LanguageCache getLang(Locale locale) {
|
public static @NotNull LanguageCache getLang(Locale locale) {
|
||||||
return getLang(locale.toString().toLowerCase());
|
return getLang(locale.toString().toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull LanguageCache getLang(CommandSender commandSender) {
|
public static @NotNull LanguageCache getLang(CommandSender commandSender) {
|
||||||
return commandSender instanceof Player ? getLang(((Player) commandSender).locale()) : getLang(config.default_lang);
|
return commandSender instanceof Player ? getLang(((Player) commandSender).locale()) : getLang(config.default_lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull LanguageCache getLang(String lang) {
|
public static @NotNull LanguageCache getLang(String lang) {
|
||||||
if (!config.auto_lang) return languageCacheMap.get(config.default_lang.toString().toLowerCase());
|
if (!config.auto_lang) return languageCacheMap.get(config.default_lang.toString().toLowerCase());
|
||||||
return languageCacheMap.getOrDefault(lang.replace("-", "_"), languageCacheMap.get(config.default_lang.toString().toLowerCase()));
|
return languageCacheMap.getOrDefault(lang.replace("-", "_"), languageCacheMap.get(config.default_lang.toString().toLowerCase()));
|
||||||
@ -206,8 +182,8 @@ public final class VillagerOptimizer extends JavaPlugin {
|
|||||||
private void reloadConfiguration() {
|
private void reloadConfiguration() {
|
||||||
try {
|
try {
|
||||||
config = new Config();
|
config = new Config();
|
||||||
if (wrapperCache != null) wrapperCache.cleanUp();
|
if (wrapperCache != null) wrapperCache.disable();
|
||||||
wrapperCache = Caffeine.newBuilder().expireAfterWrite(config.cache_keep_time).build();
|
wrapperCache = new WrapperCache(config.cache_keep_time);
|
||||||
VillagerOptimizerCommand.reloadCommands();
|
VillagerOptimizerCommand.reloadCommands();
|
||||||
VillagerOptimizerModule.reloadModules();
|
VillagerOptimizerModule.reloadModules();
|
||||||
config.saveConfig();
|
config.saveConfig();
|
||||||
@ -253,7 +229,7 @@ public final class VillagerOptimizer extends JavaPlugin {
|
|||||||
.collect(Collectors.toCollection(TreeSet::new));
|
.collect(Collectors.toCollection(TreeSet::new));
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.error("Failed while searching for available translations!", t);
|
logger.error("Failed while searching for available translations!", t);
|
||||||
return Collections.emptySortedSet();
|
return new TreeSet<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
src/main/java/me/xginko/villageroptimizer/WrapperCache.java
Normal file
31
src/main/java/me/xginko/villageroptimizer/WrapperCache.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package me.xginko.villageroptimizer;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
import me.xginko.villageroptimizer.utils.Disableable;
|
||||||
|
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||||
|
import org.bukkit.entity.Villager;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public final class WrapperCache implements Disableable {
|
||||||
|
|
||||||
|
private final @NotNull Cache<UUID, WrappedVillager> wrapperCache;
|
||||||
|
|
||||||
|
public WrapperCache(Duration cacheDuration) {
|
||||||
|
this.wrapperCache = Caffeine.newBuilder().expireAfterWrite(cacheDuration).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disable() {
|
||||||
|
this.wrapperCache.invalidateAll();
|
||||||
|
this.wrapperCache.cleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("DataFlowIssue")
|
||||||
|
public @NotNull WrappedVillager get(@NotNull Villager villager) {
|
||||||
|
return this.wrapperCache.get(villager.getUniqueId(), k -> new WrappedVillager(villager));
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package me.xginko.villageroptimizer.commands;
|
package me.xginko.villageroptimizer.commands;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.struct.Disableable;
|
import me.xginko.villageroptimizer.utils.Disableable;
|
||||||
import me.xginko.villageroptimizer.struct.Enableable;
|
import me.xginko.villageroptimizer.utils.Enableable;
|
||||||
import org.bukkit.command.CommandException;
|
import org.bukkit.command.CommandException;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
@ -11,11 +11,11 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
import org.reflections.scanners.Scanners;
|
import org.reflections.scanners.Scanners;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public abstract class VillagerOptimizerCommand implements Enableable, Disableable, CommandExecutor, TabCompleter {
|
public abstract class VillagerOptimizerCommand implements Enableable, Disableable, CommandExecutor, TabCompleter {
|
||||||
@ -36,15 +36,19 @@ public abstract class VillagerOptimizerCommand implements Enableable, Disableabl
|
|||||||
COMMANDS.forEach(VillagerOptimizerCommand::disable);
|
COMMANDS.forEach(VillagerOptimizerCommand::disable);
|
||||||
COMMANDS.clear();
|
COMMANDS.clear();
|
||||||
|
|
||||||
for (Class<?> clazz : COMMANDS_PACKAGE.get(Scanners.SubTypes.of(VillagerOptimizerCommand.class).asClass())) {
|
COMMANDS_PACKAGE.get(Scanners.SubTypes.of(VillagerOptimizerCommand.class).asClass())
|
||||||
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) continue;
|
.stream()
|
||||||
|
.filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers()))
|
||||||
|
.map(clazz -> {
|
||||||
try {
|
try {
|
||||||
COMMANDS.add((VillagerOptimizerCommand) clazz.getDeclaredConstructor().newInstance());
|
return (VillagerOptimizerCommand) clazz.getDeclaredConstructor().newInstance();
|
||||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
} catch (Throwable t) {
|
||||||
VillagerOptimizer.logger().error("Failed initialising command class '{}'.", clazz.getSimpleName(), e);
|
VillagerOptimizer.logger().error("Failed initialising command '{}'.", clazz.getSimpleName(), t);
|
||||||
}
|
return null;
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.forEach(COMMANDS::add);
|
||||||
|
|
||||||
COMMANDS.forEach(VillagerOptimizerCommand::enable);
|
COMMANDS.forEach(VillagerOptimizerCommand::enable);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package me.xginko.villageroptimizer.commands.optimizevillagers;
|
package me.xginko.villageroptimizer.commands.optimizevillagers;
|
||||||
|
|
||||||
|
import me.xginko.villageroptimizer.WrapperCache;
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand;
|
import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand;
|
||||||
import me.xginko.villageroptimizer.config.Config;
|
import me.xginko.villageroptimizer.config.Config;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Permissions;
|
import me.xginko.villageroptimizer.enums.Permissions;
|
||||||
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
|
import me.xginko.villageroptimizer.events.VillagerOptimizeEvent;
|
||||||
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||||
@ -89,6 +90,7 @@ public class OptVillagersRadius extends VillagerOptimizerCommand {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WrapperCache wrapperCache = VillagerOptimizer.getCache();
|
||||||
int successCount = 0;
|
int successCount = 0;
|
||||||
int failCount = 0;
|
int failCount = 0;
|
||||||
final boolean player_has_cooldown_bypass = player.hasPermission(Permissions.Bypass.COMMAND_COOLDOWN.get());
|
final boolean player_has_cooldown_bypass = player.hasPermission(Permissions.Bypass.COMMAND_COOLDOWN.get());
|
||||||
@ -99,7 +101,7 @@ public class OptVillagersRadius extends 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 = VillagerOptimizer.wrappers().get(villager, WrappedVillager::new);
|
WrappedVillager wVillager = wrapperCache.get(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);
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package me.xginko.villageroptimizer.commands.unoptimizevillagers;
|
package me.xginko.villageroptimizer.commands.unoptimizevillagers;
|
||||||
|
|
||||||
|
import me.xginko.villageroptimizer.WrapperCache;
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand;
|
import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Permissions;
|
import me.xginko.villageroptimizer.enums.Permissions;
|
||||||
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
|
import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
|
||||||
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||||
@ -84,6 +85,7 @@ public class UnOptVillagersRadius extends VillagerOptimizerCommand {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WrapperCache wrapperCache = VillagerOptimizer.getCache();
|
||||||
int successCount = 0;
|
int successCount = 0;
|
||||||
|
|
||||||
for (Entity entity : player.getNearbyEntities(safeRadius, safeRadius, safeRadius)) {
|
for (Entity entity : player.getNearbyEntities(safeRadius, safeRadius, safeRadius)) {
|
||||||
@ -92,7 +94,7 @@ public class UnOptVillagersRadius extends 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 = VillagerOptimizer.wrappers().get(villager, WrappedVillager::new);
|
WrappedVillager wVillager = wrapperCache.get(villager);
|
||||||
|
|
||||||
if (wVillager.isOptimized()) {
|
if (wVillager.isOptimized()) {
|
||||||
VillagerUnoptimizeEvent unOptimizeEvent = new VillagerUnoptimizeEvent(wVillager, player, OptimizationType.COMMAND);
|
VillagerUnoptimizeEvent unOptimizeEvent = new VillagerUnoptimizeEvent(wVillager, player, OptimizationType.COMMAND);
|
||||||
|
@ -5,7 +5,7 @@ import me.xginko.villageroptimizer.commands.VillagerOptimizerCommand;
|
|||||||
import me.xginko.villageroptimizer.commands.villageroptimizer.subcommands.DisableSubCmd;
|
import me.xginko.villageroptimizer.commands.villageroptimizer.subcommands.DisableSubCmd;
|
||||||
import me.xginko.villageroptimizer.commands.villageroptimizer.subcommands.ReloadSubCmd;
|
import me.xginko.villageroptimizer.commands.villageroptimizer.subcommands.ReloadSubCmd;
|
||||||
import me.xginko.villageroptimizer.commands.villageroptimizer.subcommands.VersionSubCmd;
|
import me.xginko.villageroptimizer.commands.villageroptimizer.subcommands.VersionSubCmd;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Permissions;
|
import me.xginko.villageroptimizer.enums.Permissions;
|
||||||
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
||||||
import me.xginko.villageroptimizer.utils.Util;
|
import me.xginko.villageroptimizer.utils.Util;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
@ -2,7 +2,7 @@ package me.xginko.villageroptimizer.commands.villageroptimizer.subcommands;
|
|||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.commands.SubCommand;
|
import me.xginko.villageroptimizer.commands.SubCommand;
|
||||||
import me.xginko.villageroptimizer.struct.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;
|
||||||
import me.xginko.villageroptimizer.utils.Util;
|
import me.xginko.villageroptimizer.utils.Util;
|
||||||
|
@ -2,7 +2,7 @@ package me.xginko.villageroptimizer.commands.villageroptimizer.subcommands;
|
|||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.commands.SubCommand;
|
import me.xginko.villageroptimizer.commands.SubCommand;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Permissions;
|
import me.xginko.villageroptimizer.enums.Permissions;
|
||||||
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
||||||
import me.xginko.villageroptimizer.utils.Util;
|
import me.xginko.villageroptimizer.utils.Util;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
@ -3,7 +3,7 @@ package me.xginko.villageroptimizer.commands.villageroptimizer.subcommands;
|
|||||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.commands.SubCommand;
|
import me.xginko.villageroptimizer.commands.SubCommand;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Permissions;
|
import me.xginko.villageroptimizer.enums.Permissions;
|
||||||
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
||||||
import me.xginko.villageroptimizer.utils.Util;
|
import me.xginko.villageroptimizer.utils.Util;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
@ -118,13 +118,13 @@ public class Config {
|
|||||||
return this.config.getInteger(path, def);
|
return this.config.getInteger(path, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull <T> List<T> getList(@NotNull String path, @NotNull List<T> def, @NotNull String comment) {
|
public @NotNull List<String> getList(@NotNull String path, @NotNull List<String> def, @NotNull String comment) {
|
||||||
this.config.addDefault(path, def, comment);
|
this.config.addDefault(path, def, comment);
|
||||||
return this.config.getList(path);
|
return this.config.getStringList(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull <T> List<T> getList(@NotNull String path, @NotNull List<T> def) {
|
public @NotNull List<String> getList(@NotNull String path, @NotNull List<String> def) {
|
||||||
this.config.addDefault(path, def);
|
this.config.addDefault(path, def);
|
||||||
return this.config.getList(path);
|
return this.config.getStringList(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ public class LanguageCache {
|
|||||||
public final @NotNull List<Component> nametag_optimize_success, nametag_on_optimize_cooldown, nametag_unoptimize_success,
|
public final @NotNull List<Component> nametag_optimize_success, nametag_on_optimize_cooldown, nametag_unoptimize_success,
|
||||||
block_optimize_success, block_on_optimize_cooldown, block_unoptimize_success,
|
block_optimize_success, block_on_optimize_cooldown, block_unoptimize_success,
|
||||||
workstation_optimize_success, workstation_on_optimize_cooldown, workstation_unoptimize_success,
|
workstation_optimize_success, workstation_on_optimize_cooldown, workstation_unoptimize_success,
|
||||||
activity_optimize_success,
|
|
||||||
command_optimize_success, command_radius_limit_exceed, command_optimize_fail, command_unoptimize_success,
|
command_optimize_success, command_radius_limit_exceed, command_optimize_fail, command_unoptimize_success,
|
||||||
command_specify_radius, command_radius_invalid, command_no_villagers_nearby,
|
command_specify_radius, command_radius_invalid, command_no_villagers_nearby,
|
||||||
trades_restocked, optimize_for_trading, villager_leveling_up;
|
trades_restocked, optimize_for_trading, villager_leveling_up;
|
||||||
@ -68,10 +67,6 @@ public class LanguageCache {
|
|||||||
"<gray>You need to wait %time% until you can optimize this villager again.");
|
"<gray>You need to wait %time% until you can optimize this villager again.");
|
||||||
this.workstation_unoptimize_success = getListTranslation("messages.workstation.unoptimize-success",
|
this.workstation_unoptimize_success = getListTranslation("messages.workstation.unoptimize-success",
|
||||||
"<green>Successfully unoptimized %villagertype% villager by removing workstation block %blocktype%.");
|
"<green>Successfully unoptimized %villagertype% villager by removing workstation block %blocktype%.");
|
||||||
// Activity
|
|
||||||
this.activity_optimize_success = getListTranslation("messages.activity.optimized-near-you",
|
|
||||||
"<gray>%amount% villagers close to you were automatically optimized due to high activity.");
|
|
||||||
|
|
||||||
// Command
|
// Command
|
||||||
this.command_optimize_success = getListTranslation("messages.command.optimize-success",
|
this.command_optimize_success = getListTranslation("messages.command.optimize-success",
|
||||||
"<green>Successfully optimized %amount% villager(s) in a radius of %radius% blocks.");
|
"<green>Successfully optimized %amount% villager(s) in a radius of %radius% blocks.");
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package me.xginko.villageroptimizer.struct.enums;
|
package me.xginko.villageroptimizer.enums;
|
||||||
|
|
||||||
import net.kyori.adventure.key.Namespaced;
|
import net.kyori.adventure.key.Namespaced;
|
||||||
import org.bukkit.Keyed;
|
import org.bukkit.Keyed;
|
||||||
@ -52,7 +52,7 @@ public final class Keyring {
|
|||||||
OPTIMIZATION_TYPE("optimization-type"),
|
OPTIMIZATION_TYPE("optimization-type"),
|
||||||
LAST_OPTIMIZE_SYSTIME_MILLIS("last-optimize"),
|
LAST_OPTIMIZE_SYSTIME_MILLIS("last-optimize"),
|
||||||
LAST_LEVELUP_SYSTIME_MILLIS("last-levelup"),
|
LAST_LEVELUP_SYSTIME_MILLIS("last-levelup"),
|
||||||
LAST_RESTOCK_WORLD_FULLTIME("last-restock-full-time");
|
LAST_RESTOCK_SYSTIME_MILLIS("last-restock");
|
||||||
|
|
||||||
private final @NotNull NamespacedKey key;
|
private final @NotNull NamespacedKey key;
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ public final class Keyring {
|
|||||||
public enum AntiVillagerLag implements Keyed {
|
public enum AntiVillagerLag implements Keyed {
|
||||||
|
|
||||||
NEXT_OPTIMIZATION_SYSTIME_SECONDS("cooldown"), // Returns LONG -> (System.currentTimeMillis() / 1000) + cooldown seconds
|
NEXT_OPTIMIZATION_SYSTIME_SECONDS("cooldown"), // Returns LONG -> (System.currentTimeMillis() / 1000) + cooldown seconds
|
||||||
LAST_RESTOCK_WORLD_FULLTIME("time"), // Returns LONG -> villager.getWorld().getFullTime()
|
LAST_RESTOCK_WORLDFULLTIME("time"), // Returns LONG -> villager.getWorld().getFullTime()
|
||||||
NEXT_LEVELUP_SYSTIME_SECONDS("levelCooldown"), // Returns LONG -> (System.currentTimeMillis() / 1000) + cooldown seconds
|
NEXT_LEVELUP_SYSTIME_SECONDS("levelCooldown"), // Returns LONG -> (System.currentTimeMillis() / 1000) + cooldown seconds
|
||||||
OPTIMIZED_ANY("Marker"), // Returns STRING -> "AVL"
|
OPTIMIZED_ANY("Marker"), // Returns STRING -> "AVL"
|
||||||
OPTIMIZED_BLOCK("disabledByBlock"), // Returns STRING -> key().toString()
|
OPTIMIZED_BLOCK("disabledByBlock"), // Returns STRING -> key().toString()
|
@ -1,8 +1,6 @@
|
|||||||
package me.xginko.villageroptimizer.struct.enums;
|
package me.xginko.villageroptimizer.enums;
|
||||||
|
|
||||||
public enum OptimizationType {
|
public enum OptimizationType {
|
||||||
CHUNK_LIMIT,
|
|
||||||
REGIONAL_ACTIVITY,
|
|
||||||
COMMAND,
|
COMMAND,
|
||||||
NAMETAG,
|
NAMETAG,
|
||||||
WORKSTATION,
|
WORKSTATION,
|
@ -1,4 +1,4 @@
|
|||||||
package me.xginko.villageroptimizer.struct.enums;
|
package me.xginko.villageroptimizer.enums;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.permissions.Permission;
|
import org.bukkit.permissions.Permission;
|
@ -1,7 +1,7 @@
|
|||||||
package me.xginko.villageroptimizer.events;
|
package me.xginko.villageroptimizer.events;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Cancellable;
|
import org.bukkit.event.Cancellable;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package me.xginko.villageroptimizer.events;
|
package me.xginko.villageroptimizer.events;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Cancellable;
|
import org.bukkit.event.Cancellable;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
package me.xginko.villageroptimizer.modules;
|
package me.xginko.villageroptimizer.modules;
|
||||||
|
|
||||||
import com.cryptomorin.xseries.XEntityType;
|
import com.cryptomorin.xseries.XEntityType;
|
||||||
import me.xginko.villageroptimizer.struct.models.ExpiringSet;
|
import me.xginko.villageroptimizer.utils.ExpiringSet;
|
||||||
import me.xginko.villageroptimizer.utils.LocationUtil;
|
import me.xginko.villageroptimizer.utils.LocationUtil;
|
||||||
import me.xginko.villageroptimizer.utils.Util;
|
import me.xginko.villageroptimizer.utils.Util;
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
@ -20,12 +19,9 @@ import space.arim.morepaperlib.scheduling.ScheduledTask;
|
|||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -33,11 +29,10 @@ public class VillagerChunkLimit extends VillagerOptimizerModule implements Runna
|
|||||||
|
|
||||||
private ScheduledTask periodic_chunk_check;
|
private ScheduledTask 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 Set<Villager.Profession> profession_whitelist;
|
|
||||||
private final ExpiringSet<Chunk> checked_chunks;
|
private final ExpiringSet<Chunk> checked_chunks;
|
||||||
private final long check_period;
|
private final long check_period;
|
||||||
private final int non_optimized_max_per_chunk, optimized_max_per_chunk;
|
private final int non_optimized_max_per_chunk, optimized_max_per_chunk;
|
||||||
private final boolean log_enabled, skip_unloaded_chunks, use_whitelist;
|
private final boolean log_enabled, skip_unloaded_chunks;
|
||||||
|
|
||||||
protected VillagerChunkLimit() {
|
protected VillagerChunkLimit() {
|
||||||
super("villager-chunk-limit");
|
super("villager-chunk-limit");
|
||||||
@ -49,12 +44,14 @@ public class VillagerChunkLimit extends VillagerOptimizerModule implements Runna
|
|||||||
"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_chunks = config.getBoolean(configPath + ".skip-not-fully-loaded-chunks", true,
|
this.skip_unloaded_chunks = config.getBoolean(configPath + ".skip-not-fully-loaded-chunks", 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.non_optimized_max_per_chunk = config.getInt(configPath + ".unoptimized.max-per-chunk", 20,
|
||||||
|
"The maximum amount of unoptimized villagers per chunk.");
|
||||||
this.checked_chunks = new ExpiringSet<>(Duration.ofSeconds(
|
this.checked_chunks = new ExpiringSet<>(Duration.ofSeconds(
|
||||||
Math.max(1, config.getInt(configPath + ".chunk-check-cooldown-seconds", 5,
|
Math.max(1, config.getInt(configPath + ".chunk-check-cooldown-seconds", 5,
|
||||||
"The delay in seconds a chunk will not be checked again after the first time.\n" +
|
"The delay in seconds a chunk will not be checked again after the first time.\n" +
|
||||||
"Reduces chances to lag the server due to overchecking."))));
|
"Reduces chances to lag the server due to overchecking."))));
|
||||||
this.log_enabled = config.getBoolean(configPath + ".log-removals", true);
|
final List<String> defaults = Stream.of(
|
||||||
List<String> defaults = Stream.of(
|
|
||||||
"NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER",
|
"NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER",
|
||||||
"FLETCHER", "MASON", "FARMER", "ARMORER", "TOOLSMITH", "WEAPONSMITH", "CLERIC", "LIBRARIAN")
|
"FLETCHER", "MASON", "FARMER", "ARMORER", "TOOLSMITH", "WEAPONSMITH", "CLERIC", "LIBRARIAN")
|
||||||
.filter(profession -> {
|
.filter(profession -> {
|
||||||
@ -66,26 +63,7 @@ public class VillagerChunkLimit extends VillagerOptimizerModule implements Runna
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
this.use_whitelist = config.getBoolean(configPath + ".whitelist.enable", false,
|
this.non_optimized_removal_priority = config.getList(configPath + ".unoptimized.removal-priority", defaults,
|
||||||
"Enable if you only want to manage villager counts for certain profession types.");
|
|
||||||
this.profession_whitelist = config.getList(configPath + ".whitelist.professions", Arrays.asList("NONE", "NITWIT"),
|
|
||||||
"Professions in this list will not be touched by the chunk limit.")
|
|
||||||
.stream()
|
|
||||||
.map(configuredProfession -> {
|
|
||||||
try {
|
|
||||||
return Villager.Profession.valueOf(configuredProfession);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
warn("(whitelist) Villager profession '" + configuredProfession +
|
|
||||||
"' not recognized. Make sure you're using the correct profession enums from " +
|
|
||||||
"https://jd.papermc.io/paper/1.20/org/bukkit/entity/Villager.Profession.html.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toCollection(HashSet::new));
|
|
||||||
this.non_optimized_max_per_chunk = config.getInt(configPath + ".unoptimized.max-per-chunk", 20,
|
|
||||||
"The maximum amount of unoptimized villagers per chunk.");
|
|
||||||
this.non_optimized_removal_priority = config.getList(configPath + ".unoptimized.removal-priority", new ArrayList<>(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()
|
||||||
@ -103,7 +81,7 @@ public class VillagerChunkLimit extends VillagerOptimizerModule implements Runna
|
|||||||
.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", new ArrayList<>(defaults))
|
this.optimized_removal_priority = config.getList(configPath + ".optimized.removal-priority", defaults)
|
||||||
.stream()
|
.stream()
|
||||||
.map(configuredProfession -> {
|
.map(configuredProfession -> {
|
||||||
try {
|
try {
|
||||||
@ -181,10 +159,7 @@ public class VillagerChunkLimit extends VillagerOptimizerModule implements Runna
|
|||||||
|
|
||||||
Villager villager = (Villager) entity;
|
Villager villager = (Villager) entity;
|
||||||
|
|
||||||
// Ignore villager if profession is not in the whitelist
|
if (wrapperCache.get(villager).isOptimized()) {
|
||||||
if (use_whitelist && profession_whitelist.contains(villager.getProfession())) continue;
|
|
||||||
|
|
||||||
if (wrapperCache.get(villager, WrappedVillager::new).isOptimized()) {
|
|
||||||
optimized_villagers.add(villager);
|
optimized_villagers.add(villager);
|
||||||
} else {
|
} else {
|
||||||
not_optimized_villagers.add(villager);
|
not_optimized_villagers.add(villager);
|
||||||
@ -205,7 +180,7 @@ public class VillagerChunkLimit extends VillagerOptimizerModule implements Runna
|
|||||||
scheduling.entitySpecificScheduler(villager).run(kill -> {
|
scheduling.entitySpecificScheduler(villager).run(kill -> {
|
||||||
villager.remove();
|
villager.remove();
|
||||||
if (log_enabled) info("Removed unoptimized villager with profession '" +
|
if (log_enabled) info("Removed unoptimized villager with profession '" +
|
||||||
Util.toNiceString(villager.getProfession()) + "' at " + LocationUtil.toString(villager.getLocation()));
|
Util.formatEnum(villager.getProfession()) + "' at " + LocationUtil.toString(villager.getLocation()));
|
||||||
}, null);
|
}, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,7 +199,7 @@ public class VillagerChunkLimit extends VillagerOptimizerModule implements Runna
|
|||||||
scheduling.entitySpecificScheduler(villager).run(kill -> {
|
scheduling.entitySpecificScheduler(villager).run(kill -> {
|
||||||
villager.remove();
|
villager.remove();
|
||||||
if (log_enabled) info("Removed unoptimized villager with profession '" +
|
if (log_enabled) info("Removed unoptimized villager with profession '" +
|
||||||
Util.toNiceString(villager.getProfession()) + "' at " + LocationUtil.toString(villager.getLocation()));
|
Util.formatEnum(villager.getProfession()) + "' at " + LocationUtil.toString(villager.getLocation()));
|
||||||
}, null);
|
}, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
package me.xginko.villageroptimizer.modules;
|
package me.xginko.villageroptimizer.modules;
|
||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
import me.xginko.villageroptimizer.WrapperCache;
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.config.Config;
|
import me.xginko.villageroptimizer.config.Config;
|
||||||
import me.xginko.villageroptimizer.struct.Disableable;
|
import me.xginko.villageroptimizer.utils.Disableable;
|
||||||
import me.xginko.villageroptimizer.struct.Enableable;
|
import me.xginko.villageroptimizer.utils.Enableable;
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
|
||||||
import org.bukkit.entity.Villager;
|
|
||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
import org.reflections.scanners.Scanners;
|
import org.reflections.scanners.Scanners;
|
||||||
import space.arim.morepaperlib.scheduling.GracefulScheduling;
|
import space.arim.morepaperlib.scheduling.GracefulScheduling;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public abstract class VillagerOptimizerModule implements Enableable, Disableable {
|
public abstract class VillagerOptimizerModule implements Enableable, Disableable {
|
||||||
@ -25,7 +23,7 @@ public abstract class VillagerOptimizerModule implements Enableable, Disableable
|
|||||||
|
|
||||||
protected final VillagerOptimizer plugin;
|
protected final VillagerOptimizer plugin;
|
||||||
protected final Config config;
|
protected final Config config;
|
||||||
protected final Cache<Villager, WrappedVillager> wrapperCache;
|
protected final WrapperCache wrapperCache;
|
||||||
protected final GracefulScheduling scheduling;
|
protected final GracefulScheduling scheduling;
|
||||||
public final String configPath;
|
public final String configPath;
|
||||||
private final String logFormat;
|
private final String logFormat;
|
||||||
@ -33,7 +31,7 @@ public abstract class VillagerOptimizerModule implements Enableable, Disableable
|
|||||||
public VillagerOptimizerModule(String configPath) {
|
public VillagerOptimizerModule(String configPath) {
|
||||||
this.plugin = VillagerOptimizer.getInstance();
|
this.plugin = VillagerOptimizer.getInstance();
|
||||||
this.config = VillagerOptimizer.config();
|
this.config = VillagerOptimizer.config();
|
||||||
this.wrapperCache = VillagerOptimizer.wrappers();
|
this.wrapperCache = VillagerOptimizer.getCache();
|
||||||
this.scheduling = VillagerOptimizer.scheduling();
|
this.scheduling = VillagerOptimizer.scheduling();
|
||||||
this.configPath = configPath;
|
this.configPath = configPath;
|
||||||
shouldEnable(); // Ensure enable option is always first
|
shouldEnable(); // Ensure enable option is always first
|
||||||
@ -49,18 +47,20 @@ public abstract class VillagerOptimizerModule implements Enableable, Disableable
|
|||||||
ENABLED_MODULES.forEach(VillagerOptimizerModule::disable);
|
ENABLED_MODULES.forEach(VillagerOptimizerModule::disable);
|
||||||
ENABLED_MODULES.clear();
|
ENABLED_MODULES.clear();
|
||||||
|
|
||||||
for (Class<?> clazz : MODULES_PACKAGE.get(Scanners.SubTypes.of(VillagerOptimizerModule.class).asClass())) {
|
MODULES_PACKAGE.get(Scanners.SubTypes.of(VillagerOptimizerModule.class).asClass())
|
||||||
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) continue;
|
.stream()
|
||||||
|
.filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers()))
|
||||||
|
.map(clazz -> {
|
||||||
try {
|
try {
|
||||||
VillagerOptimizerModule module = (VillagerOptimizerModule) clazz.getDeclaredConstructor().newInstance();
|
return (VillagerOptimizerModule) clazz.getDeclaredConstructor().newInstance();
|
||||||
if (module.shouldEnable()) {
|
} catch (Throwable t) {
|
||||||
ENABLED_MODULES.add(module);
|
VillagerOptimizer.logger().error("Failed initialising module '{}'.", clazz.getSimpleName(), t);
|
||||||
}
|
return null;
|
||||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
|
||||||
VillagerOptimizer.logger().error("Failed initialising module class '{}'.", clazz.getSimpleName(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(VillagerOptimizerModule::shouldEnable)
|
||||||
|
.forEach(ENABLED_MODULES::add);
|
||||||
|
|
||||||
ENABLED_MODULES.forEach(VillagerOptimizerModule::enable);
|
ENABLED_MODULES.forEach(VillagerOptimizerModule::enable);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import com.cryptomorin.xseries.XEntityType;
|
|||||||
import com.cryptomorin.xseries.XMaterial;
|
import com.cryptomorin.xseries.XMaterial;
|
||||||
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 me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
@ -54,7 +53,7 @@ public class EnableLeashingVillagers extends VillagerOptimizerModule implements
|
|||||||
|
|
||||||
final Villager villager = (Villager) event.getRightClicked();
|
final Villager villager = (Villager) event.getRightClicked();
|
||||||
if (villager.isLeashed()) return;
|
if (villager.isLeashed()) return;
|
||||||
if (only_optimized && !wrapperCache.get(villager, WrappedVillager::new).isOptimized()) return;
|
if (only_optimized && !wrapperCache.get(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
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ public class FixOptimisationAfterCure extends VillagerOptimizerModule implements
|
|||||||
) {
|
) {
|
||||||
Villager villager = (Villager) event.getTransformedEntity();
|
Villager villager = (Villager) event.getTransformedEntity();
|
||||||
scheduling.entitySpecificScheduler(villager).runDelayed(() -> {
|
scheduling.entitySpecificScheduler(villager).runDelayed(() -> {
|
||||||
WrappedVillager wVillager = wrapperCache.get(villager, WrappedVillager::new);
|
WrappedVillager wVillager = wrapperCache.get(villager);
|
||||||
wVillager.setOptimizationType(wVillager.getOptimizationType());
|
wVillager.setOptimizationType(wVillager.getOptimizationType());
|
||||||
}, null, 40L);
|
}, null, 40L);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ public class LevelOptimizedProfession extends VillagerOptimizerModule implements
|
|||||||
&& 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 = wrapperCache.get(villager, WrappedVillager::new);
|
final WrappedVillager wVillager = wrapperCache.get(villager);
|
||||||
if (!wVillager.isOptimized()) return;
|
if (!wVillager.isOptimized()) return;
|
||||||
|
|
||||||
if (wVillager.canLevelUp(cooldown_millis)) {
|
if (wVillager.canLevelUp(cooldown_millis)) {
|
||||||
|
@ -2,7 +2,6 @@ package me.xginko.villageroptimizer.modules.gameplay;
|
|||||||
|
|
||||||
import com.cryptomorin.xseries.XEntityType;
|
import com.cryptomorin.xseries.XEntityType;
|
||||||
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
@ -66,7 +65,7 @@ public class PreventOptimizedDamage extends VillagerOptimizerModule implements L
|
|||||||
if (
|
if (
|
||||||
event.getEntityType() == XEntityType.VILLAGER.get()
|
event.getEntityType() == XEntityType.VILLAGER.get()
|
||||||
&& damage_causes_to_cancel.contains(event.getCause())
|
&& damage_causes_to_cancel.contains(event.getCause())
|
||||||
&& wrapperCache.get((Villager) event.getEntity(), WrappedVillager::new).isOptimized()
|
&& wrapperCache.get((Villager) event.getEntity()).isOptimized()
|
||||||
) {
|
) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
@ -77,7 +76,7 @@ public class PreventOptimizedDamage extends VillagerOptimizerModule implements L
|
|||||||
if (
|
if (
|
||||||
cancel_knockback
|
cancel_knockback
|
||||||
&& event.getEntityType() == XEntityType.VILLAGER.get()
|
&& event.getEntityType() == XEntityType.VILLAGER.get()
|
||||||
&& wrapperCache.get((Villager) event.getEntity(), WrappedVillager::new).isOptimized()
|
&& wrapperCache.get((Villager) event.getEntity()).isOptimized()
|
||||||
) {
|
) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package me.xginko.villageroptimizer.modules.gameplay;
|
|||||||
|
|
||||||
import com.cryptomorin.xseries.XEntityType;
|
import com.cryptomorin.xseries.XEntityType;
|
||||||
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Mob;
|
import org.bukkit.entity.Mob;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
@ -42,7 +41,7 @@ public class PreventOptimizedTargeting extends VillagerOptimizerModule implement
|
|||||||
if (
|
if (
|
||||||
target != null
|
target != null
|
||||||
&& target.getType() == XEntityType.VILLAGER.get()
|
&& target.getType() == XEntityType.VILLAGER.get()
|
||||||
&& wrapperCache.get((Villager) target, WrappedVillager::new).isOptimized()
|
&& wrapperCache.get((Villager) target).isOptimized()
|
||||||
) {
|
) {
|
||||||
event.setTarget(null);
|
event.setTarget(null);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
@ -55,7 +54,7 @@ public class PreventOptimizedTargeting extends VillagerOptimizerModule implement
|
|||||||
if (
|
if (
|
||||||
target != null
|
target != null
|
||||||
&& target.getType() == XEntityType.VILLAGER.get()
|
&& target.getType() == XEntityType.VILLAGER.get()
|
||||||
&& wrapperCache.get((Villager) target, WrappedVillager::new).isOptimized()
|
&& wrapperCache.get((Villager) target).isOptimized()
|
||||||
) {
|
) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
@ -66,7 +65,7 @@ public class PreventOptimizedTargeting extends VillagerOptimizerModule implement
|
|||||||
if (
|
if (
|
||||||
event.getEntityType() == XEntityType.VILLAGER.get()
|
event.getEntityType() == XEntityType.VILLAGER.get()
|
||||||
&& event.getDamager() instanceof Mob
|
&& event.getDamager() instanceof Mob
|
||||||
&& wrapperCache.get((Villager) event.getEntity(), WrappedVillager::new).isOptimized()
|
&& wrapperCache.get((Villager) event.getEntity()).isOptimized()
|
||||||
) {
|
) {
|
||||||
((Mob) event.getDamager()).setTarget(null);
|
((Mob) event.getDamager()).setTarget(null);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
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.struct.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;
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -49,7 +48,7 @@ public class PreventUnoptimizedTrading extends VillagerOptimizerModule implement
|
|||||||
if (event.getInventory().getType() != InventoryType.MERCHANT) return;
|
if (event.getInventory().getType() != 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 (wrapperCache.get((Villager) event.getInventory().getHolder(), WrappedVillager::new).isOptimized()) return;
|
if (wrapperCache.get((Villager) event.getInventory().getHolder()).isOptimized()) return;
|
||||||
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|
||||||
@ -64,7 +63,7 @@ public class PreventUnoptimizedTrading extends VillagerOptimizerModule implement
|
|||||||
if (event.getInventory().getType() != InventoryType.MERCHANT) return;
|
if (event.getInventory().getType() != 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 (wrapperCache.get((Villager) event.getInventory().getHolder(), WrappedVillager::new).isOptimized()) return;
|
if (wrapperCache.get((Villager) event.getInventory().getHolder()).isOptimized()) return;
|
||||||
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
@ -2,13 +2,14 @@ package me.xginko.villageroptimizer.modules.gameplay;
|
|||||||
|
|
||||||
import com.cryptomorin.xseries.XEntityType;
|
import com.cryptomorin.xseries.XEntityType;
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
|
import me.xginko.villageroptimizer.enums.Permissions;
|
||||||
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Permissions;
|
|
||||||
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.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.entity.Player;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
@ -17,14 +18,10 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.SortedSet;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
public class RestockOptimizedTrades extends VillagerOptimizerModule implements Listener {
|
public class RestockOptimizedTrades extends VillagerOptimizerModule implements Listener {
|
||||||
|
|
||||||
private final SortedSet<Long> restockDayTimes;
|
private final long restock_delay_millis;
|
||||||
private final boolean log_enabled, notify_player;
|
private final boolean log_enabled, notify_player;
|
||||||
|
|
||||||
public RestockOptimizedTrades() {
|
public RestockOptimizedTrades() {
|
||||||
@ -32,10 +29,8 @@ public class RestockOptimizedTrades extends VillagerOptimizerModule implements L
|
|||||||
config.master().addComment(configPath,
|
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.restockDayTimes = new TreeSet<>(Comparator.reverseOrder());
|
this.restock_delay_millis = config.getInt(configPath + ".delay-in-ticks", 1000,
|
||||||
this.restockDayTimes.addAll(config.getList(configPath + ".restock-times", Arrays.asList(1000L, 13000L),
|
"1 second = 20 ticks. There are 24.000 ticks in a single minecraft day.") * 50L;
|
||||||
"At which (tick-)times during the day villagers will restock.\n" +
|
|
||||||
"There are 24.000 ticks in a single minecraft day."));
|
|
||||||
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);
|
||||||
@ -57,54 +52,30 @@ public class RestockOptimizedTrades extends VillagerOptimizerModule implements L
|
|||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
private void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
private void onInteract(PlayerInteractEntityEvent event) {
|
||||||
if (event.getRightClicked().getType() != XEntityType.VILLAGER.get()) return;
|
if (event.getRightClicked().getType() != XEntityType.VILLAGER.get()) return;
|
||||||
|
|
||||||
WrappedVillager wrapped = wrapperCache.get((Villager) event.getRightClicked(), WrappedVillager::new);
|
final WrappedVillager wVillager = wrapperCache.get((Villager) event.getRightClicked());
|
||||||
if (!wrapped.isOptimized()) return;
|
if (!wVillager.isOptimized()) return;
|
||||||
|
|
||||||
if (event.getPlayer().hasPermission(Permissions.Bypass.RESTOCK_COOLDOWN.get())) {
|
final Player player = event.getPlayer();
|
||||||
wrapped.restock();
|
final boolean player_bypassing = player.hasPermission(Permissions.Bypass.RESTOCK_COOLDOWN.get());
|
||||||
return;
|
if (!wVillager.canRestock(restock_delay_millis) && !player_bypassing) return;
|
||||||
}
|
|
||||||
|
|
||||||
long lastRestockFullTimeTicks = wrapped.getLastRestockFullTime();
|
wVillager.restock();
|
||||||
long currentFullTimeTicks = wrapped.currentFullTimeTicks();
|
wVillager.saveRestockTime();
|
||||||
long currentDayTimeTicks = wrapped.currentDayTimeTicks();
|
|
||||||
|
|
||||||
long currentDay = currentFullTimeTicks - currentDayTimeTicks;
|
if (notify_player && !player_bypassing) {
|
||||||
long ticksTillRestock = (24000 + currentDay + restockDayTimes.first()) - currentFullTimeTicks;
|
|
||||||
|
|
||||||
boolean restocked = false;
|
|
||||||
|
|
||||||
for (Long restockDayTime : restockDayTimes) {
|
|
||||||
long restockTimeToday = currentDay + restockDayTime;
|
|
||||||
|
|
||||||
if (currentFullTimeTicks < restockTimeToday || lastRestockFullTimeTicks >= restockTimeToday) {
|
|
||||||
ticksTillRestock = Math.min(ticksTillRestock, restockTimeToday - currentFullTimeTicks);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!restocked) {
|
|
||||||
wrapped.restock();
|
|
||||||
wrapped.saveRestockTime();
|
|
||||||
restocked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!restocked) return;
|
|
||||||
|
|
||||||
if (notify_player) {
|
|
||||||
final TextReplacementConfig timeLeft = TextReplacementConfig.builder()
|
final TextReplacementConfig timeLeft = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%time%")
|
.matchLiteral("%time%")
|
||||||
.replacement(Util.formatDuration(Duration.ofMillis(ticksTillRestock * 50L)))
|
.replacement(Util.formatDuration(Duration.ofMillis(wVillager.getRestockCooldownMillis(restock_delay_millis))))
|
||||||
.build();
|
.build();
|
||||||
VillagerOptimizer.getLang(event.getPlayer().locale()).trades_restocked
|
VillagerOptimizer.getLang(player.locale()).trades_restocked
|
||||||
.forEach(line -> KyoriUtil.sendMessage(event.getPlayer(), line.replaceText(timeLeft)));
|
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(timeLeft)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_enabled) {
|
if (log_enabled) {
|
||||||
info("Restocked optimized villager at " + LocationUtil.toString(wrapped.villager.getLocation()));
|
info("Restocked optimized villager at " + LocationUtil.toString(wVillager.villager().getLocation()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.xginko.villageroptimizer.modules.gameplay;
|
package me.xginko.villageroptimizer.modules.gameplay;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.struct.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 me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -35,9 +35,9 @@ public class UnoptimizeOnJobLoose extends VillagerOptimizerModule implements Lis
|
|||||||
@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() != VillagerCareerChangeEvent.ChangeReason.LOSING_JOB) return;
|
if (event.getReason() != VillagerCareerChangeEvent.ChangeReason.LOSING_JOB) return;
|
||||||
final WrappedVillager wrapped = wrapperCache.get(event.getEntity(), WrappedVillager::new);
|
final WrappedVillager wrappedVillager = wrapperCache.get(event.getEntity());
|
||||||
if (wrapped.isOptimized()) {
|
if (wrappedVillager.isOptimized()) {
|
||||||
wrapped.setOptimizationType(OptimizationType.NONE);
|
wrappedVillager.setOptimizationType(OptimizationType.NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ public class VisuallyHighlightOptimized extends VillagerOptimizerModule implemen
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
private void onOptimize(VillagerOptimizeEvent event) {
|
private void onOptimize(VillagerOptimizeEvent event) {
|
||||||
Villager villager = event.getWrappedVillager().villager;
|
Villager villager = event.getWrappedVillager().villager();
|
||||||
scheduling.entitySpecificScheduler(villager).run(glow -> {
|
scheduling.entitySpecificScheduler(villager).run(glow -> {
|
||||||
if (!villager.isGlowing()) villager.setGlowing(true);
|
if (!villager.isGlowing()) villager.setGlowing(true);
|
||||||
}, null);
|
}, null);
|
||||||
@ -42,7 +42,7 @@ public class VisuallyHighlightOptimized extends VillagerOptimizerModule implemen
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
private void onUnOptimize(VillagerUnoptimizeEvent event) {
|
private void onUnOptimize(VillagerUnoptimizeEvent event) {
|
||||||
Villager villager = event.getWrappedVillager().villager;
|
Villager villager = event.getWrappedVillager().villager();
|
||||||
scheduling.entitySpecificScheduler(villager).run(unGlow -> {
|
scheduling.entitySpecificScheduler(villager).run(unGlow -> {
|
||||||
if (villager.isGlowing()) villager.setGlowing(false);
|
if (villager.isGlowing()) villager.setGlowing(false);
|
||||||
}, null);
|
}, null);
|
||||||
|
@ -1,240 +0,0 @@
|
|||||||
package me.xginko.villageroptimizer.modules.optimization;
|
|
||||||
|
|
||||||
import com.cryptomorin.xseries.XEntityType;
|
|
||||||
import com.destroystokyo.paper.event.entity.EntityPathfindEvent;
|
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
|
||||||
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
|
||||||
import me.xginko.villageroptimizer.struct.models.BlockRegion2D;
|
|
||||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
|
||||||
import net.kyori.adventure.text.TextReplacementConfig;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.Villager;
|
|
||||||
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.EntityInteractEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
public class OptimizeByActivity extends VillagerOptimizerModule implements Listener {
|
|
||||||
|
|
||||||
protected static class RegionData {
|
|
||||||
|
|
||||||
public final BlockRegion2D region;
|
|
||||||
public final AtomicInteger pathfindCount, entityInteractCount;
|
|
||||||
public final AtomicBoolean regionBusy;
|
|
||||||
|
|
||||||
public RegionData(BlockRegion2D region) {
|
|
||||||
this.region = region;
|
|
||||||
this.pathfindCount = new AtomicInteger();
|
|
||||||
this.entityInteractCount = new AtomicInteger();
|
|
||||||
this.regionBusy = new AtomicBoolean(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Cache<BlockRegion2D, RegionData> regionDataCache;
|
|
||||||
private final double checkRadius;
|
|
||||||
private final int pathfindLimit, entityInteractLimit;
|
|
||||||
private final boolean notifyPlayers, doLogging;
|
|
||||||
|
|
||||||
public OptimizeByActivity() {
|
|
||||||
super("optimization-methods.regional-activity");
|
|
||||||
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.checkRadius = config.getDouble(configPath + ".check-radius-blocks", 500.0,
|
|
||||||
"The radius in blocks in which activity will be grouped together and measured.");
|
|
||||||
this.regionDataCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(
|
|
||||||
config.getInt(configPath + ".data-keep-time-millis", 10000,
|
|
||||||
"The time in milliseconds before a region and its data will be expired\n" +
|
|
||||||
"if no activity has been detected.\n" +
|
|
||||||
"For proper functionality, needs to be at least as long as your pause time."))).build();
|
|
||||||
|
|
||||||
this.pathfindLimit = config.getInt(configPath + ".limits.pathfind-event", 150);
|
|
||||||
this.entityInteractLimit = config.getInt(configPath + ".limits.interact-event", 50);
|
|
||||||
|
|
||||||
this.notifyPlayers = config.getBoolean(configPath + ".notify-players", true,
|
|
||||||
"Sends players a message to any player near an auto-optimized villager.");
|
|
||||||
this.doLogging = config.getBoolean(configPath + ".log", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enable() {
|
|
||||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disable() {
|
|
||||||
HandlerList.unregisterAll(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldEnable() {
|
|
||||||
return config.getBoolean(configPath + ".enable", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @NotNull RegionData getRegionData(Location location) {
|
|
||||||
return regionDataCache.get(getRegion(location), RegionData::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @NotNull BlockRegion2D getRegion(Location location) {
|
|
||||||
// Find and return region containing this location
|
|
||||||
for (Map.Entry<BlockRegion2D, RegionData> regionDataEntry : regionDataCache.asMap().entrySet()) {
|
|
||||||
if (regionDataEntry.getKey().contains(location)) {
|
|
||||||
return regionDataEntry.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and cache region if none exists
|
|
||||||
BlockRegion2D region = BlockRegion2D.of(location.getWorld(), location.getX(), location.getZ(), checkRadius);
|
|
||||||
regionDataCache.put(region, new RegionData(region));
|
|
||||||
return region;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
|
||||||
private void onEntityPathfind(EntityPathfindEvent event) {
|
|
||||||
if (event.getEntityType() != XEntityType.VILLAGER.get()) return;
|
|
||||||
|
|
||||||
Location location = event.getEntity().getLocation();
|
|
||||||
BlockRegion2D region2D = getRegion(location);
|
|
||||||
RegionData regionData = getRegionData(location);
|
|
||||||
|
|
||||||
if (regionData.regionBusy.get() || regionData.pathfindCount.incrementAndGet() <= pathfindLimit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
regionData.regionBusy.set(true);
|
|
||||||
|
|
||||||
AtomicInteger optimizeCount = new AtomicInteger();
|
|
||||||
Set<Player> playersWithinArea = new CopyOnWriteArraySet<>();
|
|
||||||
|
|
||||||
region2D.getEntities()
|
|
||||||
.thenAccept(entities -> {
|
|
||||||
for (Entity entity : entities) {
|
|
||||||
scheduling.entitySpecificScheduler(entity).run(() -> {
|
|
||||||
if (entity.getType() == XEntityType.VILLAGER.get()) {
|
|
||||||
WrappedVillager wrappedVillager = wrapperCache.get((Villager) entity, WrappedVillager::new);
|
|
||||||
|
|
||||||
if (wrappedVillager.isOptimized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wrappedVillager.setOptimizationType(OptimizationType.REGIONAL_ACTIVITY);
|
|
||||||
optimizeCount.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notifyPlayers && entity.getType() == XEntityType.PLAYER.get()) {
|
|
||||||
playersWithinArea.add((Player) entity);
|
|
||||||
}
|
|
||||||
}, null);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.thenRun(() -> {
|
|
||||||
if (notifyPlayers) {
|
|
||||||
TextReplacementConfig amount = TextReplacementConfig.builder()
|
|
||||||
.matchLiteral("%amount%")
|
|
||||||
.replacement(optimizeCount.toString())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
for (Player player : playersWithinArea) {
|
|
||||||
VillagerOptimizer.scheduling().entitySpecificScheduler(player).run(() ->
|
|
||||||
VillagerOptimizer.getLang(player.locale()).activity_optimize_success
|
|
||||||
.forEach(line -> player.sendMessage(line.replaceText(amount))),
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
playersWithinArea.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doLogging) {
|
|
||||||
info( "Optimized " + optimizeCount.get() + " villagers in a radius of " + checkRadius +
|
|
||||||
" blocks from center at x=" + regionData.region.getCenterX() + ", z=" + regionData.region.getCenterZ() +
|
|
||||||
" in world " + location.getWorld().getName() +
|
|
||||||
"because of too high pathfinding activity within the configured timeframe: " +
|
|
||||||
regionData.pathfindCount + " (limit: " + pathfindLimit + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
regionDataCache.invalidate(region2D);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
|
||||||
private void onEntityInteract(EntityInteractEvent event) {
|
|
||||||
if (event.getEntityType() != XEntityType.VILLAGER.get()) return;
|
|
||||||
|
|
||||||
Location location = event.getEntity().getLocation();
|
|
||||||
BlockRegion2D region2D = getRegion(location);
|
|
||||||
RegionData regionData = getRegionData(location);
|
|
||||||
|
|
||||||
if (regionData.regionBusy.get() || regionData.entityInteractCount.incrementAndGet() <= entityInteractLimit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
regionData.regionBusy.set(true);
|
|
||||||
|
|
||||||
AtomicInteger optimizeCount = new AtomicInteger();
|
|
||||||
Set<Player> playersWithinArea = new CopyOnWriteArraySet<>();
|
|
||||||
|
|
||||||
region2D.getEntities()
|
|
||||||
.thenAccept(entities -> {
|
|
||||||
for (Entity entity : entities) {
|
|
||||||
scheduling.entitySpecificScheduler(entity).run(() -> {
|
|
||||||
if (entity.getType() == XEntityType.VILLAGER.get()) {
|
|
||||||
WrappedVillager wrappedVillager = wrapperCache.get((Villager) entity, WrappedVillager::new);
|
|
||||||
|
|
||||||
if (wrappedVillager.isOptimized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wrappedVillager.setOptimizationType(OptimizationType.REGIONAL_ACTIVITY);
|
|
||||||
optimizeCount.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notifyPlayers && entity.getType() == XEntityType.PLAYER.get()) {
|
|
||||||
playersWithinArea.add((Player) entity);
|
|
||||||
}
|
|
||||||
}, null);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.thenRun(() -> {
|
|
||||||
if (notifyPlayers) {
|
|
||||||
TextReplacementConfig amount = TextReplacementConfig.builder()
|
|
||||||
.matchLiteral("%amount%")
|
|
||||||
.replacement(optimizeCount.toString())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
for (Player player : playersWithinArea) {
|
|
||||||
VillagerOptimizer.scheduling().entitySpecificScheduler(player).run(() ->
|
|
||||||
VillagerOptimizer.getLang(player.locale()).activity_optimize_success
|
|
||||||
.forEach(line -> player.sendMessage(line.replaceText(amount))),
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
playersWithinArea.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doLogging) {
|
|
||||||
info( "Optimized " + optimizeCount.get() + " villagers in a radius of " + checkRadius +
|
|
||||||
" blocks from center at x=" + regionData.region.getCenterX() + ", z=" + regionData.region.getCenterZ() +
|
|
||||||
" in world " + location.getWorld().getName() +
|
|
||||||
"because of too many villagers interacting with objects within the configured timeframe: " +
|
|
||||||
regionData.pathfindCount + " (limit: " + pathfindLimit + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
regionDataCache.invalidate(region2D);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,8 +2,8 @@ package me.xginko.villageroptimizer.modules.optimization;
|
|||||||
|
|
||||||
import com.cryptomorin.xseries.XMaterial;
|
import com.cryptomorin.xseries.XMaterial;
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import me.xginko.villageroptimizer.struct.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;
|
||||||
@ -111,7 +111,7 @@ public class OptimizeByBlock extends VillagerOptimizerModule implements 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 = wrapperCache.get(villager, WrappedVillager::new);
|
final WrappedVillager wVillager = wrapperCache.get(villager);
|
||||||
if (wVillager.canOptimize(cooldown_millis)) {
|
if (wVillager.canOptimize(cooldown_millis)) {
|
||||||
closestOptimizableVillager = wVillager;
|
closestOptimizableVillager = wVillager;
|
||||||
closestDistance = distance;
|
closestDistance = distance;
|
||||||
@ -135,11 +135,11 @@ public class OptimizeByBlock extends VillagerOptimizerModule implements Listener
|
|||||||
if (notify_player) {
|
if (notify_player) {
|
||||||
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%vil_profession%")
|
.matchLiteral("%vil_profession%")
|
||||||
.replacement(Util.toNiceString(closestOptimizableVillager.villager.getProfession()))
|
.replacement(Util.formatEnum(closestOptimizableVillager.villager().getProfession()))
|
||||||
.build();
|
.build();
|
||||||
final TextReplacementConfig placedMaterial = TextReplacementConfig.builder()
|
final TextReplacementConfig placedMaterial = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%blocktype%")
|
.matchLiteral("%blocktype%")
|
||||||
.replacement(Util.toNiceString(placed.getType()))
|
.replacement(Util.formatEnum(placed.getType()))
|
||||||
.build();
|
.build();
|
||||||
VillagerOptimizer.getLang(player.locale()).block_optimize_success
|
VillagerOptimizer.getLang(player.locale()).block_optimize_success
|
||||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(placedMaterial)));
|
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(placedMaterial)));
|
||||||
@ -147,7 +147,7 @@ public class OptimizeByBlock extends VillagerOptimizerModule implements Listener
|
|||||||
|
|
||||||
if (log_enabled) {
|
if (log_enabled) {
|
||||||
info(player.getName() + " optimized villager at " +
|
info(player.getName() + " optimized villager at " +
|
||||||
LocationUtil.toString(closestOptimizableVillager.villager.getLocation()));
|
LocationUtil.toString(closestOptimizableVillager.villager().getLocation()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
closestOptimizableVillager.sayNo();
|
closestOptimizableVillager.sayNo();
|
||||||
@ -178,7 +178,7 @@ public class OptimizeByBlock extends VillagerOptimizerModule implements 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 = wrapperCache.get(villager, WrappedVillager::new);
|
final WrappedVillager wVillager = wrapperCache.get(villager);
|
||||||
if (wVillager.isOptimized()) {
|
if (wVillager.isOptimized()) {
|
||||||
closestOptimizedVillager = wVillager;
|
closestOptimizedVillager = wVillager;
|
||||||
closestDistance = distance;
|
closestDistance = distance;
|
||||||
@ -200,19 +200,19 @@ public class OptimizeByBlock extends VillagerOptimizerModule implements Listener
|
|||||||
if (notify_player) {
|
if (notify_player) {
|
||||||
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%vil_profession%")
|
.matchLiteral("%vil_profession%")
|
||||||
.replacement(Util.toNiceString(closestOptimizedVillager.villager.getProfession()))
|
.replacement(Util.formatEnum(closestOptimizedVillager.villager().getProfession()))
|
||||||
.build();
|
.build();
|
||||||
final TextReplacementConfig brokenMaterial = TextReplacementConfig.builder()
|
final TextReplacementConfig brokenMaterial = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%blocktype%")
|
.matchLiteral("%blocktype%")
|
||||||
.replacement(Util.toNiceString(broken.getType()))
|
.replacement(Util.formatEnum(broken.getType()))
|
||||||
.build();
|
.build();
|
||||||
VillagerOptimizer.getLang(player.locale()).block_unoptimize_success
|
VillagerOptimizer.getLang(player.locale()).block_unoptimize_success
|
||||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(brokenMaterial)));
|
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(brokenMaterial)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_enabled) {
|
if (log_enabled) {
|
||||||
info(player.getName() + " unoptimized villager using " + Util.toNiceString(broken.getType()) +
|
info(player.getName() + " unoptimized villager using " + Util.formatEnum(broken.getType()) +
|
||||||
LocationUtil.toString(closestOptimizedVillager.villager.getLocation()));
|
LocationUtil.toString(closestOptimizedVillager.villager().getLocation()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,8 +3,8 @@ package me.xginko.villageroptimizer.modules.optimization;
|
|||||||
import com.cryptomorin.xseries.XEntityType;
|
import com.cryptomorin.xseries.XEntityType;
|
||||||
import com.cryptomorin.xseries.XMaterial;
|
import com.cryptomorin.xseries.XMaterial;
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import me.xginko.villageroptimizer.struct.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;
|
||||||
@ -14,7 +14,6 @@ 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.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -86,12 +85,13 @@ public class OptimizeByNametag extends VillagerOptimizerModule implements Listen
|
|||||||
if (!meta.hasDisplayName()) return;
|
if (!meta.hasDisplayName()) return;
|
||||||
|
|
||||||
final String nameTagPlainText = ChatColor.stripColor(meta.getDisplayName());
|
final String nameTagPlainText = ChatColor.stripColor(meta.getDisplayName());
|
||||||
final WrappedVillager wrapped = wrapperCache.get((Villager) event.getRightClicked(), WrappedVillager::new);
|
final Villager villager = (Villager) event.getRightClicked();
|
||||||
|
final WrappedVillager wVillager = wrapperCache.get(villager);
|
||||||
|
|
||||||
if (nametags.contains(nameTagPlainText.toLowerCase())) {
|
if (nametags.contains(nameTagPlainText.toLowerCase())) {
|
||||||
if (wrapped.canOptimize(cooldown) || player.hasPermission(Permissions.Bypass.NAMETAG_COOLDOWN.get())) {
|
if (wVillager.canOptimize(cooldown) || player.hasPermission(Permissions.Bypass.NAMETAG_COOLDOWN.get())) {
|
||||||
VillagerOptimizeEvent optimizeEvent = new VillagerOptimizeEvent(
|
VillagerOptimizeEvent optimizeEvent = new VillagerOptimizeEvent(
|
||||||
wrapped,
|
wVillager,
|
||||||
OptimizationType.NAMETAG,
|
OptimizationType.NAMETAG,
|
||||||
player,
|
player,
|
||||||
event.isAsynchronous()
|
event.isAsynchronous()
|
||||||
@ -99,13 +99,14 @@ public class OptimizeByNametag extends VillagerOptimizerModule implements Listen
|
|||||||
|
|
||||||
if (!optimizeEvent.callEvent()) return;
|
if (!optimizeEvent.callEvent()) return;
|
||||||
|
|
||||||
wrapped.setOptimizationType(optimizeEvent.getOptimizationType());
|
if (!consume_nametag) {
|
||||||
wrapped.saveOptimizeTime();
|
|
||||||
|
|
||||||
if (!consume_nametag && player.getGameMode() == GameMode.SURVIVAL) {
|
|
||||||
player.getInventory().addItem(usedItem.asOne());
|
player.getInventory().addItem(usedItem.asOne());
|
||||||
|
player.updateInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wVillager.setOptimizationType(optimizeEvent.getOptimizationType());
|
||||||
|
wVillager.saveOptimizeTime();
|
||||||
|
|
||||||
if (notify_player) {
|
if (notify_player) {
|
||||||
VillagerOptimizer.getLang(player.locale()).nametag_optimize_success
|
VillagerOptimizer.getLang(player.locale()).nametag_optimize_success
|
||||||
.forEach(line -> KyoriUtil.sendMessage(player, line));
|
.forEach(line -> KyoriUtil.sendMessage(player, line));
|
||||||
@ -113,35 +114,31 @@ public class OptimizeByNametag extends VillagerOptimizerModule implements Listen
|
|||||||
|
|
||||||
if (log_enabled) {
|
if (log_enabled) {
|
||||||
info(player.getName() + " optimized villager using nametag '" + nameTagPlainText + "' at " +
|
info(player.getName() + " optimized villager using nametag '" + nameTagPlainText + "' at " +
|
||||||
LocationUtil.toString(wrapped.villager.getLocation()));
|
LocationUtil.toString(wVillager.villager().getLocation()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
wrapped.sayNo();
|
wVillager.sayNo();
|
||||||
if (notify_player) {
|
if (notify_player) {
|
||||||
final TextReplacementConfig timeLeft = TextReplacementConfig.builder()
|
final TextReplacementConfig timeLeft = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%time%")
|
.matchLiteral("%time%")
|
||||||
.replacement(Util.formatDuration(Duration.ofMillis(wrapped.getOptimizeCooldownMillis(cooldown))))
|
.replacement(Util.formatDuration(Duration.ofMillis(wVillager.getOptimizeCooldownMillis(cooldown))))
|
||||||
.build();
|
.build();
|
||||||
VillagerOptimizer.getLang(player.locale()).nametag_on_optimize_cooldown
|
VillagerOptimizer.getLang(player.locale()).nametag_on_optimize_cooldown
|
||||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(timeLeft)));
|
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(timeLeft)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (wrapped.isOptimized()) {
|
if (wVillager.isOptimized()) {
|
||||||
VillagerUnoptimizeEvent unOptimizeEvent = new VillagerUnoptimizeEvent(
|
VillagerUnoptimizeEvent unOptimizeEvent = new VillagerUnoptimizeEvent(
|
||||||
wrapped,
|
wVillager,
|
||||||
player,
|
player,
|
||||||
OptimizationType.NAMETAG,
|
OptimizationType.NAMETAG,
|
||||||
event.isAsynchronous()
|
event.isAsynchronous()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!unOptimizeEvent.callEvent()) return;
|
if (!unOptimizeEvent.callEvent()) return;
|
||||||
wrapped.setOptimizationType(OptimizationType.NONE);
|
wVillager.setOptimizationType(OptimizationType.NONE);
|
||||||
|
|
||||||
if (!consume_nametag && player.getGameMode() == GameMode.SURVIVAL) {
|
|
||||||
player.getInventory().addItem(usedItem.asOne());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notify_player) {
|
if (notify_player) {
|
||||||
VillagerOptimizer.getLang(player.locale()).nametag_unoptimize_success
|
VillagerOptimizer.getLang(player.locale()).nametag_unoptimize_success
|
||||||
@ -150,7 +147,7 @@ public class OptimizeByNametag extends VillagerOptimizerModule implements Listen
|
|||||||
|
|
||||||
if (log_enabled) {
|
if (log_enabled) {
|
||||||
info(player.getName() + " unoptimized villager using nametag '" + nameTagPlainText + "' at " +
|
info(player.getName() + " unoptimized villager using nametag '" + nameTagPlainText + "' at " +
|
||||||
LocationUtil.toString(wrapped.villager.getLocation()));
|
LocationUtil.toString(wVillager.villager().getLocation()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package me.xginko.villageroptimizer.modules.optimization;
|
package me.xginko.villageroptimizer.modules.optimization;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import me.xginko.villageroptimizer.struct.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;
|
||||||
@ -92,17 +92,14 @@ public class OptimizeByWorkstation extends VillagerOptimizerModule implements Li
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Villager villager : workstationLoc.getNearbyEntitiesByType(Villager.class, search_radius)) {
|
for (Villager villager : workstationLoc.getNearbyEntitiesByType(Villager.class, search_radius)) {
|
||||||
scheduling.entitySpecificScheduler(villager).run(() -> {
|
if (villager.getProfession() != workstationProfession) continue;
|
||||||
if (villager.getProfession() != workstationProfession) return;
|
WrappedVillager wrapped = wrapperCache.get(villager);
|
||||||
WrappedVillager wrapped = wrapperCache.get(villager, WrappedVillager::new);
|
if (wrapped.getJobSite() == null) continue;
|
||||||
|
if (wrapped.getJobSite().getWorld().getUID() != workstationLoc.getWorld().getUID()) continue;
|
||||||
Location jobSite = wrapped.getJobSite();
|
if (LocationUtil.relDistance3DSquared(wrapped.getJobSite(), workstationLoc) > 1) continue;
|
||||||
if (jobSite == null || jobSite.getWorld().getUID() != workstationLoc.getWorld().getUID()) return;
|
|
||||||
if (LocationUtil.relDistance3DSquared(jobSite, workstationLoc) > 1) return;
|
|
||||||
|
|
||||||
if (!wrapped.canOptimize(cooldown_millis) && !player.hasPermission(Permissions.Bypass.WORKSTATION_COOLDOWN.get())) {
|
if (!wrapped.canOptimize(cooldown_millis) && !player.hasPermission(Permissions.Bypass.WORKSTATION_COOLDOWN.get())) {
|
||||||
wrapped.sayNo();
|
wrapped.sayNo();
|
||||||
|
|
||||||
if (notify_player) {
|
if (notify_player) {
|
||||||
final TextReplacementConfig timeLeft = TextReplacementConfig.builder()
|
final TextReplacementConfig timeLeft = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%time%")
|
.matchLiteral("%time%")
|
||||||
@ -111,7 +108,6 @@ public class OptimizeByWorkstation extends VillagerOptimizerModule implements Li
|
|||||||
VillagerOptimizer.getLang(player.locale()).nametag_on_optimize_cooldown
|
VillagerOptimizer.getLang(player.locale()).nametag_on_optimize_cooldown
|
||||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(timeLeft)));
|
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(timeLeft)));
|
||||||
}
|
}
|
||||||
|
|
||||||
taskComplete.set(true);
|
taskComplete.set(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -131,23 +127,23 @@ public class OptimizeByWorkstation extends VillagerOptimizerModule implements Li
|
|||||||
if (notify_player) {
|
if (notify_player) {
|
||||||
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%vil_profession%")
|
.matchLiteral("%vil_profession%")
|
||||||
.replacement(Util.toNiceString(wrapped.villager.getProfession()))
|
.replacement(Util.formatEnum(wrapped.villager().getProfession()))
|
||||||
.build();
|
.build();
|
||||||
final TextReplacementConfig placedWorkstation = TextReplacementConfig.builder()
|
final TextReplacementConfig placedWorkstation = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%blocktype%")
|
.matchLiteral("%blocktype%")
|
||||||
.replacement(Util.toNiceString(placed.getType()))
|
.replacement(Util.formatEnum(placed.getType()))
|
||||||
.build();
|
.build();
|
||||||
VillagerOptimizer.getLang(player.locale()).workstation_optimize_success
|
VillagerOptimizer.getLang(player.locale()).workstation_optimize_success
|
||||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(placedWorkstation)));
|
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(placedWorkstation)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_enabled) {
|
if (log_enabled) {
|
||||||
info(player.getName() + " optimized villager using workstation " + Util.toNiceString(placed.getType()) + " at " +
|
info(player.getName() + " optimized villager using workstation " + Util.formatEnum(placed.getType()) + " at " +
|
||||||
LocationUtil.toString(wrapped.villager.getLocation()));
|
LocationUtil.toString(wrapped.villager().getLocation()));
|
||||||
}
|
}
|
||||||
|
|
||||||
taskComplete.set(true);
|
taskComplete.set(true);
|
||||||
}, null);
|
return;
|
||||||
}
|
}
|
||||||
}, 1L, 10L);
|
}, 1L, 10L);
|
||||||
}
|
}
|
||||||
@ -171,7 +167,7 @@ public class OptimizeByWorkstation extends VillagerOptimizerModule implements Li
|
|||||||
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 = wrapperCache.get(villager, WrappedVillager::new);
|
WrappedVillager wrapped = wrapperCache.get(villager);
|
||||||
|
|
||||||
if (wrapped.isOptimized()) {
|
if (wrapped.isOptimized()) {
|
||||||
closestOptimized = wrapped;
|
closestOptimized = wrapped;
|
||||||
@ -195,19 +191,19 @@ public class OptimizeByWorkstation extends VillagerOptimizerModule implements Li
|
|||||||
if (notify_player) {
|
if (notify_player) {
|
||||||
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%vil_profession%")
|
.matchLiteral("%vil_profession%")
|
||||||
.replacement(Util.toNiceString(closestOptimized.villager.getProfession()))
|
.replacement(Util.formatEnum(closestOptimized.villager().getProfession()))
|
||||||
.build();
|
.build();
|
||||||
final TextReplacementConfig brokenWorkstation = TextReplacementConfig.builder()
|
final TextReplacementConfig brokenWorkstation = TextReplacementConfig.builder()
|
||||||
.matchLiteral("%blocktype%")
|
.matchLiteral("%blocktype%")
|
||||||
.replacement(Util.toNiceString(broken.getType()))
|
.replacement(Util.formatEnum(broken.getType()))
|
||||||
.build();
|
.build();
|
||||||
VillagerOptimizer.getLang(player.locale()).workstation_unoptimize_success
|
VillagerOptimizer.getLang(player.locale()).workstation_unoptimize_success
|
||||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(brokenWorkstation)));
|
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(brokenWorkstation)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_enabled) {
|
if (log_enabled) {
|
||||||
info(player.getName() + " unoptimized villager using workstation " + Util.toNiceString(broken.getType()) + " at " +
|
info(player.getName() + " unoptimized villager using workstation " + Util.formatEnum(broken.getType()) + " at " +
|
||||||
LocationUtil.toString(closestOptimized.villager.getLocation()));
|
LocationUtil.toString(closestOptimized.villager().getLocation()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,131 +0,0 @@
|
|||||||
package me.xginko.villageroptimizer.struct.models;
|
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public class BlockRegion2D {
|
|
||||||
|
|
||||||
private final UUID worldUID;
|
|
||||||
private final double halfSideLength, centerX, centerZ;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A square region on a minecraft world map.
|
|
||||||
*
|
|
||||||
* @param worldUID The UUID of the world this region is in.
|
|
||||||
* @param centerX The X-axis of the center location on the map.
|
|
||||||
* @param centerZ The Z-axis of the center location on the map.
|
|
||||||
* @param halfSideLength Half the length of the square's side. Acts like a radius would on circular regions.
|
|
||||||
*/
|
|
||||||
public BlockRegion2D(UUID worldUID, double centerX, double centerZ, double halfSideLength) {
|
|
||||||
this.worldUID = worldUID;
|
|
||||||
this.centerX = centerX;
|
|
||||||
this.centerZ = centerZ;
|
|
||||||
this.halfSideLength = halfSideLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a square region on a minecraft world map.
|
|
||||||
*
|
|
||||||
* @param worldUID The UUID of the world this region is in.
|
|
||||||
* @param centerX The X-axis of the center location on the map.
|
|
||||||
* @param centerZ The Z-axis of the center location on the map.
|
|
||||||
* @param halfSideLength Half the length of the square's side. Acts like a radius would on circular regions.
|
|
||||||
*/
|
|
||||||
public static BlockRegion2D of(UUID worldUID, double centerX, double centerZ, double halfSideLength) {
|
|
||||||
return new BlockRegion2D(worldUID, centerX, centerZ, halfSideLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a square region on a minecraft world map.
|
|
||||||
*
|
|
||||||
* @param world The world this region is in.
|
|
||||||
* @param centerX The X-axis of the center location on the map.
|
|
||||||
* @param centerZ The Z-axis of the center location on the map.
|
|
||||||
* @param halfSideLength Half the length of the square's side. Acts like a radius would on circular regions.
|
|
||||||
*/
|
|
||||||
public static BlockRegion2D of(World world, double centerX, double centerZ, double halfSideLength) {
|
|
||||||
return BlockRegion2D.of(world.getUID(), centerX, centerZ, halfSideLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getWorldUID() {
|
|
||||||
return this.worldUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getHalfSideLength() {
|
|
||||||
return this.halfSideLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getCenterX() {
|
|
||||||
return this.centerX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getCenterZ() {
|
|
||||||
return this.centerZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Location location) {
|
|
||||||
if (!location.getWorld().getUID().equals(this.worldUID)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return location.getX() >= this.centerX - this.halfSideLength
|
|
||||||
&& location.getX() <= this.centerX + this.halfSideLength
|
|
||||||
&& location.getZ() >= this.centerZ - this.halfSideLength
|
|
||||||
&& location.getZ() <= this.centerZ + this.halfSideLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<Collection<Entity>> getEntities() {
|
|
||||||
World world = Bukkit.getWorld(worldUID);
|
|
||||||
|
|
||||||
if (world == null) {
|
|
||||||
// Only way I can imagine this happening would be if the server is using a world manager plugin and unloads
|
|
||||||
// the world during an operation.
|
|
||||||
// Since these plugins are rather common though, we will silently complete with an empty set instead of exceptionally.
|
|
||||||
return CompletableFuture.completedFuture(Collections.emptySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletableFuture<Collection<Entity>> future = new CompletableFuture<>();
|
|
||||||
Location centerLoc = new Location(world, centerX, world.getMinHeight(), centerZ);
|
|
||||||
|
|
||||||
VillagerOptimizer.scheduling().regionSpecificScheduler(centerLoc).run(() -> future.complete(
|
|
||||||
centerLoc.getNearbyEntities(
|
|
||||||
halfSideLength,
|
|
||||||
Math.abs(world.getMaxHeight()) + Math.abs(world.getMinHeight()), // World y can be between -64 and 320, we want everything from top to bottom
|
|
||||||
halfSideLength
|
|
||||||
)));
|
|
||||||
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (null == obj || obj.getClass() != BlockRegion2D.class)
|
|
||||||
return false;
|
|
||||||
BlockRegion2D blockRegion2D = (BlockRegion2D)obj;
|
|
||||||
return blockRegion2D.worldUID.equals(this.worldUID) && blockRegion2D.centerX == this.centerX && blockRegion2D.centerZ == this.centerZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(this.worldUID, this.centerX, this.centerZ, this.halfSideLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "BlockRegion2D{" +
|
|
||||||
" radius(half side length)=" + halfSideLength +
|
|
||||||
", centerX=" + centerX +
|
|
||||||
", centerZ=" + centerZ +
|
|
||||||
", worldUID=" + worldUID +
|
|
||||||
"}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package me.xginko.villageroptimizer.logging;
|
package me.xginko.villageroptimizer.utils;
|
||||||
|
|
||||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||||
import net.kyori.adventure.text.logger.slf4j.ComponentLoggerProvider;
|
import net.kyori.adventure.text.logger.slf4j.ComponentLoggerProvider;
|
@ -1,4 +1,4 @@
|
|||||||
package me.xginko.villageroptimizer.struct;
|
package me.xginko.villageroptimizer.utils;
|
||||||
|
|
||||||
public interface Disableable {
|
public interface Disableable {
|
||||||
void disable();
|
void disable();
|
@ -1,4 +1,4 @@
|
|||||||
package me.xginko.villageroptimizer.struct;
|
package me.xginko.villageroptimizer.utils;
|
||||||
|
|
||||||
public interface Enableable {
|
public interface Enableable {
|
||||||
void enable();
|
void enable();
|
@ -1,4 +1,4 @@
|
|||||||
package me.xginko.villageroptimizer.struct.models;
|
package me.xginko.villageroptimizer.utils;
|
||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
@ -63,7 +63,7 @@ public final class ExpiringSet<E> extends AbstractSet<E> implements Set<E> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Object item) {
|
public boolean contains(Object item) {
|
||||||
return this.cache.getIfPresent(item) != null;
|
return this.cache.getIfPresent((E) item) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
@ -11,11 +11,11 @@ import java.util.Locale;
|
|||||||
public class KyoriUtil {
|
public class KyoriUtil {
|
||||||
|
|
||||||
public static void sendMessage(@NotNull CommandSender sender, @NotNull Component message) {
|
public static void sendMessage(@NotNull CommandSender sender, @NotNull Component message) {
|
||||||
VillagerOptimizer.audiences().sender(sender).sendMessage(message);
|
VillagerOptimizer.getAudiences().sender(sender).sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendActionBar(@NotNull CommandSender sender, @NotNull Component message) {
|
public static void sendActionBar(@NotNull CommandSender sender, @NotNull Component message) {
|
||||||
VillagerOptimizer.audiences().sender(sender).sendActionBar(message);
|
VillagerOptimizer.getAudiences().sender(sender).sendActionBar(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull Component toUpperCase(@NotNull Component input, @NotNull Locale locale) {
|
public static @NotNull Component toUpperCase(@NotNull Component input, @NotNull Locale locale) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package me.xginko.villageroptimizer.logging;
|
package me.xginko.villageroptimizer.utils;
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.TranslatableComponent;
|
import net.kyori.adventure.text.TranslatableComponent;
|
@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashMap;
|
import java.util.EnumMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -25,8 +25,7 @@ public class Util {
|
|||||||
static {
|
static {
|
||||||
PL_COLOR = TextColor.color(102,255,230);
|
PL_COLOR = TextColor.color(102,255,230);
|
||||||
PL_STYLE = Style.style(PL_COLOR, TextDecoration.BOLD);
|
PL_STYLE = Style.style(PL_COLOR, TextDecoration.BOLD);
|
||||||
|
PROFESSION_MAP = new EnumMap<>(Material.class);
|
||||||
PROFESSION_MAP = new HashMap<>();
|
|
||||||
PROFESSION_MAP.put(XMaterial.LOOM.parseMaterial(), Villager.Profession.SHEPHERD);
|
PROFESSION_MAP.put(XMaterial.LOOM.parseMaterial(), Villager.Profession.SHEPHERD);
|
||||||
PROFESSION_MAP.put(XMaterial.BARREL.parseMaterial(), Villager.Profession.FISHERMAN);
|
PROFESSION_MAP.put(XMaterial.BARREL.parseMaterial(), Villager.Profession.FISHERMAN);
|
||||||
PROFESSION_MAP.put(XMaterial.SMOKER.parseMaterial(), Villager.Profession.BUTCHER);
|
PROFESSION_MAP.put(XMaterial.SMOKER.parseMaterial(), Villager.Profession.BUTCHER);
|
||||||
@ -40,7 +39,6 @@ public class Util {
|
|||||||
PROFESSION_MAP.put(XMaterial.SMITHING_TABLE.parseMaterial(), Villager.Profession.TOOLSMITH);
|
PROFESSION_MAP.put(XMaterial.SMITHING_TABLE.parseMaterial(), Villager.Profession.TOOLSMITH);
|
||||||
PROFESSION_MAP.put(XMaterial.FLETCHING_TABLE.parseMaterial(), Villager.Profession.FLETCHER);
|
PROFESSION_MAP.put(XMaterial.FLETCHING_TABLE.parseMaterial(), Villager.Profession.FLETCHER);
|
||||||
PROFESSION_MAP.put(XMaterial.CARTOGRAPHY_TABLE.parseMaterial(), Villager.Profession.CARTOGRAPHER);
|
PROFESSION_MAP.put(XMaterial.CARTOGRAPHY_TABLE.parseMaterial(), Villager.Profession.CARTOGRAPHER);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Chunk.class.getMethod("isEntitiesLoaded");
|
Chunk.class.getMethod("isEntitiesLoaded");
|
||||||
canUseIsEntitiesLoaded = true;
|
canUseIsEntitiesLoaded = true;
|
||||||
@ -73,24 +71,14 @@ public class Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull String toNiceString(@NotNull Object input) {
|
public static @NotNull String formatEnum(@NotNull Enum<?> input) {
|
||||||
// Get name
|
|
||||||
String name;
|
|
||||||
if (input instanceof Enum<?>) {
|
|
||||||
name = ((Enum<?>) input).name();
|
|
||||||
} else {
|
|
||||||
name = input.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn something like "REDSTONE_TORCH" into "redstone torch"
|
// Turn something like "REDSTONE_TORCH" into "redstone torch"
|
||||||
String[] lowercaseWords = name.toLowerCase(Locale.ROOT).split("_");
|
String[] lowercaseWords = input.name().toLowerCase(Locale.ROOT).split("_");
|
||||||
|
|
||||||
// Capitalize first letter for each word
|
|
||||||
for (int i = 0; i < lowercaseWords.length; i++) {
|
for (int i = 0; i < lowercaseWords.length; i++) {
|
||||||
String word = lowercaseWords[i];
|
String word = lowercaseWords[i];
|
||||||
|
// Capitalize first letter for each word
|
||||||
lowercaseWords[i] = word.substring(0, 1).toUpperCase() + word.substring(1);
|
lowercaseWords[i] = word.substring(0, 1).toUpperCase() + word.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return as nice string
|
// return as nice string
|
||||||
return String.join(" ", lowercaseWords);
|
return String.join(" ", lowercaseWords);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
package me.xginko.villageroptimizer.wrapper;
|
package me.xginko.villageroptimizer.wrapper;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Keyring;
|
import me.xginko.villageroptimizer.enums.Keyring;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class PDCWrapperAVL extends PDCWrapper {
|
public class AVLVillagerDataHandlerImpl implements VillagerDataHandler {
|
||||||
|
|
||||||
PDCWrapperAVL(@NotNull Villager villager) {
|
private final @NotNull Villager villager;
|
||||||
super(villager);
|
private final @NotNull PersistentDataContainer dataContainer;
|
||||||
|
|
||||||
|
AVLVillagerDataHandlerImpl(@NotNull Villager villager) {
|
||||||
|
this.villager = villager;
|
||||||
|
this.dataContainer = villager.getPersistentDataContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -99,16 +104,21 @@ public final class PDCWrapperAVL extends PDCWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLastRestockFullTime() {
|
public boolean canRestock(long cooldown_millis) {
|
||||||
if (dataContainer.has(Keyring.AntiVillagerLag.LAST_RESTOCK_WORLD_FULLTIME.getKey(), PersistentDataType.LONG)) {
|
return !dataContainer.has(Keyring.AntiVillagerLag.LAST_RESTOCK_WORLDFULLTIME.getKey(), PersistentDataType.LONG)
|
||||||
return dataContainer.get(Keyring.AntiVillagerLag.LAST_RESTOCK_WORLD_FULLTIME.getKey(), PersistentDataType.LONG);
|
|| villager.getWorld().getFullTime() > dataContainer.get(Keyring.AntiVillagerLag.LAST_RESTOCK_WORLDFULLTIME.getKey(), PersistentDataType.LONG);
|
||||||
}
|
|
||||||
return 0L;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveRestockTime() {
|
public void saveRestockTime() {
|
||||||
dataContainer.set(Keyring.AntiVillagerLag.LAST_RESTOCK_WORLD_FULLTIME.getKey(), PersistentDataType.LONG, villager.getWorld().getFullTime());
|
dataContainer.set(Keyring.AntiVillagerLag.LAST_RESTOCK_WORLDFULLTIME.getKey(), PersistentDataType.LONG, villager.getWorld().getFullTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRestockCooldownMillis(long cooldown_millis) {
|
||||||
|
if (dataContainer.has(Keyring.AntiVillagerLag.LAST_RESTOCK_WORLDFULLTIME.getKey(), PersistentDataType.LONG))
|
||||||
|
return (villager.getWorld().getFullTime() - dataContainer.get(Keyring.AntiVillagerLag.LAST_RESTOCK_WORLDFULLTIME.getKey(), PersistentDataType.LONG)) * 50L;
|
||||||
|
return cooldown_millis;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -1,16 +1,21 @@
|
|||||||
package me.xginko.villageroptimizer.wrapper;
|
package me.xginko.villageroptimizer.wrapper;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Keyring;
|
import me.xginko.villageroptimizer.enums.Keyring;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public final class PDCWrapperVO extends PDCWrapper {
|
public class MainVillagerDataHandlerImpl implements VillagerDataHandler {
|
||||||
|
|
||||||
PDCWrapperVO(@NotNull Villager villager) {
|
private final @NotNull Villager villager;
|
||||||
super(villager);
|
private final @NotNull PersistentDataContainer dataContainer;
|
||||||
|
|
||||||
|
MainVillagerDataHandlerImpl(@NotNull Villager villager) {
|
||||||
|
this.villager = villager;
|
||||||
|
this.dataContainer = villager.getPersistentDataContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,16 +87,30 @@ public final class PDCWrapperVO extends PDCWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLastRestockFullTime() {
|
public boolean canRestock(long cooldown_millis) {
|
||||||
if (dataContainer.has(Keyring.VillagerOptimizer.LAST_RESTOCK_WORLD_FULLTIME.getKey(), PersistentDataType.LONG)) {
|
return getLastRestock() + cooldown_millis <= System.currentTimeMillis();
|
||||||
return dataContainer.get(Keyring.VillagerOptimizer.LAST_RESTOCK_WORLD_FULLTIME.getKey(), PersistentDataType.LONG);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveRestockTime() {
|
||||||
|
dataContainer.set(Keyring.VillagerOptimizer.LAST_RESTOCK_SYSTIME_MILLIS.getKey(), PersistentDataType.LONG, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The time when the entity was last restocked.
|
||||||
|
*/
|
||||||
|
private long getLastRestock() {
|
||||||
|
if (dataContainer.has(Keyring.VillagerOptimizer.LAST_RESTOCK_SYSTIME_MILLIS.getKey(), PersistentDataType.LONG)) {
|
||||||
|
return dataContainer.get(Keyring.VillagerOptimizer.LAST_RESTOCK_SYSTIME_MILLIS.getKey(), PersistentDataType.LONG);
|
||||||
}
|
}
|
||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveRestockTime() {
|
public long getRestockCooldownMillis(long cooldown_millis) {
|
||||||
dataContainer.set(Keyring.VillagerOptimizer.LAST_RESTOCK_WORLD_FULLTIME.getKey(), PersistentDataType.LONG, villager.getWorld().getFullTime());
|
if (dataContainer.has(Keyring.VillagerOptimizer.LAST_RESTOCK_SYSTIME_MILLIS.getKey(), PersistentDataType.LONG))
|
||||||
|
return System.currentTimeMillis() - (dataContainer.get(Keyring.VillagerOptimizer.LAST_RESTOCK_SYSTIME_MILLIS.getKey(), PersistentDataType.LONG) + cooldown_millis);
|
||||||
|
return cooldown_millis;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -1,61 +1,54 @@
|
|||||||
package me.xginko.villageroptimizer.wrapper;
|
package me.xginko.villageroptimizer.wrapper;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Keyring;
|
import me.xginko.villageroptimizer.enums.Keyring;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public abstract class PDCWrapper {
|
public interface VillagerDataHandler {
|
||||||
|
|
||||||
public final Villager villager;
|
static VillagerDataHandler[] forVillager(Villager villager) {
|
||||||
public final PersistentDataContainer dataContainer;
|
|
||||||
|
|
||||||
public PDCWrapper(Villager villager) {
|
|
||||||
this.villager = villager;
|
|
||||||
this.dataContainer = villager.getPersistentDataContainer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PDCWrapper[] forVillager(Villager villager) {
|
|
||||||
if (VillagerOptimizer.config().support_other_plugins) {
|
if (VillagerOptimizer.config().support_other_plugins) {
|
||||||
return new PDCWrapper[]{new PDCWrapperVO(villager), new PDCWrapperAVL(villager)};
|
return new VillagerDataHandler[]{
|
||||||
|
new MainVillagerDataHandlerImpl(villager),
|
||||||
|
new AVLVillagerDataHandlerImpl(villager)
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return new PDCWrapper[]{new PDCWrapperVO(villager)};
|
return new VillagerDataHandler[]{ new MainVillagerDataHandlerImpl(villager) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The namespace of the handler
|
* @return The namespace of the handler
|
||||||
*/
|
*/
|
||||||
public abstract Keyring.Space getSpace();
|
Keyring.Space getSpace();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if the villager is optimized by plugin, otherwise false.
|
* @return True if the villager is optimized by plugin, otherwise false.
|
||||||
*/
|
*/
|
||||||
public abstract boolean isOptimized();
|
boolean isOptimized();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param cooldown_millis The configured cooldown in millis until the next optimization is allowed to occur.
|
* @param cooldown_millis The configured cooldown in millis until the next optimization is allowed to occur.
|
||||||
* @return True if villager can be optimized again, otherwise false.
|
* @return True if villager can be optimized again, otherwise false.
|
||||||
*/
|
*/
|
||||||
public abstract boolean canOptimize(long cooldown_millis);
|
boolean canOptimize(long cooldown_millis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param type OptimizationType the villager should be set to.
|
* @param type OptimizationType the villager should be set to.
|
||||||
*/
|
*/
|
||||||
public abstract void setOptimizationType(OptimizationType type);
|
void setOptimizationType(OptimizationType type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The current OptimizationType of the villager.
|
* @return The current OptimizationType of the villager.
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull OptimizationType getOptimizationType();
|
||||||
public abstract OptimizationType getOptimizationType();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the system time when the villager was last optimized.
|
* Saves the system time when the villager was last optimized.
|
||||||
*/
|
*/
|
||||||
public abstract void saveOptimizeTime();
|
void saveOptimizeTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For convenience so the remaining millis since the last stored optimize time
|
* For convenience so the remaining millis since the last stored optimize time
|
||||||
@ -65,30 +58,42 @@ public abstract class PDCWrapper {
|
|||||||
* @param cooldown_millis The configured cooldown in milliseconds you want to check against.
|
* @param cooldown_millis The configured cooldown in milliseconds you want to check against.
|
||||||
* @return The time left in millis until the villager can be optimized again.
|
* @return The time left in millis until the villager can be optimized again.
|
||||||
*/
|
*/
|
||||||
public abstract long getOptimizeCooldownMillis(long cooldown_millis);
|
long getOptimizeCooldownMillis(long cooldown_millis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the time of the day in ticks when the entity was last restocked.
|
* For convenience so the remaining millis since the last stored restock time
|
||||||
* This value is affected by /time set
|
* can be easily calculated.
|
||||||
* @return The time of the minecraft day (in ticks) when the villager was last restocked
|
*
|
||||||
|
* @param cooldown_millis The configured cooldown in milliseconds you want to check against.
|
||||||
|
* @return True if the villager has been loaded long enough.
|
||||||
*/
|
*/
|
||||||
public abstract long getLastRestockFullTime();
|
boolean canRestock(long cooldown_millis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the time of when the entity was last restocked.
|
* Saves the time of when the entity was last restocked.
|
||||||
*/
|
*/
|
||||||
public abstract void saveRestockTime();
|
void saveRestockTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For convenience so the remaining millis since the last stored restock time
|
||||||
|
* can be easily calculated.
|
||||||
|
* This enables new configured cooldowns to instantly apply instead of them being persistent.
|
||||||
|
*
|
||||||
|
* @param cooldown_millis The configured cooldown in milliseconds you want to check against.
|
||||||
|
* @return The time left in millis until the villager can be restocked again.
|
||||||
|
*/
|
||||||
|
long getRestockCooldownMillis(long cooldown_millis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param cooldown_millis The configured cooldown in milliseconds you want to check against.
|
* @param cooldown_millis The configured cooldown in milliseconds you want to check against.
|
||||||
* @return Whether the villager can be leveled up or not with the checked milliseconds
|
* @return Whether the villager can be leveled up or not with the checked milliseconds
|
||||||
*/
|
*/
|
||||||
public abstract boolean canLevelUp(long cooldown_millis);
|
boolean canLevelUp(long cooldown_millis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the time of the in-game world when the entity was last leveled up.
|
* Saves the time of the in-game world when the entity was last leveled up.
|
||||||
*/
|
*/
|
||||||
public abstract void saveLastLevelUp();
|
void saveLastLevelUp();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Here for convenience so the remaining millis since the last stored level-up time
|
* Here for convenience so the remaining millis since the last stored level-up time
|
||||||
@ -96,5 +101,5 @@ public abstract class PDCWrapper {
|
|||||||
*
|
*
|
||||||
* @return The time of the in-game world when the entity was last leveled up.
|
* @return The time of the in-game world when the entity was last leveled up.
|
||||||
*/
|
*/
|
||||||
public abstract long getLevelCooldownMillis(long cooldown_millis);
|
long getLevelCooldownMillis(long cooldown_millis);
|
||||||
}
|
}
|
@ -1,55 +1,40 @@
|
|||||||
package me.xginko.villageroptimizer.wrapper;
|
package me.xginko.villageroptimizer.wrapper;
|
||||||
|
|
||||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
import me.xginko.villageroptimizer.enums.Keyring;
|
||||||
import me.xginko.villageroptimizer.struct.enums.Keyring;
|
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||||
import me.xginko.villageroptimizer.struct.enums.OptimizationType;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.entity.Villager;
|
import org.bukkit.entity.Villager;
|
||||||
import org.bukkit.entity.memory.MemoryKey;
|
import org.bukkit.entity.memory.MemoryKey;
|
||||||
import org.bukkit.event.entity.VillagerReplenishTradeEvent;
|
|
||||||
import org.bukkit.inventory.MerchantRecipe;
|
import org.bukkit.inventory.MerchantRecipe;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class WrappedVillager extends PDCWrapper {
|
public class WrappedVillager implements VillagerDataHandler {
|
||||||
|
|
||||||
private final @NotNull PDCWrapper[] pdcWrappers;
|
private final @NotNull Villager villager;
|
||||||
|
private final @NotNull VillagerDataHandler[] dataHandlers;
|
||||||
|
|
||||||
public WrappedVillager(@NotNull Villager villager) {
|
public WrappedVillager(@NotNull Villager villager) {
|
||||||
super(villager);
|
this.villager = villager;
|
||||||
this.pdcWrappers = PDCWrapper.forVillager(villager);
|
this.dataHandlers = VillagerDataHandler.forVillager(villager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a number between 0 and 24000
|
* @return The villager inside the wrapper.
|
||||||
* is affected by /time set
|
|
||||||
*/
|
*/
|
||||||
public long currentDayTimeTicks() {
|
public @NotNull Villager villager() {
|
||||||
return villager.getWorld().getTime();
|
return villager;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the tick time of the world
|
|
||||||
* is affected by /time set
|
|
||||||
*/
|
|
||||||
public long currentFullTimeTicks() {
|
|
||||||
return villager.getWorld().getFullTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restock all trading recipes.
|
* Restock all trading recipes.
|
||||||
*/
|
*/
|
||||||
public void restock() {
|
public void restock() {
|
||||||
VillagerOptimizer.scheduling().entitySpecificScheduler(villager).run(() -> {
|
for (MerchantRecipe recipe : villager.getRecipes()) {
|
||||||
for (MerchantRecipe merchantRecipe : villager.getRecipes()) {
|
recipe.setUses(0);
|
||||||
VillagerReplenishTradeEvent restockRecipeEvent = new VillagerReplenishTradeEvent(villager, merchantRecipe);
|
|
||||||
if (restockRecipeEvent.callEvent()) {
|
|
||||||
restockRecipeEvent.getRecipe().setUses(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The level between 1-5 calculated from the villagers experience.
|
* @return The level between 1-5 calculated from the villagers experience.
|
||||||
@ -65,7 +50,7 @@ public class WrappedVillager extends PDCWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the villager can lose its acquired profession by having its workstation destroyed.
|
* @return true if the villager can loose his acquired profession by having their workstation destroyed.
|
||||||
*/
|
*/
|
||||||
public boolean canLooseProfession() {
|
public boolean canLooseProfession() {
|
||||||
// A villager with a level of 1 and no trading experience is liable to lose its profession.
|
// A villager with a level of 1 and no trading experience is liable to lose its profession.
|
||||||
@ -91,8 +76,8 @@ public class WrappedVillager extends PDCWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOptimized() {
|
public boolean isOptimized() {
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
if (pdcWrapper.isOptimized()) {
|
if (handler.isOptimized()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,8 +86,8 @@ public class WrappedVillager extends PDCWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canOptimize(long cooldown_millis) {
|
public boolean canOptimize(long cooldown_millis) {
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
if (!pdcWrapper.canOptimize(cooldown_millis)) {
|
if (!handler.canOptimize(cooldown_millis)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,18 +96,18 @@ public class WrappedVillager extends PDCWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOptimizationType(OptimizationType type) {
|
public void setOptimizationType(OptimizationType type) {
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
pdcWrapper.setOptimizationType(type);
|
handler.setOptimizationType(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull OptimizationType getOptimizationType() {
|
public @NotNull OptimizationType getOptimizationType() {
|
||||||
OptimizationType result = OptimizationType.NONE;
|
OptimizationType result = OptimizationType.NONE;
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
OptimizationType type = pdcWrapper.getOptimizationType();
|
OptimizationType type = handler.getOptimizationType();
|
||||||
if (type != OptimizationType.NONE) {
|
if (type != OptimizationType.NONE) {
|
||||||
if (pdcWrapper.getSpace() == Keyring.Space.VillagerOptimizer) {
|
if (handler.getSpace() == Keyring.Space.VillagerOptimizer) {
|
||||||
return type;
|
return type;
|
||||||
} else {
|
} else {
|
||||||
result = type;
|
result = type;
|
||||||
@ -134,40 +119,50 @@ public class WrappedVillager extends PDCWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveOptimizeTime() {
|
public void saveOptimizeTime() {
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
pdcWrapper.saveOptimizeTime();
|
handler.saveOptimizeTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getOptimizeCooldownMillis(long cooldown_millis) {
|
public long getOptimizeCooldownMillis(long cooldown_millis) {
|
||||||
long cooldown = 0L;
|
long cooldown = 0L;
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
cooldown = Math.max(cooldown, pdcWrapper.getOptimizeCooldownMillis(cooldown_millis));
|
cooldown = Math.max(cooldown, handler.getOptimizeCooldownMillis(cooldown_millis));
|
||||||
}
|
}
|
||||||
return cooldown;
|
return cooldown;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLastRestockFullTime() {
|
public boolean canRestock(long cooldown_millis) {
|
||||||
long cooldown = 0L;
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
if (!handler.canRestock(cooldown_millis)) {
|
||||||
cooldown = Math.max(cooldown, pdcWrapper.getLastRestockFullTime());
|
return false;
|
||||||
}
|
}
|
||||||
return cooldown;
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveRestockTime() {
|
public void saveRestockTime() {
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
pdcWrapper.saveRestockTime();
|
handler.saveRestockTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRestockCooldownMillis(long cooldown_millis) {
|
||||||
|
long cooldown = cooldown_millis;
|
||||||
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
|
cooldown = Math.max(cooldown, handler.getRestockCooldownMillis(cooldown_millis));
|
||||||
|
}
|
||||||
|
return cooldown;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canLevelUp(long cooldown_millis) {
|
public boolean canLevelUp(long cooldown_millis) {
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
if (!pdcWrapper.canLevelUp(cooldown_millis)) {
|
if (!handler.canLevelUp(cooldown_millis)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,16 +171,16 @@ public class WrappedVillager extends PDCWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveLastLevelUp() {
|
public void saveLastLevelUp() {
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
pdcWrapper.saveLastLevelUp();
|
handler.saveLastLevelUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLevelCooldownMillis(long cooldown_millis) {
|
public long getLevelCooldownMillis(long cooldown_millis) {
|
||||||
long cooldown = cooldown_millis;
|
long cooldown = cooldown_millis;
|
||||||
for (PDCWrapper pdcWrapper : pdcWrappers) {
|
for (VillagerDataHandler handler : dataHandlers) {
|
||||||
cooldown = Math.max(cooldown, pdcWrapper.getLevelCooldownMillis(cooldown_millis));
|
cooldown = Math.max(cooldown, handler.getLevelCooldownMillis(cooldown_millis));
|
||||||
}
|
}
|
||||||
return cooldown;
|
return cooldown;
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
me.xginko.villageroptimizer.logging.ComponentLoggerProviderImpl
|
me.xginko.villageroptimizer.utils.ComponentLoggerProviderImpl
|
@ -5,8 +5,6 @@ authors: [ xGinko ]
|
|||||||
description: ${project.description}
|
description: ${project.description}
|
||||||
website: ${project.url}
|
website: ${project.url}
|
||||||
api-version: '1.16'
|
api-version: '1.16'
|
||||||
softdepend:
|
|
||||||
- AntiVillagerLag
|
|
||||||
folia-supported: true
|
folia-supported: true
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user