Update dependencies and improve configuration management
- Updated LoLib dependency to version 3.0.0 in build.gradle.kts - Added HikariCP and MySQL connector dependencies for improved database handling - Enhanced jar minimization process to exclude JDBC pool and driver - Refactored configuration management by introducing ConfigAccessor and ConfigLoader for better file handling and validation - Removed deprecated GenerationOptions class and integrated its functionality into the new structure - Improved command error handling and added cooldown hints for admin commands
This commit is contained in:
parent
978f739045
commit
3100c53229
86 changed files with 4324 additions and 3248 deletions
|
|
@ -1,9 +1,5 @@
|
|||
package dev.loki.loparkour.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.config.Config;
|
||||
|
|
@ -17,10 +13,10 @@ import dev.loki.loparkour.player.data.PreviousData;
|
|||
import dev.loki.loparkour.session.Session;
|
||||
import dev.loki.loparkour.storage.Storage;
|
||||
import dev.loki.loparkour.world.Divider;
|
||||
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
|
@ -38,6 +34,9 @@ public class ParkourPlayer extends ParkourUser {
|
|||
|
||||
public static final Map<String, PlayerSettingsManager.OptionContainer> PLAYER_COLUMNS = PlayerSettingsManager.getColumnMappings();
|
||||
|
||||
// Track scored blocks to prevent duplicate scoring
|
||||
private final Set<Block> scoredBlocks = new HashSet<>();
|
||||
|
||||
public @Expose Double schematicDifficulty;
|
||||
public @Expose Integer blockLead;
|
||||
public @Expose Boolean particles;
|
||||
|
|
@ -68,10 +67,6 @@ public class ParkourPlayer extends ParkourUser {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean parseBoolean(String string) {
|
||||
return string == null || string.equals("1") || string.equals("true");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player The player.
|
||||
* @return True when this player is a {@link ParkourPlayer}, false if not.
|
||||
|
|
@ -111,10 +106,27 @@ public class ParkourPlayer extends ParkourUser {
|
|||
}
|
||||
|
||||
session.removePlayers(this);
|
||||
|
||||
// Clear scored blocks to prevent memory leak
|
||||
scoredBlocks.clear();
|
||||
|
||||
save(LoParkour.getPlugin().isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if player has already scored on this block.
|
||||
*/
|
||||
public boolean hasScored(Block block) {
|
||||
return scoredBlocks.contains(block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark block as scored to prevent duplicate scoring.
|
||||
*/
|
||||
public void markScored(Block block) {
|
||||
scoredBlocks.add(block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user's settings. If an item is not included, the setting gets reset.
|
||||
*
|
||||
|
|
@ -140,7 +152,8 @@ public class ParkourPlayer extends ParkourUser {
|
|||
.set("selectedTime", selectedTime.toString())
|
||||
.set("style", style);
|
||||
|
||||
generator.overrideProfile();
|
||||
// Use profileManager instead of calling overrideProfile directly on generator
|
||||
generator.profileManager.overrideProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package dev.loki.loparkour.player;
|
||||
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.api.event.ParkourSpectateEvent;
|
||||
import dev.loki.loparkour.config.Locales;
|
||||
|
|
@ -9,11 +7,11 @@ import dev.loki.loparkour.player.data.PreviousData;
|
|||
import dev.loki.loparkour.session.Session;
|
||||
import dev.loki.loparkour.util.ColorUtil;
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
import dev.lolib.scheduler.ScheduledTask;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Player;
|
||||
import dev.lolib.scheduler.ScheduledTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
|
@ -26,7 +24,7 @@ import java.util.Comparator;
|
|||
*/
|
||||
public class ParkourSpectator extends ParkourUser {
|
||||
|
||||
private final dev.lolib.scheduler.ScheduledTask closestChecker;
|
||||
private final ScheduledTask closestChecker;
|
||||
/**
|
||||
* The closest player.
|
||||
*/
|
||||
|
|
@ -54,7 +52,8 @@ public class ParkourSpectator extends ParkourUser {
|
|||
}
|
||||
}, 1);
|
||||
|
||||
closestChecker = Scheduler.get(LoParkour.getPlugin()).runTimerAsync(() -> {
|
||||
// Use runTimer (sync) instead of runTimerAsync to safely access Bukkit API
|
||||
closestChecker = Scheduler.get(LoParkour.getPlugin()).runTimer(() -> {
|
||||
if (session.getPlayers().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -68,6 +67,7 @@ public class ParkourSpectator extends ParkourUser {
|
|||
/**
|
||||
* Updates the spectator's action bar, scoreboard and checks distance.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Spigot Chat API: action bar via TextComponent
|
||||
public void update() {
|
||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(ColorUtil.color(Locales.getString(player, "play.spectator.action_bar"))));
|
||||
player.setGameMode(GameMode.SPECTATOR);
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public abstract class ParkourUser {
|
|||
public final Instant joined;
|
||||
private ScoreboardManager scoreboardManager;
|
||||
|
||||
@SuppressWarnings("deprecation") // Scoreboard: legacy registerNewObjective(String,String,String)
|
||||
public ParkourUser(@NotNull Player player, @NotNull Session session, @Nullable PreviousData previousData) {
|
||||
this.player = player;
|
||||
this.session = session;
|
||||
|
|
|
|||
|
|
@ -25,18 +25,21 @@ public class PlayerSettingsManager {
|
|||
private static void initializeColumnMappings() {
|
||||
COLUMN_MAPPINGS.put("uuid", new OptionContainer(null, null));
|
||||
COLUMN_MAPPINGS.put("style", new OptionContainer(ParkourOption.STYLES, (p, v) -> p.style = v));
|
||||
COLUMN_MAPPINGS.put("blockLead", new OptionContainer(ParkourOption.LEADS, (p, v) -> p.blockLead = Integer.parseInt(v)));
|
||||
COLUMN_MAPPINGS.put("blockLead", new OptionContainer(ParkourOption.LEADS, (p, v) ->
|
||||
p.blockLead = parseIntSafe(v, defaultBlockLead())));
|
||||
COLUMN_MAPPINGS.put("useParticles", new OptionContainer(ParkourOption.PARTICLES, (p, v) -> p.particles = parseBoolean(v)));
|
||||
COLUMN_MAPPINGS.put("useSpecial", new OptionContainer(ParkourOption.SPECIAL_BLOCKS, (p, v) -> p.useSpecialBlocks = parseBoolean(v)));
|
||||
COLUMN_MAPPINGS.put("showFallMsg", new OptionContainer(ParkourOption.FALL_MESSAGE, (p, v) -> p.showFallMessage = parseBoolean(v)));
|
||||
COLUMN_MAPPINGS.put("showScoreboard", new OptionContainer(ParkourOption.SCOREBOARD, (p, v) -> p.showScoreboard = parseBoolean(v)));
|
||||
COLUMN_MAPPINGS.put("selectedTime", new OptionContainer(ParkourOption.TIME, (p, v) -> p.selectedTime = Integer.parseInt(v)));
|
||||
COLUMN_MAPPINGS.put("selectedTime", new OptionContainer(ParkourOption.TIME, (p, v) ->
|
||||
p.selectedTime = parseIntSafe(v, defaultSelectedTime())));
|
||||
COLUMN_MAPPINGS.put("collectedRewards", new OptionContainer(null, PlayerSettingsManager::applyCollectedRewards));
|
||||
COLUMN_MAPPINGS.put("locale", new OptionContainer(ParkourOption.LANG, (p, v) -> {
|
||||
p._locale = v;
|
||||
p.locale = v;
|
||||
}));
|
||||
COLUMN_MAPPINGS.put("schematicDifficulty", new OptionContainer(ParkourOption.SCHEMATICS, (p, v) -> p.schematicDifficulty = Double.parseDouble(v)));
|
||||
COLUMN_MAPPINGS.put("schematicDifficulty", new OptionContainer(ParkourOption.SCHEMATICS, (p, v) ->
|
||||
p.schematicDifficulty = parseDoubleSafe(v, defaultSchematicDifficulty())));
|
||||
COLUMN_MAPPINGS.put("sound", new OptionContainer(ParkourOption.SOUND, (p, v) -> p.sound = parseBoolean(v)));
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +67,49 @@ public class PlayerSettingsManager {
|
|||
}
|
||||
|
||||
private static boolean parseBoolean(String string) {
|
||||
return string == null || string.equals("1") || string.equals("true");
|
||||
return string == null || string.equals("1") || string.equalsIgnoreCase("true");
|
||||
}
|
||||
|
||||
private static int defaultBlockLead() {
|
||||
return parseIntSafe(Option.OPTIONS_DEFAULTS.getOrDefault(ParkourOption.LEADS, "1"), 1);
|
||||
}
|
||||
|
||||
private static int defaultSelectedTime() {
|
||||
return parseIntSafe(Option.OPTIONS_DEFAULTS.getOrDefault(ParkourOption.TIME, "6000"), 6000);
|
||||
}
|
||||
|
||||
private static double defaultSchematicDifficulty() {
|
||||
return parseDoubleSafe(Option.OPTIONS_DEFAULTS.getOrDefault(ParkourOption.SCHEMATICS, "0.6"), 0.6);
|
||||
}
|
||||
|
||||
private static int parseIntSafe(String v, int fallback) {
|
||||
if (v == null) {
|
||||
return fallback;
|
||||
}
|
||||
String s = v.trim();
|
||||
if (s.isEmpty() || "true".equalsIgnoreCase(s) || "false".equalsIgnoreCase(s)) {
|
||||
return fallback;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
private static double parseDoubleSafe(String v, double fallback) {
|
||||
if (v == null) {
|
||||
return fallback;
|
||||
}
|
||||
String s = v.trim();
|
||||
if (s.isEmpty() || "true".equalsIgnoreCase(s) || "false".equalsIgnoreCase(s)) {
|
||||
return fallback;
|
||||
}
|
||||
try {
|
||||
return Double.parseDouble(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyCollectedRewards(ParkourPlayer player, String value) {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ class ScoreboardManager {
|
|||
return new Score("?", "?", "?", 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // Scoreboard: legacy registerNewObjective(String,String,String)
|
||||
private void updateTitle(Score top, Score high, ParkourGenerator generator) {
|
||||
Objective obj = board.getObjective("lp_sidebar");
|
||||
if (obj == null) {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
package dev.loki.loparkour.player.data;
|
||||
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.config.Config;
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
import org.bukkit.util.io.BukkitObjectOutputStream;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
|
|
@ -18,6 +16,10 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Saved hotbar/inventory slots for restore on leave. New files use YAML
|
||||
* (serializable ItemStacks); legacy Java-serialized files are still read once.
|
||||
*/
|
||||
public class InventoryData {
|
||||
|
||||
private final File file;
|
||||
|
|
@ -51,11 +53,46 @@ public class InventoryData {
|
|||
Scheduler.get(LoParkour.getPlugin()).runAsync(() -> loadFile(onFinish));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void loadFile(Consumer<@Nullable InventoryData> onFinish) {
|
||||
try {
|
||||
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(file);
|
||||
if (!yaml.getKeys(false).isEmpty()) {
|
||||
loadFromYaml(yaml);
|
||||
onFinish.accept(this);
|
||||
return;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LoParkour.getPlugin().getLogger().warning(
|
||||
"YAML inventory parse failed for %s, trying legacy format: %s".formatted(file.getName(), ex.getMessage()));
|
||||
}
|
||||
|
||||
if (file.length() == 0) {
|
||||
onFinish.accept(null);
|
||||
return;
|
||||
}
|
||||
|
||||
loadLegacy(onFinish);
|
||||
}
|
||||
|
||||
private void loadFromYaml(YamlConfiguration yaml) {
|
||||
items = new HashMap<>();
|
||||
for (String key : yaml.getKeys(false)) {
|
||||
try {
|
||||
int slot = Integer.parseInt(key);
|
||||
ItemStack stack = yaml.getItemStack(key);
|
||||
if (stack != null) {
|
||||
items.put(slot, stack);
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
// skip non-slot keys
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void loadLegacy(Consumer<@Nullable InventoryData> onFinish) {
|
||||
try (BukkitObjectInputStream stream = new BukkitObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) {
|
||||
items = (Map<Integer, ItemStack>) stream.readObject();
|
||||
|
||||
onFinish.accept(this);
|
||||
} catch (IOException | ClassNotFoundException ex) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while reading inventory of %s from file %s".formatted(player.getName(), file.getName()) + " - " + ex.getMessage());
|
||||
|
|
@ -98,9 +135,13 @@ public class InventoryData {
|
|||
LoParkour.getPlugin().getLogger().severe("Error while creating file to save inventory of %s to file %s".formatted(player.getName(), file.getName()) + " - " + ex.getMessage());
|
||||
}
|
||||
|
||||
try (ObjectOutputStream stream = new BukkitObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
|
||||
stream.writeObject(items);
|
||||
stream.flush();
|
||||
try {
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
yaml.options().header(" LoParkour inventory (YAML). Legacy binary saves are migrated on next save.");
|
||||
for (Map.Entry<Integer, ItemStack> e : items.entrySet()) {
|
||||
yaml.set(String.valueOf(e.getKey()), e.getValue());
|
||||
}
|
||||
yaml.save(file);
|
||||
} catch (IOException ex) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while saving inventory of %s to file %s".formatted(player.getName(), file.getName()) + " - " + ex.getMessage());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue