finalize workstation optimization

This commit is contained in:
xGinko 2023-09-26 22:48:29 +02:00
parent bd884e307e
commit fe943f6666
10 changed files with 99 additions and 93 deletions

View File

@ -4,7 +4,7 @@ import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.utils.LogUtils;
import me.xginko.villageroptimizer.utils.LogUtil;
import org.bukkit.Chunk;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
@ -66,7 +66,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
Villager.Profession profession = Villager.Profession.valueOf(configuredProfession);
this.removalPriority.add(profession);
} catch (IllegalArgumentException e) {
LogUtils.moduleLog(Level.WARNING, "villager-chunk-limit",
LogUtil.moduleLog(Level.WARNING, "villager-chunk-limit",
"Villager profession '"+configuredProfession+"' not recognized. Make sure you're using the correct profession enums.");
}
});
@ -130,7 +130,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
for (int i = 0; i < amount_over_the_limit; i++) {
Villager villager = villagers_in_chunk.get(i);
villager.remove();
if (logIsEnabled) LogUtils.moduleLog(Level.INFO, "villager-chunk-limit",
if (logIsEnabled) LogUtil.moduleLog(Level.INFO, "villager-chunk-limit",
"Removed villager of profession type '"+villager.getProfession()+"' at "+villager.getLocation());
}
}

View File

@ -5,7 +5,7 @@ import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.WrappedVillager;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.CommonUtils;
import me.xginko.villageroptimizer.utils.CommonUtil;
import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
@ -79,7 +79,7 @@ public class LevelVillagers implements VillagerOptimizerModule, Listener {
} else {
if (shouldNotify) {
Player player = (Player) event.getPlayer();
final String timeLeft = CommonUtils.formatTime(wVillager.getLevelCooldownMillis(cooldown));
final String timeLeft = CommonUtil.formatTime(wVillager.getLevelCooldownMillis(cooldown));
VillagerOptimizer.getLang(player.locale()).villager_leveling_up.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%time%").replacement(timeLeft).build())
));

View File

@ -6,7 +6,7 @@ import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.WrappedVillager;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.CommonUtils;
import me.xginko.villageroptimizer.utils.CommonUtil;
import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
@ -69,7 +69,7 @@ public class RestockTrades implements VillagerOptimizerModule, Listener {
wVillager.restock();
wVillager.saveRestockTime();
if (notifyPlayer) {
final String timeLeft = CommonUtils.formatTime(wVillager.getRestockCooldownMillis(restock_delay_millis));
final String timeLeft = CommonUtil.formatTime(wVillager.getRestockCooldownMillis(restock_delay_millis));
VillagerOptimizer.getLang(player.locale()).trades_restocked.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%time%").replacement(timeLeft).build()))
);

View File

@ -7,8 +7,8 @@ import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.OptimizationType;
import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.CommonUtils;
import me.xginko.villageroptimizer.utils.LogUtils;
import me.xginko.villageroptimizer.utils.CommonUtil;
import me.xginko.villageroptimizer.utils.LogUtil;
import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.Location;
import org.bukkit.Material;
@ -51,7 +51,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
Material disableBlock = Material.valueOf(configuredMaterial);
this.blocks_that_disable.add(disableBlock);
} catch (IllegalArgumentException e) {
LogUtils.materialNotRecognized("block-optimization", configuredMaterial);
LogUtil.materialNotRecognized("block-optimization", configuredMaterial);
}
});
this.cooldown = config.getInt("optimization-methods.block-optimization.optimize-cooldown-seconds", 600, """
@ -81,7 +81,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
return VillagerOptimizer.getConfiguration().getBoolean("optimization-methods.block-optimization.enable", false);
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onBlockPlace(BlockPlaceEvent event) {
Block placed = event.getBlock();
if (!blocks_that_disable.contains(placed.getType())) return;
@ -119,7 +119,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
final String villagerType = closestOptimizableVillager.villager().getProfession().toString().toLowerCase();
final String placedType = placed.getType().toString().toLowerCase();
VillagerOptimizer.getLang(player.locale()).block_optimize_success.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%villagertype%").replacement(villagerType).build())
.replaceText(TextReplacementConfig.builder().matchLiteral("%vil_profession%").replacement(villagerType).build())
.replaceText(TextReplacementConfig.builder().matchLiteral("%blocktype%").replacement(placedType).build())
));
}
@ -128,14 +128,14 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
} else {
closestOptimizableVillager.villager().shakeHead();
if (shouldNotifyPlayer) {
final String timeLeft = CommonUtils.formatTime(closestOptimizableVillager.getOptimizeCooldownMillis(cooldown));
final String timeLeft = CommonUtil.formatTime(closestOptimizableVillager.getOptimizeCooldownMillis(cooldown));
VillagerOptimizer.getLang(player.locale()).block_on_optimize_cooldown.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%time%").replacement(timeLeft).build())));
}
}
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onBlockBreak(BlockBreakEvent event) {
Block broken = event.getBlock();
if (!blocks_that_disable.contains(broken.getType())) return;
@ -169,11 +169,11 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
final String villagerType = closestOptimizedVillager.villager().getProfession().toString().toLowerCase();
final String brokenType = broken.getType().toString().toLowerCase();
VillagerOptimizer.getLang(player.locale()).block_unoptimize_success.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%villagertype%").replacement(villagerType).build())
.replaceText(TextReplacementConfig.builder().matchLiteral("%vil_profession%").replacement(villagerType).build())
.replaceText(TextReplacementConfig.builder().matchLiteral("%blocktype%").replacement(brokenType).build())
));
}
if (shouldLog)
VillagerOptimizer.getLog().info("Villager unoptimized because no longer standing on optimization block at "+closestOptimizedVillager.villager().getLocation());
VillagerOptimizer.getLog().info("Villager unoptimized because nearby optimization block broken at: "+closestOptimizedVillager.villager().getLocation());
}
}

View File

@ -8,7 +8,7 @@ import me.xginko.villageroptimizer.enums.OptimizationType;
import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.WrappedVillager;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.CommonUtils;
import me.xginko.villageroptimizer.utils.CommonUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextReplacementConfig;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
@ -98,7 +98,7 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener {
event.setCancelled(true);
wVillager.villager().shakeHead();
if (shouldNotifyPlayer) {
final String time = CommonUtils.formatTime(wVillager.getOptimizeCooldownMillis(cooldown));
final String time = CommonUtil.formatTime(wVillager.getOptimizeCooldownMillis(cooldown));
VillagerOptimizer.getLang(player.locale()).nametag_on_optimize_cooldown.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%time%").replacement(time).build())));
}

View File

@ -1,14 +1,14 @@
package me.xginko.villageroptimizer.modules.optimizations;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.VillagerCache;
import me.xginko.villageroptimizer.VillagerOptimizer;
import me.xginko.villageroptimizer.WrappedVillager;
import me.xginko.villageroptimizer.config.Config;
import me.xginko.villageroptimizer.enums.OptimizationType;
import me.xginko.villageroptimizer.enums.Permissions;
import me.xginko.villageroptimizer.WrappedVillager;
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
import me.xginko.villageroptimizer.utils.CommonUtils;
import me.xginko.villageroptimizer.utils.LogUtils;
import me.xginko.villageroptimizer.utils.CommonUtil;
import me.xginko.villageroptimizer.utils.LogUtil;
import net.kyori.adventure.text.TextReplacementConfig;
import org.bukkit.Location;
import org.bukkit.Material;
@ -28,9 +28,6 @@ import java.util.HashSet;
import java.util.List;
public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener {
/*
* TODO: Make placed workstation villager profession related.
* */
private final VillagerCache villagerCache;
private final HashSet<Material> workstations_that_disable = new HashSet<>(14);
@ -54,7 +51,7 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
Material disableBlock = Material.valueOf(configuredMaterial);
this.workstations_that_disable.add(disableBlock);
} catch (IllegalArgumentException e) {
LogUtils.materialNotRecognized("workstation-optimization", configuredMaterial);
LogUtil.materialNotRecognized("workstation-optimization", configuredMaterial);
}
});
this.search_radius = config.getDouble("optimization-methods.workstation-optimization.search-radius-in-blocks", 2.0, """
@ -87,19 +84,22 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onBlockPlace(BlockPlaceEvent event) {
Block placed = event.getBlock();
if (!workstations_that_disable.contains(placed.getType())) return;
final Material placedType = placed.getType();
if (!workstations_that_disable.contains(placedType)) return;
Player player = event.getPlayer();
if (!player.hasPermission(Permissions.Optimize.WORKSTATION.get())) return;
Villager.Profession workstationProfession = getWorkstationProfession(placedType);
if (workstationProfession.equals(Villager.Profession.NONE)) return;
final Location workstationLoc = placed.getLocation();
WrappedVillager closestOptimizableVillager = null;
double closestDistance = Double.MAX_VALUE;
for (Entity entity : workstationLoc.getNearbyEntities(search_radius, search_radius, search_radius)) {
if (!entity.getType().equals(EntityType.VILLAGER)) continue;
Villager villager = (Villager) entity;
final Villager.Profession profession = villager.getProfession();
if (profession.equals(Villager.Profession.NONE) || profession.equals(Villager.Profession.NITWIT)) continue;
if (!villager.getProfession().equals(workstationProfession)) continue;
WrappedVillager wVillager = villagerCache.getOrAdd(villager);
final double distance = entity.getLocation().distance(workstationLoc);
@ -122,16 +122,16 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
final String villagerType = closestOptimizableVillager.villager().getProfession().toString().toLowerCase();
final String workstation = placed.getType().toString().toLowerCase();
VillagerOptimizer.getLang(player.locale()).workstation_optimize_success.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%villagertype%").replacement(villagerType).build())
.replaceText(TextReplacementConfig.builder().matchLiteral("%vil_profession%").replacement(villagerType).build())
.replaceText(TextReplacementConfig.builder().matchLiteral("%workstation%").replacement(workstation).build())
));
}
if (shouldLog)
VillagerOptimizer.getLog().info(event.getPlayer().getName() + " optimized a villager using workstation: '" + placed.getType().toString().toLowerCase() + "'");
VillagerOptimizer.getLog().info(player.getName() + " optimized a villager using workstation: '" + placed.getType().toString().toLowerCase() + "'");
} else {
closestOptimizableVillager.villager().shakeHead();
if (shouldNotifyPlayer) {
final String timeLeft = CommonUtils.formatTime(closestOptimizableVillager.getOptimizeCooldownMillis(cooldown));
final String timeLeft = CommonUtil.formatTime(closestOptimizableVillager.getOptimizeCooldownMillis(cooldown));
VillagerOptimizer.getLang(player.locale()).nametag_on_optimize_cooldown.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%time%").replacement(timeLeft).build())
));
@ -142,9 +142,12 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onBlockBreak(BlockBreakEvent event) {
Block placed = event.getBlock();
if (!workstations_that_disable.contains(placed.getType())) return;
final Material brokenType = placed.getType();
if (!workstations_that_disable.contains(brokenType)) return;
Player player = event.getPlayer();
if (!player.hasPermission(Permissions.Optimize.WORKSTATION.get())) return;
Villager.Profession workstationProfession = getWorkstationProfession(brokenType);
if (workstationProfession.equals(Villager.Profession.NONE)) return;
final Location workstationLoc = placed.getLocation();
WrappedVillager closestOptimizedVillager = null;
@ -153,6 +156,7 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
for (Entity entity : workstationLoc.getNearbyEntities(search_radius, search_radius, search_radius)) {
if (!entity.getType().equals(EntityType.VILLAGER)) continue;
Villager villager = (Villager) entity;
if (!villager.getProfession().equals(workstationProfession)) continue;
WrappedVillager wVillager = villagerCache.getOrAdd(villager);
final double distance = entity.getLocation().distance(workstationLoc);
@ -160,24 +164,44 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
if (distance < closestDistance) {
final OptimizationType type = wVillager.getOptimizationType();
if (type.equals(OptimizationType.WORKSTATION) || type.equals(OptimizationType.COMMAND)) {
closestOptimizedVillager = wVillager;
closestDistance = distance;
}
}
}
if (closestOptimizedVillager != null) {
closestOptimizedVillager.setOptimization(OptimizationType.NONE);
if (shouldNotifyPlayer) {
final String villagerType = closestOptimizedVillager.villager().getProfession().toString().toLowerCase();
final String workstation = placed.getType().toString().toLowerCase();
VillagerOptimizer.getLang(player.locale()).workstation_unoptimize_success.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%villagertype%").replacement(villagerType).build())
.replaceText(TextReplacementConfig.builder().matchLiteral("%workstation%").replacement(workstation).build())
));
}
if (shouldLog)
VillagerOptimizer.getLog().info(event.getPlayer().getName() + " unoptimized a villager by breaking workstation: '" + placed.getType().toString().toLowerCase() + "'");
if (closestOptimizedVillager == null) return;
closestOptimizedVillager.setOptimization(OptimizationType.NONE);
if (shouldNotifyPlayer) {
final String villagerType = closestOptimizedVillager.villager().getProfession().toString().toLowerCase();
final String workstation = placed.getType().toString().toLowerCase();
VillagerOptimizer.getLang(player.locale()).workstation_unoptimize_success.forEach(line -> player.sendMessage(line
.replaceText(TextReplacementConfig.builder().matchLiteral("%vil_profession%").replacement(villagerType).build())
.replaceText(TextReplacementConfig.builder().matchLiteral("%workstation%").replacement(workstation).build())
));
}
if (shouldLog)
VillagerOptimizer.getLog().info(player.getName() + " unoptimized a villager by breaking workstation: '" + placed.getType().toString().toLowerCase() + "'");
}
private Villager.Profession getWorkstationProfession(Material workstation) {
return switch (workstation) {
case BARREL -> Villager.Profession.FISHERMAN;
case CARTOGRAPHY_TABLE -> Villager.Profession.CARTOGRAPHER;
case SMOKER -> Villager.Profession.BUTCHER;
case SMITHING_TABLE -> Villager.Profession.TOOLSMITH;
case GRINDSTONE -> Villager.Profession.WEAPONSMITH;
case BLAST_FURNACE -> Villager.Profession.ARMORER;
case CAULDRON -> Villager.Profession.LEATHERWORKER;
case BREWING_STAND -> Villager.Profession.CLERIC;
case COMPOSTER -> Villager.Profession.FARMER;
case FLETCHING_TABLE -> Villager.Profession.FLETCHER;
case LOOM -> Villager.Profession.SHEPHERD;
case LECTERN -> Villager.Profession.LIBRARIAN;
case STONECUTTER -> Villager.Profession.MASON;
default -> Villager.Profession.NONE;
};
}
}

View File

@ -0,0 +1,26 @@
package me.xginko.villageroptimizer.utils;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
import static java.lang.String.format;
public class CommonUtil {
public static @NotNull String formatTime(final long millis) {
Duration duration = Duration.ofMillis(millis);
final int seconds = duration.toSecondsPart();
final int minutes = duration.toMinutesPart();
final int hours = duration.toHoursPart();
if (hours > 0) {
return format("%02dh %02dm %02ds", hours, minutes, seconds);
} else if (minutes > 0) {
return format("%02dm %02ds", minutes, seconds);
} else {
return format("%02ds", seconds);
}
}
}

View File

@ -1,44 +0,0 @@
package me.xginko.villageroptimizer.utils;
import org.bukkit.Material;
import org.bukkit.entity.Villager;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
import static java.lang.String.format;
public class CommonUtils {
public static @NotNull String formatTime(final long millis) {
Duration duration = Duration.ofMillis(millis);
final int seconds = duration.toSecondsPart();
final int minutes = duration.toMinutesPart();
final int hours = duration.toHoursPart();
if (hours > 0) {
return format("%02dh %02dm %02ds", hours, minutes, seconds);
} else {
return minutes > 0 ? format("%02dm %02ds", minutes, seconds) : format("%02ds", seconds);
}
}
public static @NotNull Villager.Profession getWorkstationProfession(@NotNull final Material workstation) {
return switch (workstation) {
case BARREL -> Villager.Profession.FISHERMAN;
case CARTOGRAPHY_TABLE -> Villager.Profession.CARTOGRAPHER;
case SMOKER -> Villager.Profession.BUTCHER;
case SMITHING_TABLE -> Villager.Profession.TOOLSMITH;
case GRINDSTONE -> Villager.Profession.WEAPONSMITH;
case BLAST_FURNACE -> Villager.Profession.ARMORER;
case CAULDRON -> Villager.Profession.LEATHERWORKER;
case BREWING_STAND -> Villager.Profession.CLERIC;
case COMPOSTER -> Villager.Profession.FARMER;
case FLETCHING_TABLE -> Villager.Profession.FLETCHER;
case LOOM -> Villager.Profession.SHEPHERD;
case LECTERN -> Villager.Profession.LIBRARIAN;
case STONECUTTER -> Villager.Profession.MASON;
default -> Villager.Profession.NONE;
};
}
}

View File

@ -4,7 +4,7 @@ import me.xginko.villageroptimizer.VillagerOptimizer;
import java.util.logging.Level;
public class LogUtils {
public class LogUtil {
public static void moduleLog(Level logLevel, String path, String logMessage) {
VillagerOptimizer.getLog().log(logLevel, "(" + path + ") " + logMessage);

View File

@ -15,14 +15,14 @@ messages:
- "<green>Successfully unoptimized villager by using a nametag."
block:
optimize-success:
- "<green>%villagertype% villager successfully optimized using block %blocktype%."
- "<green>%vil_profession% villager successfully optimized using block %blocktype%."
optimize-on-cooldown:
- "<gray>You need to wait %time% until you can optimize this villager again."
unoptimize-success:
- "<green>Successfully unoptimized %villagertype% villager by removing %blocktype%."
- "<green>Successfully unoptimized %vil_profession% villager by removing %blocktype%."
workstation:
optimize-success:
- "<green>%villagertype% villager successfully optimized using workstation block %blocktype%."
- "<green>%vil_profession% villager successfully optimized using workstation block %blocktype%."
optimize-on-cooldown:
- "<gray>You need to wait %time% until you can optimize this villager again."
unoptimize-success: