only change optimization state once no longer trading

optimize plugin logging and scheduling
This commit is contained in:
xGinko 2024-01-30 14:13:25 +01:00
parent 73eef0b479
commit 63744345e2
11 changed files with 81 additions and 75 deletions

View File

@ -12,6 +12,13 @@ There are 4 methods to do so:
It aims to be highly customizable and performant. Offering a multilang system, which displays messages based on the player client's language setting as well as an optimize- and unoptimize event, so you may extend the plugin with your own custom solutions.
### Commands:
| Command | Aliases | Description |
|:---------------------------------------------:|:-------------------:|:------------------------------------------:|
| /villageroptimizer [reload, version, disable] | voptimizer, vo | VillagerOptimizer admin commands |
| /optimizevillagers <blockradius> | noai, optvils | Optmize villagers in a radius around you |
| /unoptimizevillagers <blockradius> | noaiundo, unoptvils | Unoptmize villagers in a radius around you |
Other features:
- Prevent trading with unoptimized villagers to encourage players to optimize them
- Smart villager chunk limit with configurable max numbers for optimized and unoptimized villagers and a villager profession based priorisation system (you can configure what kind of villagers should be deleted first, like for example nitwits or jobless villagers.)

View File

@ -11,10 +11,9 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
import org.bstats.bukkit.Metrics;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
@ -23,7 +22,6 @@ import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
import java.util.jar.JarFile;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ -37,49 +35,47 @@ public final class VillagerOptimizer extends JavaPlugin {
private static FoliaLib foliaLib;
private static HashMap<String, LanguageCache> languageCacheMap;
private static Config config;
private static ConsoleCommandSender console;
private static Logger logger;
private static ComponentLogger logger;
@Override
public void onEnable() {
instance = this;
logger = getLogger();
console = getServer().getConsoleSender();
logger = getComponentLogger();
foliaLib = new FoliaLib(this);
console.sendMessage(Component.text("╭────────────────────────────────────────────────────────────╮").style(plugin_style));
console.sendMessage(Component.text("│ │").style(plugin_style));
console.sendMessage(Component.text("│ │").style(plugin_style));
console.sendMessage(Component.text("│ _ __ _ __ __ │").style(plugin_style));
console.sendMessage(Component.text("│ | | / /(_)/ // /___ _ ___ _ ___ ____ │").style(plugin_style));
console.sendMessage(Component.text("│ | |/ // // // // _ `// _ `// -_)/ __/ │").style(plugin_style));
console.sendMessage(Component.text("│ |___//_//_//_/ \\_,_/ \\_, / \\__//_/ │").style(plugin_style));
console.sendMessage(Component.text("│ ____ __ _ /___/_ │").style(plugin_style));
console.sendMessage(Component.text("│ / __ \\ ___ / /_ (_)__ _ (_)___ ___ ____ │").style(plugin_style));
console.sendMessage(Component.text("│ / /_/ // _ \\/ __// // ' \\ / //_ // -_)/ __/ │").style(plugin_style));
console.sendMessage(Component.text("\\____// .__/\\__//_//_/_/_//_/ /__/\\__//_/ │").style(plugin_style));
console.sendMessage(Component.text("│ /_/ by xGinko │").style(plugin_style));
console.sendMessage(Component.text("│ │").style(plugin_style));
console.sendMessage(Component.text("│ │").style(plugin_style));
console.sendMessage(Component.text("")
logger.info(Component.text("╭────────────────────────────────────────────────────────────╮").style(plugin_style));
logger.info(Component.text("│ │").style(plugin_style));
logger.info(Component.text("│ │").style(plugin_style));
logger.info(Component.text("│ _ __ _ __ __ │").style(plugin_style));
logger.info(Component.text("│ | | / /(_)/ // /___ _ ___ _ ___ ____ │").style(plugin_style));
logger.info(Component.text("│ | |/ // // // // _ `// _ `// -_)/ __/ │").style(plugin_style));
logger.info(Component.text("│ |___//_//_//_/ \\_,_/ \\_, / \\__//_/ │").style(plugin_style));
logger.info(Component.text("│ ____ __ _ /___/_ │").style(plugin_style));
logger.info(Component.text("│ / __ \\ ___ / /_ (_)__ _ (_)___ ___ ____ │").style(plugin_style));
logger.info(Component.text("│ / /_/ // _ \\/ __// // ' \\ / //_ // -_)/ __/ │").style(plugin_style));
logger.info(Component.text("\\____// .__/\\__//_//_/_/_//_/ /__/\\__//_/ │").style(plugin_style));
logger.info(Component.text("│ /_/ by xGinko │").style(plugin_style));
logger.info(Component.text("│ │").style(plugin_style));
logger.info(Component.text("│ │").style(plugin_style));
logger.info(Component.text("")
.style(plugin_style).append(Component.text("https://github.com/xGinko/VillagerOptimizer")
.color(NamedTextColor.GRAY)).append(Component.text("").style(plugin_style)));
console.sendMessage(Component.text("│ │").style(plugin_style));
console.sendMessage(Component.text("│ │").style(plugin_style));
console.sendMessage(Component.text("")
logger.info(Component.text("│ │").style(plugin_style));
logger.info(Component.text("│ │").style(plugin_style));
logger.info(Component.text("")
.style(plugin_style).append(Component.text(" ➤ Loading Translations...").style(plugin_style))
.append(Component.text("").style(plugin_style)));
reloadLang(true);
console.sendMessage(Component.text("")
logger.info(Component.text("")
.style(plugin_style).append(Component.text(" ➤ Loading Config...").style(plugin_style))
.append(Component.text("").style(plugin_style)));
reloadConfiguration();
console.sendMessage(Component.text("")
logger.info(Component.text("")
.style(plugin_style).append(Component.text(" ✓ Done.").color(NamedTextColor.WHITE).decorate(TextDecoration.BOLD))
.append(Component.text("").style(plugin_style)));
console.sendMessage(Component.text("│ │").style(plugin_style));
console.sendMessage(Component.text("│ │").style(plugin_style));
console.sendMessage(Component.text("╰────────────────────────────────────────────────────────────╯").style(plugin_style));
logger.info(Component.text("│ │").style(plugin_style));
logger.info(Component.text("│ │").style(plugin_style));
logger.info(Component.text("╰────────────────────────────────────────────────────────────╯").style(plugin_style));
new Metrics(this, 19954);
}
@ -96,13 +92,7 @@ public final class VillagerOptimizer extends JavaPlugin {
public static FoliaLib getFoliaLib() {
return foliaLib;
}
public static ServerImplementation getScheduler() {
return foliaLib.getImpl();
}
public static ConsoleCommandSender getConsole() {
return console;
}
public static Logger getLog() {
public static ComponentLogger getLog() {
return logger;
}
public static LanguageCache getLang(Locale locale) {
@ -129,7 +119,7 @@ public final class VillagerOptimizer extends JavaPlugin {
VillagerOptimizerModule.reloadModules();
config.saveConfig();
} catch (Exception e) {
logger.severe("Error loading config! - " + e.getLocalizedMessage());
logger.error("Error loading config! - " + e.getLocalizedMessage());
e.printStackTrace();
}
}
@ -141,7 +131,7 @@ public final class VillagerOptimizer extends JavaPlugin {
Files.createDirectories(langDirectory.toPath());
for (String fileName : getDefaultLanguageFiles()) {
final String localeString = fileName.substring(fileName.lastIndexOf(File.separator) + 1, fileName.lastIndexOf('.'));
if (startup) console.sendMessage(
if (startup) logger.info(
Component.text("").style(plugin_style)
.append(Component.text(" "+localeString).color(NamedTextColor.WHITE).decorate(TextDecoration.BOLD))
.append(Component.text("").style(plugin_style)));
@ -154,7 +144,7 @@ public final class VillagerOptimizer extends JavaPlugin {
if (langMatcher.find()) {
String localeString = langMatcher.group(1).toLowerCase();
if (!languageCacheMap.containsKey(localeString)) { // make sure it wasn't a default file that we already loaded
if (startup) console.sendMessage(
if (startup) logger.info(
Component.text("").style(plugin_style)
.append(Component.text(" "+localeString).color(NamedTextColor.WHITE).decorate(TextDecoration.BOLD))
.append(Component.text("").style(plugin_style)));
@ -164,11 +154,11 @@ public final class VillagerOptimizer extends JavaPlugin {
}
}
} catch (Exception e) {
if (startup) console.sendMessage(
if (startup) logger.error(
Component.text("").style(plugin_style)
.append(Component.text("LANG ERROR").color(NamedTextColor.RED).decorate(TextDecoration.BOLD))
.append(Component.text("").style(plugin_style)));
else logger.severe("Error loading language files! Language files will not reload to avoid errors, make sure to correct this before restarting the server!");
else logger.error("Error loading language files! Language files will not reload to avoid errors, make sure to correct this before restarting the server!");
e.printStackTrace();
}
}
@ -180,7 +170,7 @@ public final class VillagerOptimizer extends JavaPlugin {
.filter(name -> name.startsWith("lang" + File.separator) && name.endsWith(".yml"))
.collect(Collectors.toSet());
} catch (IOException e) {
logger.severe("Failed getting default lang files! - "+e.getLocalizedMessage());
logger.error("Failed getting default lang files! - "+e.getLocalizedMessage());
return Collections.emptySet();
}
}

View File

@ -5,11 +5,14 @@ import me.xginko.villageroptimizer.enums.OptimizationType;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.entity.Villager;
import org.bukkit.inventory.MerchantRecipe;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.TimeUnit;
public final class WrappedVillager {
private final @NotNull Villager villager;
@ -81,18 +84,23 @@ public final class WrappedVillager {
* @param type OptimizationType the villager should be set to.
*/
public void setOptimization(OptimizationType type) {
VillagerOptimizer.getFoliaLib().getImpl().runAtEntityTimer(villager, setOptimization -> {
// Keep repeating task until villager is no longer trading with a player
if (villager.isTrading()) return;
if (type.equals(OptimizationType.NONE) && isOptimized()) {
if (!parseOther || isOptimized(Keys.Namespaces.VillagerOptimizer)) {
if (!parseOther || isOptimized(Keys.Namespaces.VillagerOptimizer))
dataContainer.remove(Keys.Own.OPTIMIZATION_TYPE.key());
}
VillagerOptimizer.getScheduler().runAtEntity(villager, enableAI -> {
villager.setAware(true);
villager.setAI(true);
});
villager.setAI(true); // Done for stability so villager is guaranteed to wake up
} else {
dataContainer.set(Keys.Own.OPTIMIZATION_TYPE.key(), PersistentDataType.STRING, type.name());
VillagerOptimizer.getScheduler().runAtEntity(villager, disableAI -> villager.setAware(false));
villager.setAware(false);
}
// End repeating task once logic is finished
setOptimization.cancel();
}, 0L, 1L, TimeUnit.SECONDS);
}
/**
@ -190,7 +198,9 @@ public final class WrappedVillager {
* Restock all trading recipes.
*/
public void restock() {
villager.getRecipes().forEach(recipe -> recipe.setUses(0));
for (MerchantRecipe recipe : villager.getRecipes()) {
recipe.setUses(0);
}
}
/**

View File

@ -29,7 +29,7 @@ public class ReloadSubCmd extends SubCommand {
public void perform(CommandSender sender, String[] args) {
if (sender.hasPermission(Commands.RELOAD.get())) {
sender.sendMessage(Component.text("Reloading VillagerOptimizer...").color(NamedTextColor.WHITE));
VillagerOptimizer.getScheduler().runNextTick(reload -> { // Reload in sync with the server
VillagerOptimizer.getFoliaLib().getImpl().runNextTick(reload -> { // Reload in sync with the server
VillagerOptimizer.getInstance().reloadPlugin();
sender.sendMessage(Component.text("Reload complete.").color(NamedTextColor.GREEN));
});

View File

@ -19,7 +19,7 @@ public class Config {
// Create plugin folder first if it does not exist yet
File pluginFolder = VillagerOptimizer.getInstance().getDataFolder();
if (!pluginFolder.exists() && !pluginFolder.mkdir())
VillagerOptimizer.getLog().severe("Failed to create plugin directory.");
VillagerOptimizer.getLog().error("Failed to create plugin directory.");
// Load config.yml with ConfigMaster
this.config = ConfigFile.loadConfig(new File(pluginFolder, "config.yml"));
@ -42,7 +42,7 @@ public class Config {
try {
this.config.save();
} catch (Exception e) {
VillagerOptimizer.getLog().severe("Failed to save config file! - " + e.getLocalizedMessage());
VillagerOptimizer.getLog().error("Failed to save config file! - " + e.getLocalizedMessage());
}
}

View File

@ -27,7 +27,7 @@ public class LanguageCache {
// Check if the lang folder has already been created
File parent = langYML.getParentFile();
if (!parent.exists() && !parent.mkdir())
VillagerOptimizer.getLog().severe("Failed to create lang directory.");
VillagerOptimizer.getLog().error("Failed to create lang directory.");
// Check if the file already exists and save the one from the plugins resources folder if it does not
if (!langYML.exists())
plugin.saveResource("lang" + File.separator + locale + ".yml", false);
@ -83,7 +83,7 @@ public class LanguageCache {
try {
this.lang.save();
} catch (Exception e) {
VillagerOptimizer.getLog().severe("Failed to save language file: "+ langYML.getName() +" - " + e.getLocalizedMessage());
VillagerOptimizer.getLog().error("Failed to save language file: "+ langYML.getName() +" - " + e.getLocalizedMessage());
}
}

View File

@ -55,9 +55,9 @@ public class Keys {
}
public enum AntiVillagerLag {
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_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_BLOCK("disabledByBlock"), // Returns STRING -> key().toString()
OPTIMIZED_WORKSTATION("disabledByWorkstation"); // Returns STRING -> key().toString()

View File

@ -20,10 +20,9 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.jetbrains.annotations.NotNull;
import org.slf4j.event.Level;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Stream;
public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
@ -38,7 +37,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
protected VillagerChunkLimit() {
shouldEnable();
this.scheduler = VillagerOptimizer.getScheduler();
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
this.villagerCache = VillagerOptimizer.getCache();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment("villager-chunk-limit.enable", """
@ -62,7 +61,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
try {
return Villager.Profession.valueOf(configuredProfession);
} catch (IllegalArgumentException e) {
LogUtil.moduleLog(Level.WARNING, "villager-chunk-limit.unoptimized",
LogUtil.moduleLog(Level.WARN, "villager-chunk-limit.unoptimized",
"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;
@ -77,7 +76,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
try {
return Villager.Profession.valueOf(configuredProfession);
} catch (IllegalArgumentException e) {
LogUtil.moduleLog(Level.WARNING, "villager-chunk-limit.optimized",
LogUtil.moduleLog(Level.WARN, "villager-chunk-limit.optimized",
"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;

View File

@ -68,11 +68,11 @@ public class LevelOptimizedProfession implements VillagerOptimizerModule, Listen
if (wVillager.canLevelUp(cooldown_millis)) {
if (wVillager.calculateLevel() > villager.getVillagerLevel()) {
VillagerOptimizer.getScheduler().runAtEntity(villager, enableAI -> {
VillagerOptimizer.getFoliaLib().getImpl().runAtEntity(villager, enableAI -> {
villager.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 120, 120, false, false));
villager.setAware(true);
});
VillagerOptimizer.getScheduler().runAtEntityLater(villager, disableAI -> {
VillagerOptimizer.getFoliaLib().getImpl().runAtEntityLater(villager, disableAI -> {
villager.setAware(false);
wVillager.saveLastLevelUp();
}, 5, TimeUnit.SECONDS);

View File

@ -23,7 +23,7 @@ public class RenameOptimizedVillagers implements VillagerOptimizerModule, Listen
public RenameOptimizedVillagers() {
shouldEnable();
this.scheduler = VillagerOptimizer.getScheduler();
this.scheduler = VillagerOptimizer.getFoliaLib().getImpl();
Config config = VillagerOptimizer.getConfiguration();
config.master().addComment("gameplay.rename-optimized-villagers.enable", """
Will change a villager's name to the name configured below when they are optimized.\s

View File

@ -1,26 +1,26 @@
package me.xginko.villageroptimizer.utils;
import me.xginko.villageroptimizer.VillagerOptimizer;
import org.slf4j.event.Level;
import java.util.logging.Level;
public class LogUtil {
public static void moduleLog(Level logLevel, String path, String logMessage) {
VillagerOptimizer.getLog().log(logLevel, "(" + path + ") " + logMessage);
VillagerOptimizer.getLog().atLevel(logLevel).log("(" + path + ") " + logMessage);
}
public static void materialNotRecognized(String path, String material) {
moduleLog(Level.WARNING, path, "Material '" + material + "' not recognized. Please use correct Material enums from: " +
moduleLog(Level.WARN, path, "Material '" + material + "' not recognized. Please use correct Material enums from: " +
"https://jd.papermc.io/paper/1.20/org/bukkit/Material.html");
}
public static void damageCauseNotRecognized(String path, String cause) {
moduleLog(Level.WARNING, path, "DamageCause '" + cause + "' not recognized. Please use correct DamageCause enums from: " +
moduleLog(Level.WARN, path, "DamageCause '" + cause + "' not recognized. Please use correct DamageCause enums from: " +
"https://jd.papermc.io/paper/1.20/org/bukkit/event/entity/EntityDamageEvent.DamageCause.html");
}
public static void entityTypeNotRecognized(String path, String entityType) {
moduleLog(Level.WARNING, path, "EntityType '" + entityType + "' not recognized. Please use correct Spigot EntityType enums for your Minecraft version!");
moduleLog(Level.WARN, path, "EntityType '" + entityType + "' not recognized. Please use correct Spigot EntityType enums for your Minecraft version!");
}
}