fix: resolve 266/375 checkstyle violations, add lolib jar
This commit is contained in:
parent
7df0c13ac4
commit
bfeecb0866
79 changed files with 773 additions and 292 deletions
|
|
@ -174,7 +174,7 @@ checkstyle {
|
|||
configFile = file("config/checkstyle/checkstyle.xml")
|
||||
isIgnoreFailures = true
|
||||
maxErrors = 0
|
||||
maxWarnings = 400
|
||||
maxWarnings = 200
|
||||
}
|
||||
|
||||
tasks.withType<Checkstyle>().configureEach {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public final class LoParkour extends LoPlugin {
|
|||
public static final String NAME = "&#FF6464&lLoParkour&r";
|
||||
public static final String PREFIX = NAME + " 񢩈» &#A0A0A0";
|
||||
|
||||
private static final Gson gson = new GsonBuilder()
|
||||
private static final Gson GSON = new GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.excludeFieldsWithoutExposeAnnotation()
|
||||
.create();
|
||||
|
|
@ -41,7 +41,7 @@ public final class LoParkour extends LoPlugin {
|
|||
private static PAPIHook placeholderHook;
|
||||
|
||||
public static Gson getGson() {
|
||||
return gson;
|
||||
return GSON;
|
||||
}
|
||||
|
||||
public static void log(String message) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
*/
|
||||
public class AdaptiveConfig {
|
||||
|
||||
private static final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, Object> CACHE = new ConcurrentHashMap<>();
|
||||
private static volatile boolean initialized = false;
|
||||
|
||||
// Configuration keys
|
||||
|
|
@ -39,12 +39,12 @@ public class AdaptiveConfig {
|
|||
return;
|
||||
}
|
||||
|
||||
cache.put(KEY_ENABLED, Config.CONFIG.getBoolean(KEY_ENABLED, DEFAULT_ENABLED));
|
||||
cache.put(KEY_MIN_SESSIONS, Config.CONFIG.getInt(KEY_MIN_SESSIONS, DEFAULT_MIN_SESSIONS));
|
||||
cache.put(KEY_UPDATE_INTERVAL, Config.CONFIG.getInt(KEY_UPDATE_INTERVAL, DEFAULT_UPDATE_INTERVAL));
|
||||
cache.put(KEY_RATING_WEIGHT, configDouble(KEY_RATING_WEIGHT, DEFAULT_RATING_WEIGHT));
|
||||
cache.put(KEY_CONFIDENCE_THRESHOLD, configDouble(KEY_CONFIDENCE_THRESHOLD, DEFAULT_CONFIDENCE_THRESHOLD));
|
||||
cache.put(KEY_NEAR_MISS_DISTANCE, configDouble(KEY_NEAR_MISS_DISTANCE, DEFAULT_NEAR_MISS_DISTANCE));
|
||||
CACHE.put(KEY_ENABLED, Config.CONFIG.getBoolean(KEY_ENABLED, DEFAULT_ENABLED));
|
||||
CACHE.put(KEY_MIN_SESSIONS, Config.CONFIG.getInt(KEY_MIN_SESSIONS, DEFAULT_MIN_SESSIONS));
|
||||
CACHE.put(KEY_UPDATE_INTERVAL, Config.CONFIG.getInt(KEY_UPDATE_INTERVAL, DEFAULT_UPDATE_INTERVAL));
|
||||
CACHE.put(KEY_RATING_WEIGHT, configDouble(KEY_RATING_WEIGHT, DEFAULT_RATING_WEIGHT));
|
||||
CACHE.put(KEY_CONFIDENCE_THRESHOLD, configDouble(KEY_CONFIDENCE_THRESHOLD, DEFAULT_CONFIDENCE_THRESHOLD));
|
||||
CACHE.put(KEY_NEAR_MISS_DISTANCE, configDouble(KEY_NEAR_MISS_DISTANCE, DEFAULT_NEAR_MISS_DISTANCE));
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ public class AdaptiveConfig {
|
|||
*/
|
||||
public static void reload() {
|
||||
initialized = false;
|
||||
cache.clear();
|
||||
CACHE.clear();
|
||||
init();
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ public class AdaptiveConfig {
|
|||
*/
|
||||
public static boolean isEnabled() {
|
||||
ensureInitialized();
|
||||
return (boolean) cache.getOrDefault(KEY_ENABLED, DEFAULT_ENABLED);
|
||||
return (boolean) CACHE.getOrDefault(KEY_ENABLED, DEFAULT_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -76,7 +76,7 @@ public class AdaptiveConfig {
|
|||
*/
|
||||
public static int getMinSessions() {
|
||||
ensureInitialized();
|
||||
return (int) cache.getOrDefault(KEY_MIN_SESSIONS, DEFAULT_MIN_SESSIONS);
|
||||
return (int) CACHE.getOrDefault(KEY_MIN_SESSIONS, DEFAULT_MIN_SESSIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -86,7 +86,7 @@ public class AdaptiveConfig {
|
|||
*/
|
||||
public static int getUpdateInterval() {
|
||||
ensureInitialized();
|
||||
return (int) cache.getOrDefault(KEY_UPDATE_INTERVAL, DEFAULT_UPDATE_INTERVAL);
|
||||
return (int) CACHE.getOrDefault(KEY_UPDATE_INTERVAL, DEFAULT_UPDATE_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -96,7 +96,7 @@ public class AdaptiveConfig {
|
|||
*/
|
||||
public static double getRatingWeight() {
|
||||
ensureInitialized();
|
||||
Object value = cache.get(KEY_RATING_WEIGHT);
|
||||
Object value = CACHE.get(KEY_RATING_WEIGHT);
|
||||
if (value instanceof Double) {
|
||||
return (double) value;
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ public class AdaptiveConfig {
|
|||
*/
|
||||
public static double getConfidenceThreshold() {
|
||||
ensureInitialized();
|
||||
Object value = cache.get(KEY_CONFIDENCE_THRESHOLD);
|
||||
Object value = CACHE.get(KEY_CONFIDENCE_THRESHOLD);
|
||||
if (value instanceof Double) {
|
||||
return (double) value;
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ public class AdaptiveConfig {
|
|||
*/
|
||||
public static double getNearMissDistance() {
|
||||
ensureInitialized();
|
||||
Object value = cache.get(KEY_NEAR_MISS_DISTANCE);
|
||||
Object value = CACHE.get(KEY_NEAR_MISS_DISTANCE);
|
||||
if (value instanceof Double) {
|
||||
return (double) value;
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ public class AdaptiveConfig {
|
|||
public static <T> T get(@NotNull String key, @NotNull T defaultValue) {
|
||||
ensureInitialized();
|
||||
@SuppressWarnings("unchecked")
|
||||
T value = (T) cache.get(key);
|
||||
T value = (T) CACHE.get(key);
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,11 @@ import java.util.List;
|
|||
*/
|
||||
public final class Registry {
|
||||
|
||||
private static final LinkedList<Mode> modes = new LinkedList<>();
|
||||
private static final LinkedList<Style> styles = new LinkedList<>();
|
||||
private Registry() {
|
||||
}
|
||||
|
||||
private static final LinkedList<Mode> MODES = new LinkedList<>();
|
||||
private static final LinkedList<Style> STYLES = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Registers a {@link Mode}.
|
||||
|
|
@ -25,11 +28,11 @@ public final class Registry {
|
|||
* @param mode The mode.
|
||||
*/
|
||||
public static void register(@NotNull Mode mode) {
|
||||
modes.add(mode);
|
||||
MODES.add(mode);
|
||||
}
|
||||
|
||||
public static void register(@NotNull Style style) {
|
||||
styles.add(style);
|
||||
STYLES.add(style);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -38,7 +41,7 @@ public final class Registry {
|
|||
*/
|
||||
@Nullable
|
||||
public static Mode getMode(@NotNull String name) {
|
||||
return modes.stream()
|
||||
return MODES.stream()
|
||||
.filter(mode -> mode.getName().equals(name))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
|
@ -46,17 +49,17 @@ public final class Registry {
|
|||
|
||||
@Nullable
|
||||
public static Style getStyle(@NotNull String name) {
|
||||
return styles.stream()
|
||||
return STYLES.stream()
|
||||
.filter(style -> style.getName().equals(name))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public static List<Style> getStyles() {
|
||||
return styles;
|
||||
return STYLES;
|
||||
}
|
||||
|
||||
public static List<Mode> getModes() {
|
||||
return modes;
|
||||
return MODES;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import org.bstats.bukkit.Metrics;
|
|||
import org.bstats.charts.SimplePie;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Wires plugin subsystems during {@link LoParkour#enable()} and {@link LoParkour#disable()}.
|
||||
|
|
|
|||
|
|
@ -79,11 +79,15 @@ public class LoParkourCommand implements CommandExecutor, TabCompleter {
|
|||
admin.handle(a1, a2, sender, p);
|
||||
return;
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
|
||||
if (p == null) return;
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (a1.equalsIgnoreCase("create") && p.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
if ("create".equalsIgnoreCase(a1) && p.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
SchematicCommandHandler.handleCreateDifficultyOnly(a2, sender, p, player);
|
||||
return;
|
||||
}
|
||||
|
|
@ -98,17 +102,23 @@ public class LoParkourCommand implements CommandExecutor, TabCompleter {
|
|||
}
|
||||
SchematicCommandHandler.handleSubcommand(a2, sender, p, player);
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 3-arg routing ──────────────────────────────────────────────────────────
|
||||
|
||||
private void handle3(String a1, String a2, String a3, CommandSender sender, @Nullable Player p) {
|
||||
if (p == null) return;
|
||||
if (!p.hasPermission(ParkourOption.ADMIN.permission)) return;
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
if (!p.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (a1.equalsIgnoreCase("schematic")) {
|
||||
if (a2.equalsIgnoreCase("create")) {
|
||||
if ("schematic".equalsIgnoreCase(a1)) {
|
||||
if ("create".equalsIgnoreCase(a2)) {
|
||||
SchematicCommandHandler.handleCreateDifficultyOnly(a3, sender, p, player);
|
||||
return;
|
||||
}
|
||||
|
|
@ -117,29 +127,48 @@ public class LoParkourCommand implements CommandExecutor, TabCompleter {
|
|||
}
|
||||
|
||||
private void handle4(String a1, String a2, String a3, String a4, CommandSender sender, @Nullable Player p) {
|
||||
if (p == null) return;
|
||||
if (!p.hasPermission(ParkourOption.ADMIN.permission)) return;
|
||||
if (!a1.equalsIgnoreCase("schematic") || !a2.equalsIgnoreCase("create")) return;
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
if (!p.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
return;
|
||||
}
|
||||
if (!"schematic".equalsIgnoreCase(a1) || !"create".equalsIgnoreCase(a2)) {
|
||||
return;
|
||||
}
|
||||
SchematicCommandHandler.handleCreateWithDifficulty(a3, a4, sender, p, player);
|
||||
}
|
||||
|
||||
// ── join logic ─────────────────────────────────────────────────────────────
|
||||
|
||||
private void handleJoin(String arg, CommandSender sender, Player p) {
|
||||
if (!player.cooldown(sender, "join", 2500) || !ParkourOption.JOIN.mayPerform(p)) return;
|
||||
if (!player.cooldown(sender, "join", 2500) || !ParkourOption.JOIN.mayPerform(p)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mode mode = Registry.getMode(arg);
|
||||
if (mode != null) { mode.create(p); return; }
|
||||
if (mode != null) {
|
||||
mode.create(p);
|
||||
return;
|
||||
}
|
||||
|
||||
Player other = Bukkit.getPlayer(arg);
|
||||
if (other == null) { send(sender, LoParkour.PREFIX + Locales.getString(sender, "commands.unknown_player")); return; }
|
||||
if (other == null) {
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "commands.unknown_player"));
|
||||
return;
|
||||
}
|
||||
|
||||
ParkourPlayer pp = ParkourPlayer.getPlayer(other);
|
||||
if (pp == null) { send(sender, LoParkour.PREFIX + Locales.getString(sender, "commands.not_playing")); return; }
|
||||
if (pp == null) {
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "commands.not_playing"));
|
||||
return;
|
||||
}
|
||||
|
||||
ParkourUser user = ParkourUser.getUser(p);
|
||||
Session session = pp.session;
|
||||
if (user != null && user.session == session) return;
|
||||
if (user != null && user.session == session) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.isAcceptingPlayers()) {
|
||||
Mode sessionMode = session.generator.getMode();
|
||||
|
|
|
|||
|
|
@ -38,18 +38,24 @@ public class AdminCommandHandler {
|
|||
public void handle(@NotNull String arg1, @NotNull String arg2,
|
||||
@NotNull CommandSender sender, @Nullable Player player) {
|
||||
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission)) return;
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (arg1.toLowerCase()) {
|
||||
case "forcejoin" -> handleForceJoin(arg2, sender);
|
||||
case "forceleave" -> handleForceLeave(arg2, sender);
|
||||
case "reset" -> handleReset(arg2, sender);
|
||||
case "recoverinventory" -> handleRecoverInventory(arg2, sender);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
|
||||
if (player == null) return;
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg1.equals("schematic")) {
|
||||
if ("schematic".equals(arg1)) {
|
||||
SchematicCommandHandler.handleSubcommand(arg2, sender, player, base);
|
||||
}
|
||||
}
|
||||
|
|
@ -57,52 +63,72 @@ public class AdminCommandHandler {
|
|||
// ── forcejoin ──────────────────────────────────────────────────────────────
|
||||
|
||||
private void handleForceJoin(String target, CommandSender sender) {
|
||||
if (!base.cooldown(sender, "forcejoin", 2500, Locales.getString(sender, "admin.cooldown"))) return;
|
||||
if (!base.cooldown(sender, "forcejoin", 2500, Locales.getString(sender, "admin.cooldown"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.equalsIgnoreCase("everyone")) {
|
||||
if ("everyone".equalsIgnoreCase(target)) {
|
||||
Bukkit.getOnlinePlayers().forEach(p -> Modes.DEFAULT.create(p));
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.force_join_everyone"));
|
||||
return;
|
||||
}
|
||||
if (target.equalsIgnoreCase("nearest")) {
|
||||
if ("nearest".equalsIgnoreCase(target)) {
|
||||
Player closest = findNearest(sender);
|
||||
if (closest == null) return;
|
||||
if (closest == null) {
|
||||
return;
|
||||
}
|
||||
Modes.DEFAULT.create(closest);
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.force_join_player").formatted(closest.getName()));
|
||||
return;
|
||||
}
|
||||
Player other = Bukkit.getPlayer(target);
|
||||
if (other == null) { send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.player_not_online")); return; }
|
||||
if (other == null) {
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.player_not_online"));
|
||||
return;
|
||||
}
|
||||
Modes.DEFAULT.create(other);
|
||||
}
|
||||
|
||||
// ── forceleave ─────────────────────────────────────────────────────────────
|
||||
|
||||
private void handleForceLeave(String target, CommandSender sender) {
|
||||
if (!base.cooldown(sender, "forceleave", 2500, Locales.getString(sender, "admin.cooldown"))) return;
|
||||
if (!base.cooldown(sender, "forceleave", 2500, Locales.getString(sender, "admin.cooldown"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.equalsIgnoreCase("everyone")) {
|
||||
if ("everyone".equalsIgnoreCase(target)) {
|
||||
ParkourPlayer.getPlayers().forEach(ParkourUser::leave);
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.force_leave_everyone"));
|
||||
return;
|
||||
}
|
||||
Player other = Bukkit.getPlayer(target);
|
||||
if (other == null) { send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.player_not_online")); return; }
|
||||
if (other == null) {
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.player_not_online"));
|
||||
return;
|
||||
}
|
||||
ParkourUser user = ParkourUser.getUser(other);
|
||||
if (user == null) { send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.player_not_playing")); return; }
|
||||
if (user == null) {
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.player_not_playing"));
|
||||
return;
|
||||
}
|
||||
ParkourUser.leave(user);
|
||||
}
|
||||
|
||||
// ── reset ──────────────────────────────────────────────────────────────────
|
||||
|
||||
private void handleReset(String target, CommandSender sender) {
|
||||
if (!base.cooldown(sender, "reset", 2500, Locales.getString(sender, "admin.cooldown"))) return;
|
||||
if (!base.cooldown(sender, "reset", 2500, Locales.getString(sender, "admin.cooldown"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.equalsIgnoreCase("everyone")) {
|
||||
if ("everyone".equalsIgnoreCase(target)) {
|
||||
Registry.getModes().stream()
|
||||
.map(Mode::getLeaderboard)
|
||||
.filter(lb -> lb != null)
|
||||
.forEach(lb -> { lb.resetAll(); lb.write(true); });
|
||||
.forEach(lb -> {
|
||||
lb.resetAll();
|
||||
lb.write(true);
|
||||
});
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.reset_all"));
|
||||
return;
|
||||
}
|
||||
|
|
@ -113,7 +139,10 @@ public class AdminCommandHandler {
|
|||
Registry.getModes().stream()
|
||||
.map(Mode::getLeaderboard)
|
||||
.filter(lb -> lb != null)
|
||||
.forEach(lb -> { lb.remove(uuid); lb.write(true); });
|
||||
.forEach(lb -> {
|
||||
lb.remove(uuid);
|
||||
lb.write(true);
|
||||
});
|
||||
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.reset_player").formatted(name));
|
||||
}
|
||||
|
|
@ -121,9 +150,14 @@ public class AdminCommandHandler {
|
|||
// ── recoverinventory ───────────────────────────────────────────────────────
|
||||
|
||||
private void handleRecoverInventory(String target, CommandSender sender) {
|
||||
if (!base.cooldown(sender, "recoverinventory", 2500, Locales.getString(sender, "admin.cooldown"))) return;
|
||||
if (!base.cooldown(sender, "recoverinventory", 2500, Locales.getString(sender, "admin.cooldown"))) {
|
||||
return;
|
||||
}
|
||||
Player other = Bukkit.getPlayer(target);
|
||||
if (other == null) { send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.player_not_online")); return; }
|
||||
if (other == null) {
|
||||
send(sender, LoParkour.PREFIX + Locales.getString(sender, "admin.player_not_online"));
|
||||
return;
|
||||
}
|
||||
|
||||
new InventoryData(other).load(result -> {
|
||||
if (result != null) {
|
||||
|
|
@ -140,7 +174,9 @@ public class AdminCommandHandler {
|
|||
Location from = sender instanceof Player p ? p.getLocation()
|
||||
: sender instanceof BlockCommandSender b ? b.getBlock().getLocation()
|
||||
: null;
|
||||
if (from == null || from.getWorld() == null) return null;
|
||||
if (from == null || from.getWorld() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return from.getWorld().getPlayers().stream()
|
||||
.min((a, b) -> Double.compare(a.getLocation().distance(from), b.getLocation().distance(from)))
|
||||
|
|
@ -150,7 +186,9 @@ public class AdminCommandHandler {
|
|||
@SuppressWarnings("deprecation") // Bukkit: name-based OfflinePlayer lookup (admin-only)
|
||||
private UUID resolveUUID(String input) {
|
||||
Player online = Bukkit.getPlayerExact(input);
|
||||
if (online != null) return online.getUniqueId();
|
||||
if (online != null) {
|
||||
return online.getUniqueId();
|
||||
}
|
||||
if (input.contains("-")) {
|
||||
try {
|
||||
return UUID.fromString(input);
|
||||
|
|
@ -163,7 +201,9 @@ public class AdminCommandHandler {
|
|||
|
||||
private String resolvePlayerName(String input, UUID uuid) {
|
||||
Player online = Bukkit.getPlayerExact(input);
|
||||
if (online != null) return online.getName();
|
||||
if (online != null) {
|
||||
return online.getName();
|
||||
}
|
||||
OfflinePlayer op = Bukkit.getOfflinePlayer(uuid);
|
||||
return op.getName() != null ? op.getName() : input;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,29 +37,43 @@ public class PlayerCommandHandler {
|
|||
switch (arg.toLowerCase()) {
|
||||
case "help" -> sendHelp(sender);
|
||||
case "reload" -> handleReload(sender, player);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
|
||||
if (player == null) return;
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (arg.toLowerCase()) {
|
||||
case "join" -> {
|
||||
if (!cooldown(sender, "join", 2500)) return;
|
||||
if (!cooldown(sender, "join", 2500)) {
|
||||
return;
|
||||
}
|
||||
if (!ParkourOption.JOIN.mayPerform(player)) {
|
||||
send(sender, Locales.getString(player, "other.no_do"));
|
||||
return;
|
||||
}
|
||||
if (ParkourUser.getUser(player) != null) return;
|
||||
if (ParkourUser.getUser(player) != null) {
|
||||
return;
|
||||
}
|
||||
Modes.DEFAULT.create(player);
|
||||
}
|
||||
case "leave" -> {
|
||||
if (!cooldown(sender, "leave", 2500)) return;
|
||||
if (!cooldown(sender, "leave", 2500)) {
|
||||
return;
|
||||
}
|
||||
ParkourUser.leave(player);
|
||||
}
|
||||
case "play" -> {
|
||||
if (ParkourOption.PLAY.mayPerform(player)) Menus.PLAY.open(player);
|
||||
if (ParkourOption.PLAY.mayPerform(player)) {
|
||||
Menus.PLAY.open(player);
|
||||
}
|
||||
}
|
||||
case "menu", "main" -> {
|
||||
if (ParkourOption.MAIN.mayPerform(player)) Menus.MAIN.open(player);
|
||||
if (ParkourOption.MAIN.mayPerform(player)) {
|
||||
Menus.MAIN.open(player);
|
||||
}
|
||||
}
|
||||
case "leaderboard" -> {
|
||||
if (!ParkourOption.LEADERBOARDS.mayPerform(player)) {
|
||||
|
|
@ -75,11 +89,15 @@ public class PlayerCommandHandler {
|
|||
}
|
||||
SchematicCommandHandler.sendHelp(player);
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReload(@NotNull CommandSender sender, @Nullable Player player) {
|
||||
if (!cooldown(sender, "reload", 2500)) return;
|
||||
if (!cooldown(sender, "reload", 2500)) {
|
||||
return;
|
||||
}
|
||||
if (!sender.hasPermission(ParkourOption.ADMIN.permission)) {
|
||||
send(sender, Locales.getString(sender, "other.no_do"));
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,10 @@ import java.util.Map;
|
|||
*/
|
||||
public class SchematicCommandHandler {
|
||||
|
||||
public static final Map<Player, Location[]> selections = new HashMap<>();
|
||||
private SchematicCommandHandler() {
|
||||
}
|
||||
|
||||
public static final Map<Player, Location[]> SELECTIONS = new HashMap<>();
|
||||
public static final NamespacedKey WAND_KEY = new NamespacedKey(LoParkour.getPlugin(), "schematic_wand");
|
||||
|
||||
private static ItemStack cachedWand;
|
||||
|
|
@ -53,10 +56,10 @@ public class SchematicCommandHandler {
|
|||
|
||||
@NotNull
|
||||
public static Location[] getSelection(@NotNull Player player) {
|
||||
Location[] sel = selections.get(player);
|
||||
Location[] sel = SELECTIONS.get(player);
|
||||
if (sel == null) {
|
||||
sel = new Location[]{null, null};
|
||||
selections.put(player, sel);
|
||||
SELECTIONS.put(player, sel);
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
|
@ -64,7 +67,7 @@ public class SchematicCommandHandler {
|
|||
public static void setPos(@NotNull Player player, @NotNull Location loc, int index) {
|
||||
Location[] updated = getSelection(player).clone();
|
||||
updated[index] = loc.clone();
|
||||
selections.put(player, updated);
|
||||
SELECTIONS.put(player, updated);
|
||||
}
|
||||
|
||||
public static void clearWandCache() {
|
||||
|
|
@ -161,7 +164,7 @@ public class SchematicCommandHandler {
|
|||
CommandSender sender,
|
||||
Player player
|
||||
) {
|
||||
Location[] sel = selections.get(player);
|
||||
Location[] sel = SELECTIONS.get(player);
|
||||
if (sel == null || sel[0] == null || sel[1] == null) {
|
||||
send(player, LoParkour.PREFIX + Locales.getString(player, "schematic.selection_incomplete"));
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ public enum Config {
|
|||
* Load this configuration file from disk.
|
||||
*/
|
||||
public void load() {
|
||||
if (path == null) return;
|
||||
if (path == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fileConfiguration = ConfigLoader.loadConfig(path);
|
||||
this.accessor = new ConfigAccessor(fileConfiguration, fileName);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ import java.util.logging.Logger;
|
|||
*/
|
||||
public class ConfigLoader {
|
||||
|
||||
private ConfigLoader() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FileConfiguration loadConfig(@NotNull File configFile) {
|
||||
return YamlConfiguration.loadConfiguration(configFile);
|
||||
|
|
|
|||
|
|
@ -3,10 +3,21 @@ package dev.loki.loparkour.config.core;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
|
|
@ -80,14 +91,19 @@ public class ConfigUpdater {
|
|||
}
|
||||
|
||||
int colon = trimmed.indexOf(':');
|
||||
if (colon == -1) { result.add(line); continue; }
|
||||
if (colon == -1) {
|
||||
result.add(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
String leaf = trimmed.substring(0, colon).trim();
|
||||
String after = trimmed.substring(colon + 1).trim();
|
||||
int indent = indentOf(line);
|
||||
|
||||
while (prevIndent >= 0 && indent <= prevIndent) {
|
||||
if (!stack.isEmpty()) stack.pop();
|
||||
if (!stack.isEmpty()) {
|
||||
stack.pop();
|
||||
}
|
||||
prevIndent -= 2;
|
||||
}
|
||||
|
||||
|
|
@ -120,17 +136,23 @@ public class ConfigUpdater {
|
|||
|
||||
for (String line : lines) {
|
||||
String trimmed = line.trim();
|
||||
if (trimmed.isEmpty() || trimmed.startsWith("#") || trimmed.startsWith("-")) continue;
|
||||
if (trimmed.isEmpty() || trimmed.startsWith("#") || trimmed.startsWith("-")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int colon = trimmed.indexOf(':');
|
||||
if (colon == -1) continue;
|
||||
if (colon == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String leaf = trimmed.substring(0, colon).trim();
|
||||
String after = trimmed.substring(colon + 1).trim();
|
||||
int indent = indentOf(line);
|
||||
|
||||
while (prevIndent >= 0 && indent <= prevIndent) {
|
||||
if (!stack.isEmpty()) stack.pop();
|
||||
if (!stack.isEmpty()) {
|
||||
stack.pop();
|
||||
}
|
||||
prevIndent -= 2;
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +172,9 @@ public class ConfigUpdater {
|
|||
|
||||
private static int indentOf(@NotNull String line) {
|
||||
int i = 0;
|
||||
while (i < line.length() && line.charAt(i) == ' ') i++;
|
||||
while (i < line.length() && line.charAt(i) == ' ') {
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
@ -181,16 +205,22 @@ public class ConfigUpdater {
|
|||
|
||||
@NotNull
|
||||
private static Set<String> normalizeIgnored(@Nullable List<String> keys) {
|
||||
if (keys == null) return Set.of();
|
||||
if (keys == null) {
|
||||
return Set.of();
|
||||
}
|
||||
Set<String> s = new HashSet<>();
|
||||
for (String k : keys) s.add(k.trim().toLowerCase());
|
||||
for (String k : keys) {
|
||||
s.add(k.trim().toLowerCase());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private static boolean isIgnored(@NotNull String fullPath, @NotNull Set<String> ignored) {
|
||||
String lower = fullPath.toLowerCase();
|
||||
for (String ign : ignored) {
|
||||
if (lower.equals(ign) || lower.startsWith(ign + ".")) return true;
|
||||
if (lower.equals(ign) || lower.startsWith(ign + ".")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@ package dev.loki.loparkour.config.locale;
|
|||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
|
|
@ -28,9 +31,13 @@ public class LocaleCache {
|
|||
public synchronized <T> T cachedValue(@NotNull String locale,
|
||||
@NotNull Function<FileConfiguration, T> extractor,
|
||||
@NotNull T defaultValue) {
|
||||
if (locales.isEmpty()) return defaultValue;
|
||||
if (locales.isEmpty()) {
|
||||
return defaultValue;
|
||||
}
|
||||
FileConfiguration config = locales.get(locale);
|
||||
if (config == null) return defaultValue;
|
||||
if (config == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
T result = extractor.apply(config);
|
||||
return result != null ? result : defaultValue;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,11 @@ import java.io.InputStreamReader;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
|
|
@ -48,7 +52,9 @@ public class LocaleLoader {
|
|||
try (Stream<Path> stream = Files.list(folder.toPath())) {
|
||||
stream.forEach(path -> {
|
||||
File file = path.toFile();
|
||||
if (!file.getName().endsWith(".yml")) return;
|
||||
if (!file.getName().endsWith(".yml")) {
|
||||
return;
|
||||
}
|
||||
|
||||
String locale = file.getName().split("\\.")[0];
|
||||
LoParkour.log("Found locale " + locale);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ import org.bukkit.configuration.file.FileConfiguration;
|
|||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
|
@ -23,14 +26,14 @@ import java.util.regex.Pattern;
|
|||
*/
|
||||
public class Locales {
|
||||
|
||||
private static final LocaleCache cache = new LocaleCache();
|
||||
private static final LocaleCache CACHE = new LocaleCache();
|
||||
private static final Pattern REPLACEMENT_PATTERN = Pattern.compile("%[a-z]");
|
||||
|
||||
// ── Initialization ────────────────────────────────────────────────────────
|
||||
|
||||
public static void init() {
|
||||
Map<String, FileConfiguration> loaded = LocaleLoader.loadAll();
|
||||
cache.setLocales(loaded);
|
||||
CACHE.setLocales(loaded);
|
||||
dev.loki.loparkour.command.schematic.SchematicCommandHandler.clearWandCache();
|
||||
LoParkour.log("Locales loaded successfully (" + loaded.size() + " locales)");
|
||||
}
|
||||
|
|
@ -61,7 +64,7 @@ public class Locales {
|
|||
|
||||
@NotNull
|
||||
public static String getString(@NotNull String locale, @NotNull String path) {
|
||||
return cache.cachedValue(locale, c -> c.getString(path), "");
|
||||
return CACHE.cachedValue(locale, c -> c.getString(path), "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -84,16 +87,16 @@ public class Locales {
|
|||
|
||||
@NotNull
|
||||
public static List<String> getStringList(@NotNull String locale, @NotNull String path) {
|
||||
return cache.cachedValue(locale, c -> c.getStringList(path), Collections.emptyList());
|
||||
return CACHE.cachedValue(locale, c -> c.getStringList(path), Collections.emptyList());
|
||||
}
|
||||
|
||||
public static int getLocaleCount() {
|
||||
return cache.getLocaleCount();
|
||||
return CACHE.getLocaleCount();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Set<String> getLocaleKeys() {
|
||||
return cache.getLocaleKeys();
|
||||
return CACHE.getLocaleKeys();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
|
@ -103,14 +106,14 @@ public class Locales {
|
|||
|
||||
@NotNull
|
||||
public static Item getItem(@NotNull String locale, @NotNull String path, String... replace) {
|
||||
if (cache.isEmpty()) {
|
||||
if (CACHE.isEmpty()) {
|
||||
LoParkour.getPlugin().getLogger().warning("Locales are empty! Returning STONE item for path: " + path);
|
||||
return new Item(Material.STONE, "");
|
||||
}
|
||||
FileConfiguration config = cache.getLocale(locale);
|
||||
FileConfiguration config = CACHE.getLocale(locale);
|
||||
if (config == null) {
|
||||
LoParkour.getPlugin().getLogger().warning(
|
||||
"Locale '" + locale + "' not found! Available: " + cache.getLocaleKeys() + ". Returning STONE for path: " + path);
|
||||
"Locale '" + locale + "' not found! Available: " + CACHE.getLocaleKeys() + ". Returning STONE for path: " + path);
|
||||
return new Item(Material.STONE, "");
|
||||
}
|
||||
return buildItem(config, path, replace);
|
||||
|
|
@ -147,7 +150,9 @@ public class Locales {
|
|||
|
||||
@NotNull
|
||||
private static String applyReplacements(@NotNull String text, String... replacements) {
|
||||
if (replacements.length == 0) return text;
|
||||
if (replacements.length == 0) {
|
||||
return text;
|
||||
}
|
||||
String result = text;
|
||||
int idx = 0;
|
||||
Matcher matcher = REPLACEMENT_PATTERN.matcher(result);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package dev.loki.loparkour.config.options;
|
|||
|
||||
import dev.loki.loparkour.api.core.Registry;
|
||||
import dev.loki.loparkour.config.core.Config;
|
||||
import dev.loki.loparkour.config.options.*;
|
||||
import dev.loki.loparkour.menu.core.ParkourOption;
|
||||
import dev.loki.loparkour.style.core.RandomStyle;
|
||||
import dev.loki.loparkour.style.core.Style;
|
||||
|
|
@ -61,17 +60,34 @@ public class Option {
|
|||
public static ParticleData<?> PARTICLE_DATA;
|
||||
|
||||
// Generation
|
||||
public static double TYPE_NORMAL, TYPE_SPECIAL, TYPE_SCHEMATICS;
|
||||
public static double SPECIAL_ICE, SPECIAL_SLAB, SPECIAL_PANE, SPECIAL_FENCE;
|
||||
public static double NORMAL_DISTANCE_1, NORMAL_DISTANCE_2, NORMAL_DISTANCE_3, NORMAL_DISTANCE_4;
|
||||
public static double NORMAL_HEIGHT_1, NORMAL_HEIGHT_0, NORMAL_HEIGHT_NEG1, NORMAL_HEIGHT_NEG2;
|
||||
public static int MAX_Y, MIN_Y;
|
||||
public static int BLOCK_CLEANUP_DISTANCE, CLEANUP_INTERVAL, TRAIL_KEEP_BEHIND;
|
||||
public static double TYPE_NORMAL;
|
||||
public static double TYPE_SPECIAL;
|
||||
public static double TYPE_SCHEMATICS;
|
||||
public static double SPECIAL_ICE;
|
||||
public static double SPECIAL_SLAB;
|
||||
public static double SPECIAL_PANE;
|
||||
public static double SPECIAL_FENCE;
|
||||
public static double NORMAL_DISTANCE_1;
|
||||
public static double NORMAL_DISTANCE_2;
|
||||
public static double NORMAL_DISTANCE_3;
|
||||
public static double NORMAL_DISTANCE_4;
|
||||
public static double NORMAL_HEIGHT_1;
|
||||
public static double NORMAL_HEIGHT_0;
|
||||
public static double NORMAL_HEIGHT_NEG1;
|
||||
public static double NORMAL_HEIGHT_NEG2;
|
||||
public static int MAX_Y;
|
||||
public static int MIN_Y;
|
||||
public static int BLOCK_CLEANUP_DISTANCE;
|
||||
public static int CLEANUP_INTERVAL;
|
||||
public static int TRAIL_KEEP_BEHIND;
|
||||
public static boolean GHOST_MODE_ENABLED;
|
||||
public static int GHOST_SHOW_TOP;
|
||||
public static double GHOST_TRANSPARENCY;
|
||||
public static boolean JUMP_VALIDATION_ENABLED;
|
||||
public static double MAX_JUMP_DISTANCE, MAX_HORIZONTAL_DISTANCE, MAX_VERTICAL_UP, MAX_VERTICAL_DOWN;
|
||||
public static double MAX_JUMP_DISTANCE;
|
||||
public static double MAX_HORIZONTAL_DISTANCE;
|
||||
public static double MAX_VERTICAL_UP;
|
||||
public static double MAX_VERTICAL_DOWN;
|
||||
public static boolean JUMP_TYPES_ENABLED;
|
||||
public static Map<String, Boolean> JUMP_TYPE_ENABLED;
|
||||
public static Map<String, Double> JUMP_TYPE_CHANCE;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ import org.bukkit.Location;
|
|||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockFace;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* General configuration options (heading, border, leads, go-back location, parkour options).
|
||||
|
|
@ -125,7 +129,9 @@ public class OptionGeneral {
|
|||
throw new IllegalArgumentException("Expected 4 values (x,y,z,world), got " + values.length);
|
||||
}
|
||||
World world = Bukkit.getWorld(values[3]);
|
||||
if (world == null) world = Bukkit.getWorlds().get(0);
|
||||
if (world == null) {
|
||||
world = Bukkit.getWorlds().get(0);
|
||||
}
|
||||
return new Location(world, Double.parseDouble(values[0]),
|
||||
Double.parseDouble(values[1]), Double.parseDouble(values[2]));
|
||||
} catch (Exception ex) {
|
||||
|
|
|
|||
|
|
@ -12,11 +12,23 @@ import java.util.Map;
|
|||
public class OptionGeneration {
|
||||
|
||||
// ── Block generation probabilities ────────────────────────────────────────
|
||||
public static double TYPE_NORMAL, TYPE_SPECIAL, TYPE_SCHEMATICS;
|
||||
public static double SPECIAL_ICE, SPECIAL_SLAB, SPECIAL_PANE, SPECIAL_FENCE;
|
||||
public static double NORMAL_DISTANCE_1, NORMAL_DISTANCE_2, NORMAL_DISTANCE_3, NORMAL_DISTANCE_4;
|
||||
public static double NORMAL_HEIGHT_1, NORMAL_HEIGHT_0, NORMAL_HEIGHT_NEG1, NORMAL_HEIGHT_NEG2;
|
||||
public static int MAX_Y, MIN_Y;
|
||||
public static double TYPE_NORMAL;
|
||||
public static double TYPE_SPECIAL;
|
||||
public static double TYPE_SCHEMATICS;
|
||||
public static double SPECIAL_ICE;
|
||||
public static double SPECIAL_SLAB;
|
||||
public static double SPECIAL_PANE;
|
||||
public static double SPECIAL_FENCE;
|
||||
public static double NORMAL_DISTANCE_1;
|
||||
public static double NORMAL_DISTANCE_2;
|
||||
public static double NORMAL_DISTANCE_3;
|
||||
public static double NORMAL_DISTANCE_4;
|
||||
public static double NORMAL_HEIGHT_1;
|
||||
public static double NORMAL_HEIGHT_0;
|
||||
public static double NORMAL_HEIGHT_NEG1;
|
||||
public static double NORMAL_HEIGHT_NEG2;
|
||||
public static int MAX_Y;
|
||||
public static int MIN_Y;
|
||||
|
||||
// ── Memory / cleanup ──────────────────────────────────────────────────────
|
||||
public static int BLOCK_CLEANUP_DISTANCE;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package dev.loki.loparkour.config.options;
|
|||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.config.core.Config;
|
||||
import dev.loki.loparkour.config.options.Option;
|
||||
import dev.loki.loparkour.util.particle.ParticleData;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
|
|
|
|||
|
|
@ -127,7 +127,9 @@ public class ParkourGenerator {
|
|||
|
||||
/** Last generated block, or {@code null} if history is empty. */
|
||||
public @Nullable Block getLatest() {
|
||||
if (state.history.isEmpty()) return null;
|
||||
if (state.history.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return state.history.get(state.history.size() - 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ import org.bukkit.block.data.BlockData;
|
|||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds all state data for parkour generation.
|
||||
|
|
|
|||
|
|
@ -41,14 +41,16 @@ public class Profile {
|
|||
* @return true when the string value is "true", else "false".
|
||||
*/
|
||||
public boolean asBoolean() {
|
||||
return value.equals("true"); // save parsing
|
||||
return "true".equals(value); // save parsing
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The value as a double. Returns 0.0 if the value is empty.
|
||||
*/
|
||||
public double asDouble() {
|
||||
if (value.isEmpty()) return 0.0;
|
||||
if (value.isEmpty()) {
|
||||
return 0.0;
|
||||
}
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +58,9 @@ public class Profile {
|
|||
* @return The value as an int. Returns 0 if the value is empty.
|
||||
*/
|
||||
public int asInt() {
|
||||
if (value.isEmpty()) return 0;
|
||||
if (value.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ public class EffectManager {
|
|||
* Spawns particles around the given blocks based on the configured shape.
|
||||
*/
|
||||
public void particles(List<Block> blocks) {
|
||||
if (!generator.profile.get("particles").asBoolean()) return;
|
||||
if (!generator.profile.get("particles").asBoolean()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Location> locations = blocks.stream().map(Block::getLocation).toList();
|
||||
Location max = locations.stream().reduce((a, b) -> {
|
||||
|
|
@ -41,7 +43,9 @@ public class EffectManager {
|
|||
return new Location(a.getWorld(), x, y, z);
|
||||
}).orElse(null);
|
||||
|
||||
if (max == null || min == null || max.getWorld() == null) return;
|
||||
if (max == null || min == null || max.getWorld() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ParkourPlayer> viewers = generator.getPlayers();
|
||||
|
||||
|
|
@ -64,6 +68,7 @@ public class EffectManager {
|
|||
org.bukkit.util.BoundingBox.of(min, max), max.getWorld(), Option.PARTICLE_TYPE,
|
||||
viewers.isEmpty() ? null : viewers.get(0).player, 0.3
|
||||
);
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +76,9 @@ public class EffectManager {
|
|||
* Plays the configured sound at the first block's location.
|
||||
*/
|
||||
public void sound(List<Block> blocks) {
|
||||
if (!generator.profile.get("sound").asBoolean() || blocks.isEmpty()) return;
|
||||
if (!generator.profile.get("sound").asBoolean() || blocks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location loc = blocks.get(0).getLocation();
|
||||
generator.getPlayers().forEach(p ->
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ public class JumpCalculator {
|
|||
height = Math.max(-2, Math.min(2, height));
|
||||
distance = Math.max(1, Math.min(4, distance));
|
||||
|
||||
if (height > 0) distance = Math.max(distance - height, 1);
|
||||
if (height > 0) {
|
||||
distance = Math.max(distance - height, 1);
|
||||
}
|
||||
|
||||
// Calculate offset
|
||||
Vector offset = calculateJumpOffset(distance, height);
|
||||
|
|
|
|||
|
|
@ -115,13 +115,17 @@ public class BlockPlacer {
|
|||
|
||||
private void placeNormalBlock() {
|
||||
BlockData blockData = blockSelector.selectBlockData();
|
||||
if (blockData == null) return;
|
||||
if (blockData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Material mat = blockData.getMaterial();
|
||||
boolean tall = isTallMaterial(mat);
|
||||
|
||||
List<Block> blocks = tall ? selectBlocks(-1) : selectBlocks();
|
||||
if (blocks.isEmpty()) return;
|
||||
if (blocks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block selectedBlock = blocks.get(0);
|
||||
placeBlockData(selectedBlock, blockData);
|
||||
|
|
@ -139,7 +143,9 @@ public class BlockPlacer {
|
|||
boolean tall = isTallMaterial(mat);
|
||||
|
||||
List<Block> blocks = tall ? selectBlocks(-1) : selectBlocks();
|
||||
if (blocks.isEmpty()) return;
|
||||
if (blocks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block selectedBlock = blocks.get(0);
|
||||
placeBlockData(selectedBlock, specialBlockData);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,9 @@ public class BlockSelector {
|
|||
public Material getSlabMaterialFromCurrentStyle() {
|
||||
try {
|
||||
Style style = Registry.getStyle(generator.profile.get("style").value());
|
||||
if (style == null) return null;
|
||||
if (style == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to get a slab material from the style multiple times
|
||||
for (int i = 0; i < 20; i++) {
|
||||
|
|
|
|||
|
|
@ -28,12 +28,16 @@ public class GeneratorCleanup {
|
|||
*/
|
||||
public void cleanupDistantBlocks() {
|
||||
List<Block> history = generator.state.history;
|
||||
if (history.isEmpty()) return;
|
||||
if (history.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int minStandingIndex = Integer.MAX_VALUE;
|
||||
for (ParkourPlayer pp : generator.getPlayers()) {
|
||||
Block below = blockBelowPlayer(pp);
|
||||
if (below == null) continue;
|
||||
if (below == null) {
|
||||
continue;
|
||||
}
|
||||
int idx = indexOfBlock(history, below);
|
||||
if (idx >= 0) {
|
||||
minStandingIndex = Math.min(minStandingIndex, idx);
|
||||
|
|
@ -45,7 +49,9 @@ public class GeneratorCleanup {
|
|||
|
||||
int keepBehind = Math.max(0, Option.TRAIL_KEEP_BEHIND);
|
||||
int removeCount = minStandingIndex - keepBehind;
|
||||
if (removeCount <= 0) return;
|
||||
if (removeCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Block> head = new ArrayList<>(history.subList(0, removeCount));
|
||||
for (Block block : head) {
|
||||
|
|
@ -77,7 +83,9 @@ public class GeneratorCleanup {
|
|||
* Remove trail blocks behind player at specified index.
|
||||
*/
|
||||
public void removeTrailBlocks(int startIndex) {
|
||||
if (startIndex < 0 || startIndex >= generator.state.history.size()) return;
|
||||
if (startIndex < 0 || startIndex >= generator.state.history.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int endIndex = Math.min(startIndex + Option.BLOCK_CLEANUP_DISTANCE, generator.state.history.size());
|
||||
|
||||
|
|
@ -133,6 +141,7 @@ public class GeneratorCleanup {
|
|||
case SOUTH -> blockSpawn.add(0, 0, 6);
|
||||
case WEST -> blockSpawn.add(-6, 0, 0);
|
||||
case EAST -> blockSpawn.add(6, 0, 0);
|
||||
default -> {}
|
||||
}
|
||||
|
||||
generator.generateFirst(spawn, blockSpawn);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ public class PlayerInteractionHandler {
|
|||
/** Check if history contains a block by coordinates, not reference. */
|
||||
private static boolean historyContains(@NotNull List<Block> history, @NotNull Block block) {
|
||||
for (Block b : history) {
|
||||
if (isSameBlock(b, block)) return true;
|
||||
if (isSameBlock(b, block)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
package dev.loki.loparkour.ghost.core;
|
||||
import dev.loki.loparkour.ghost.core.GhostPlayer;
|
||||
import dev.loki.loparkour.ghost.model.GhostData;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
|
|
@ -11,7 +10,12 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Loads, saves, and spawns ghost runs per mode.
|
||||
|
|
@ -46,10 +50,14 @@ public class GhostManager {
|
|||
|
||||
public void loadGhosts(@NotNull String mode) {
|
||||
File modeFolder = new File(ghostFolder, sanitizeMode(mode));
|
||||
if (!modeFolder.exists()) return;
|
||||
if (!modeFolder.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File[] files = modeFolder.listFiles((dir, name) -> name.endsWith(".ghost"));
|
||||
if (files == null) return;
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<GhostData> ghosts = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
|
|
@ -77,7 +85,9 @@ public class GhostManager {
|
|||
|
||||
public void saveGhost(@NotNull String mode, @NotNull GhostData data) {
|
||||
File modeFolder = new File(ghostFolder, sanitizeMode(mode));
|
||||
if (!modeFolder.exists()) modeFolder.mkdirs();
|
||||
if (!modeFolder.exists()) {
|
||||
modeFolder.mkdirs();
|
||||
}
|
||||
|
||||
List<GhostData> ghosts = new ArrayList<>(ghostsByMode.getOrDefault(mode, new ArrayList<>()));
|
||||
ghosts.add(data);
|
||||
|
|
@ -88,7 +98,9 @@ public class GhostManager {
|
|||
GhostData evicted = ghosts.remove(ghosts.size() - 1);
|
||||
// File is named by UUID — always finds the right file regardless of name changes
|
||||
File evictedFile = ghostFile(modeFolder, evicted);
|
||||
if (evictedFile.exists()) evictedFile.delete();
|
||||
if (evictedFile.exists()) {
|
||||
evictedFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
ghostsByMode.put(mode, ghosts);
|
||||
|
|
@ -107,12 +119,16 @@ public class GhostManager {
|
|||
|
||||
public void spawnGhosts(@NotNull String mode, @NotNull Location startLocation,
|
||||
@NotNull World world) {
|
||||
if (!Config.CONFIG.getBoolean("ghost-mode.enabled")) return;
|
||||
if (!Config.CONFIG.getBoolean("ghost-mode.enabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
stopAllGhosts();
|
||||
|
||||
List<GhostData> ghosts = ghostsByMode.get(mode);
|
||||
if (ghosts == null || ghosts.isEmpty()) return;
|
||||
if (ghosts == null || ghosts.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int showTop = Math.min(Config.CONFIG.getInt("ghost-mode.show-top"), ghosts.size());
|
||||
for (int i = 0; i < showTop; i++) {
|
||||
|
|
@ -137,13 +153,17 @@ public class GhostManager {
|
|||
|
||||
public List<GhostData> getTopGhosts(@NotNull String mode, int count) {
|
||||
List<GhostData> ghosts = ghostsByMode.get(mode);
|
||||
if (ghosts == null || ghosts.isEmpty()) return Collections.emptyList();
|
||||
if (ghosts == null || ghosts.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(ghosts.subList(0, Math.min(count, ghosts.size())));
|
||||
}
|
||||
|
||||
public boolean shouldRecordGhost(@NotNull String mode, int score) {
|
||||
List<GhostData> ghosts = ghostsByMode.get(mode);
|
||||
if (ghosts == null || ghosts.size() < MAX_GHOSTS_PER_MODE) return true;
|
||||
if (ghosts == null || ghosts.size() < MAX_GHOSTS_PER_MODE) {
|
||||
return true;
|
||||
}
|
||||
return score > ghosts.get(ghosts.size() - 1).getScore();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ public class GhostPlayer {
|
|||
}
|
||||
|
||||
public void spawn(@NotNull Location startLocation) {
|
||||
if (data.getFrames().isEmpty()) return;
|
||||
if (data.getFrames().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
entity = (ArmorStand) world.spawnEntity(startLocation, EntityType.ARMOR_STAND);
|
||||
entity.setVisible(false);
|
||||
|
|
@ -61,17 +63,27 @@ public class GhostPlayer {
|
|||
|
||||
while (currentFrame < data.getFrames().size()) {
|
||||
GhostFrame frame = data.getFrames().get(currentFrame);
|
||||
if (frame.getTimestamp() > elapsed) break;
|
||||
if (frame.getTimestamp() > elapsed) {
|
||||
break;
|
||||
}
|
||||
entity.teleport(frame.toLocation(world));
|
||||
currentFrame++;
|
||||
}
|
||||
|
||||
if (currentFrame >= data.getFrames().size()) stop();
|
||||
if (currentFrame >= data.getFrames().size()) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (task != null) { task.cancel(); task = null; }
|
||||
if (entity != null) { entity.remove(); entity = null; }
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
if (entity != null) {
|
||||
entity.remove();
|
||||
entity = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActive() { return entity != null && entity.isValid(); }
|
||||
|
|
|
|||
|
|
@ -36,8 +36,12 @@ public class GhostRecorder {
|
|||
}
|
||||
|
||||
public void recordFrame(@NotNull Location currentLocation) {
|
||||
if (!recording) return;
|
||||
if (lastLocation.distance(currentLocation) < MIN_MOVEMENT) return;
|
||||
if (!recording) {
|
||||
return;
|
||||
}
|
||||
if (lastLocation.distance(currentLocation) < MIN_MOVEMENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
long timestamp = System.currentTimeMillis() - startTime;
|
||||
frames.add(new GhostFrame(timestamp, currentLocation.clone()));
|
||||
|
|
|
|||
|
|
@ -2,7 +2,14 @@ package dev.loki.loparkour.ghost.model;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,12 @@ import dev.loki.loparkour.leaderboard.model.Score;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Facade for leaderboard: CRUD operations with automatic sorting.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ import dev.loki.loparkour.leaderboard.model.Score;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Sorting logic for leaderboard scores.
|
||||
|
|
@ -60,9 +64,15 @@ public class LeaderboardSorter {
|
|||
String diff2 = two.getValue().difficulty();
|
||||
|
||||
// Handle "?" as lowest difficulty
|
||||
if ("?".equals(diff1) && "?".equals(diff2)) return 0;
|
||||
if ("?".equals(diff1)) return 1;
|
||||
if ("?".equals(diff2)) return -1;
|
||||
if ("?".equals(diff1) && "?".equals(diff2)) {
|
||||
return 0;
|
||||
}
|
||||
if ("?".equals(diff1)) {
|
||||
return 1;
|
||||
}
|
||||
if ("?".equals(diff2)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
return (int) Math.signum(Double.parseDouble(diff2) - Double.parseDouble(diff1));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package dev.loki.loparkour.leaderboard.persistence;
|
||||
import dev.loki.loparkour.leaderboard.model.Score;
|
||||
import dev.loki.loparkour.leaderboard.core.LeaderboardSorter;
|
||||
import dev.loki.loparkour.leaderboard.core.Leaderboard;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.config.core.Config;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ import org.bukkit.event.block.BlockPlaceEvent;
|
|||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
|
||||
|
|
@ -30,31 +34,45 @@ public class ParkourRestrictionListener implements Listener {
|
|||
|
||||
@EventHandler
|
||||
public void onChat(AsyncPlayerChatEvent event) {
|
||||
if (!Option.OPTIONS_ENABLED.get(ParkourOption.CHAT)) return;
|
||||
if (!Option.OPTIONS_ENABLED.get(ParkourOption.CHAT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
ParkourUser user = ParkourUser.getUser(player);
|
||||
if (user == null) return;
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Session session = user.session;
|
||||
if (session.isMuted(user)) return;
|
||||
if (session.isMuted(user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
switch (user.chatType) {
|
||||
case LOBBY_ONLY -> session.getUsers().forEach(u -> u.sendTranslated("settings.chat.formats.lobby", player.getName(), event.getMessage()));
|
||||
case PLAYERS_ONLY -> session.getPlayers().forEach(u -> u.sendTranslated("settings.chat.formats.players", player.getName(), event.getMessage()));
|
||||
default -> event.setCancelled(false);
|
||||
case LOBBY_ONLY -> session.getUsers().forEach(
|
||||
u -> u.sendTranslated("settings.chat.formats.lobby", player.getName(), event.getMessage()));
|
||||
case PLAYERS_ONLY -> session.getPlayers().forEach(
|
||||
u -> u.sendTranslated("settings.chat.formats.players", player.getName(), event.getMessage()));
|
||||
default -> event.setCancelled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onCommand(PlayerCommandPreprocessEvent event) {
|
||||
if (!Config.CONFIG.getBoolean("focus-mode.enabled")) return;
|
||||
if (!Config.CONFIG.getBoolean("focus-mode.enabled")) {
|
||||
return;
|
||||
}
|
||||
ParkourUser user = ParkourUser.getUser(event.getPlayer());
|
||||
if (user == null) return;
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String cmd = event.getMessage().toLowerCase();
|
||||
if (Config.CONFIG.getStringList("focus-mode.whitelist").stream().anyMatch(cmd::contains)) return;
|
||||
if (Config.CONFIG.getStringList("focus-mode.whitelist").stream().anyMatch(cmd::contains)) {
|
||||
return;
|
||||
}
|
||||
|
||||
user.sendTranslated("other.no_do");
|
||||
event.setCancelled(true);
|
||||
|
|
@ -64,7 +82,9 @@ public class ParkourRestrictionListener implements Listener {
|
|||
public void onInteract(PlayerInteractEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
ParkourPlayer pp = ParkourPlayer.getPlayer(player);
|
||||
if (pp == null) return;
|
||||
if (pp == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Block container right-click
|
||||
boolean isContainer = event.getClickedBlock() != null && switch (event.getClickedBlock().getType()) {
|
||||
|
|
@ -81,47 +101,75 @@ public class ParkourRestrictionListener implements Listener {
|
|||
boolean isRightClick = (event.getAction() == org.bukkit.event.block.Action.RIGHT_CLICK_AIR
|
||||
|| event.getAction() == org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK)
|
||||
&& event.getHand() == org.bukkit.inventory.EquipmentSlot.HAND;
|
||||
if (!isRightClick) return;
|
||||
if (!isRightClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack held = heldItem(player);
|
||||
event.setCancelled(true);
|
||||
|
||||
if (matchesLocaleHotbar(player, "play.item", held)) Menus.PLAY.open(player);
|
||||
else if (matchesLocaleHotbar(player, "community.item", held)) Menus.COMMUNITY.open(player);
|
||||
else if (matchesLocaleHotbar(player, "settings.item", held)) Menus.SETTINGS.open(player);
|
||||
else if (matchesLocaleHotbar(player, "lobby.item", held)) Menus.LOBBY.open(player);
|
||||
else if (matchesLocaleHotbar(player, "other.quit", held)) ParkourUser.leave(player);
|
||||
else if (!Config.CONFIG.getBoolean("options.disable-inventory-blocks")) event.setCancelled(false);
|
||||
if (matchesLocaleHotbar(player, "play.item", held)) {
|
||||
Menus.PLAY.open(player);
|
||||
} else if (matchesLocaleHotbar(player, "community.item", held)) {
|
||||
Menus.COMMUNITY.open(player);
|
||||
} else if (matchesLocaleHotbar(player, "settings.item", held)) {
|
||||
Menus.SETTINGS.open(player);
|
||||
} else if (matchesLocaleHotbar(player, "lobby.item", held)) {
|
||||
Menus.LOBBY.open(player);
|
||||
} else if (matchesLocaleHotbar(player, "other.quit", held)) {
|
||||
ParkourUser.leave(player);
|
||||
} else if (!Config.CONFIG.getBoolean("options.disable-inventory-blocks")) {
|
||||
event.setCancelled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (!(event.getWhoClicked() instanceof Player player)) return;
|
||||
if (event.getInventory().getType() == InventoryType.CHEST) return; // LoLib GUI
|
||||
if (event.getInventory().getType() == InventoryType.CRAFTING) return; // own inv
|
||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
if (event.getInventory().getType() == InventoryType.CHEST) {
|
||||
return; // LoLib GUI
|
||||
}
|
||||
if (event.getInventory().getType() == InventoryType.CRAFTING) {
|
||||
return; // own inv
|
||||
}
|
||||
restrict(player, event);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDrop(PlayerDropItemEvent event) { restrict(event.getPlayer(), event); }
|
||||
public void onDrop(PlayerDropItemEvent event) {
|
||||
restrict(event.getPlayer(), event);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlace(BlockPlaceEvent event) { restrict(event.getPlayer(), event); }
|
||||
public void onPlace(BlockPlaceEvent event) {
|
||||
restrict(event.getPlayer(), event);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBreak(BlockBreakEvent event) { restrict(event.getPlayer(), event); }
|
||||
public void onBreak(BlockBreakEvent event) {
|
||||
restrict(event.getPlayer(), event);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageEvent event) {
|
||||
if (event.getEntity() instanceof Player p) restrict(p, event);
|
||||
if (event.getEntity() instanceof Player p) {
|
||||
restrict(p, event);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onSpectate(PlayerTeleportEvent event) {
|
||||
if (event.getCause() == PlayerTeleportEvent.TeleportCause.SPECTATE)
|
||||
if (event.getCause() == PlayerTeleportEvent.TeleportCause.SPECTATE) {
|
||||
restrict(event.getPlayer(), event);
|
||||
}
|
||||
}
|
||||
|
||||
private void restrict(Player player, Cancellable event) {
|
||||
if (ParkourUser.isUser(player)) event.setCancelled(true);
|
||||
if (ParkourUser.isUser(player)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack heldItem(Player player) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ public class PlayerConnectionListener implements Listener {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!player.getWorld().equals(World.getWorld())) return;
|
||||
if (!player.getWorld().equals(World.getWorld())) {
|
||||
return;
|
||||
}
|
||||
|
||||
org.bukkit.World fallback = Bukkit.getWorld(Config.CONFIG.getString("world.fall-back"));
|
||||
if (fallback != null) {
|
||||
|
|
@ -52,7 +54,9 @@ public class PlayerConnectionListener implements Listener {
|
|||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
ParkourUser user = ParkourUser.getUser(event.getPlayer());
|
||||
if (user == null) return;
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
ParkourUser.unregister(user, true, false, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,10 @@ public class SingleLeaderboardMenu extends LPMenu {
|
|||
OfflinePlayer op = org.bukkit.Bukkit.getOfflinePlayer(entry.getKey());
|
||||
if (op.getName() != null && !op.getName().startsWith(".")) {
|
||||
SkullMeta meta = (SkullMeta) skull.getItemMeta();
|
||||
if (meta != null) { meta.setOwningPlayer(op); skull.setItemMeta(meta); }
|
||||
if (meta != null) {
|
||||
meta.setOwningPlayer(op);
|
||||
skull.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ import org.jetbrains.annotations.NotNull;
|
|||
*
|
||||
* Real LoLib API:
|
||||
* InventoryGUI.create().title(String).rows(n).fill(item).setItem(slot, item, Consumer<InventoryClickEvent>).open(player)
|
||||
* ScrollableGUI.create().title(String).rows(n).addItem(item, Consumer<InventoryClickEvent>).scrollUpButton(item,slot).scrollDownButton(item,slot).open(player)
|
||||
* ScrollableGUI.create().title(String).rows(n).addItem(item, Consumer<InventoryClickEvent>)
|
||||
* .scrollUpButton(item,slot).scrollDownButton(item,slot).open(player)
|
||||
*
|
||||
* cancelAllClicks = true by default — items cannot be taken out automatically.
|
||||
* Handlers receive Consumer<InventoryClickEvent>, event is already cancelled before handler runs.
|
||||
|
|
@ -81,7 +82,9 @@ public abstract class LPMenu {
|
|||
|
||||
protected int[] distributeEvenly(int count, int start, int end) {
|
||||
int[] result = new int[count];
|
||||
if (count == 0) return result;
|
||||
if (count == 0) {
|
||||
return result;
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = start + Math.round((float) i * (end - start) / Math.max(count - 1, 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ import dev.loki.loparkour.menu.settings.LangMenu;
|
|||
import dev.loki.loparkour.menu.settings.ParkourSettingsMenu;
|
||||
import dev.loki.loparkour.menu.settings.SettingsMenu;
|
||||
|
||||
public class Menus {
|
||||
public final class Menus {
|
||||
|
||||
private Menus() {
|
||||
}
|
||||
|
||||
// main
|
||||
public static MainMenu MAIN = new MainMenu();
|
||||
|
|
|
|||
|
|
@ -45,7 +45,10 @@ public class PlayerManagementMenu extends LPMenu {
|
|||
if (!ParkourUser.isBedrockPlayer(other.player)
|
||||
&& other.getName() != null && !other.getName().startsWith(".")) {
|
||||
SkullMeta meta = (SkullMeta) skull.getItemMeta();
|
||||
if (meta != null) { meta.setOwningPlayer(other.player); skull.setItemMeta(meta); }
|
||||
if (meta != null) {
|
||||
meta.setOwningPlayer(other.player);
|
||||
skull.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
|
||||
boolean muted = session.isMuted(other);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,10 @@ public class SpectatorMenu extends LPMenu {
|
|||
if (!ParkourUser.isBedrockPlayer(player)
|
||||
&& pp.getName() != null && !pp.getName().startsWith(".")) {
|
||||
SkullMeta meta = (SkullMeta) skull.getItemMeta();
|
||||
if (meta != null) { meta.setOwningPlayer(pp.player); skull.setItemMeta(meta); }
|
||||
if (meta != null) {
|
||||
meta.setOwningPlayer(pp.player);
|
||||
skull.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
sessions.add(session);
|
||||
items.add(skull);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class LangMenu extends LPMenu {
|
|||
}
|
||||
gui = gui.setItem(10 + i, item, e -> {
|
||||
pp.locale = lang;
|
||||
pp._locale = lang;
|
||||
pp.locale = lang;
|
||||
pp.updateHotbar(); // Update hotbar with new language
|
||||
Menus.SETTINGS.open(player);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -158,7 +158,10 @@ public class ParkourSettingsMenu extends LPMenu {
|
|||
|
||||
ItemStack item = new ItemStack(style.getNext());
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) { meta.setDisplayName(ColorUtil.color("&#A020F0" + name)); item.setItemMeta(meta); }
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(ColorUtil.color("&#A020F0" + name));
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
|
||||
final Style s = style;
|
||||
gui = gui.setItem(slot++, item, e -> {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,18 @@
|
|||
package dev.loki.loparkour.mode.base;
|
||||
|
||||
import dev.loki.loparkour.api.core.Registry;
|
||||
import dev.loki.loparkour.mode.impl.*;
|
||||
import dev.loki.loparkour.mode.impl.CoopMode;
|
||||
import dev.loki.loparkour.mode.impl.DefaultMode;
|
||||
import dev.loki.loparkour.mode.impl.GravityShiftMode;
|
||||
import dev.loki.loparkour.mode.impl.InvisibleBarrierMode;
|
||||
import dev.loki.loparkour.mode.impl.RaceMode;
|
||||
import dev.loki.loparkour.mode.impl.SpectatorMode;
|
||||
import dev.loki.loparkour.mode.impl.SpeedrunMode;
|
||||
|
||||
public class Modes {
|
||||
public final class Modes {
|
||||
|
||||
private Modes() {
|
||||
}
|
||||
|
||||
public static DefaultMode DEFAULT;
|
||||
public static SpectatorMode SPECTATOR;
|
||||
|
|
|
|||
|
|
@ -93,7 +93,9 @@ public class CoopMode implements MultiMode {
|
|||
return;
|
||||
}
|
||||
|
||||
if (session.generator == null) return;
|
||||
if (session.generator == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register the joining player into the existing session
|
||||
ParkourPlayer pp = ParkourUser.register(joiningPlayer, session);
|
||||
|
|
@ -132,7 +134,7 @@ public class CoopMode implements MultiMode {
|
|||
/** Individual block contributions per player UUID. */
|
||||
private final Map<UUID, Integer> contributions = new HashMap<>();
|
||||
|
||||
public CoopGenerator(@NotNull Session session) {
|
||||
CoopGenerator(@NotNull Session session) {
|
||||
super(session);
|
||||
session.getPlayers().forEach(pp -> contributions.put(pp.getUUID(), 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import dev.loki.loparkour.config.locale.Locales;
|
|||
import dev.loki.loparkour.generator.core.coordinator.ParkourGenerator;
|
||||
import dev.loki.loparkour.mode.base.Mode;
|
||||
import dev.loki.loparkour.mode.base.ModeMessages;
|
||||
import dev.loki.loparkour.util.item.Item;
|
||||
import dev.loki.loparkour.leaderboard.core.Leaderboard;
|
||||
import dev.loki.loparkour.player.core.ParkourPlayer;
|
||||
import dev.loki.loparkour.session.core.Session;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,12 @@ import org.bukkit.potion.PotionEffectType;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Gravity Shift Mode — random potion effects applied every N jumps.
|
||||
|
|
@ -67,7 +72,7 @@ public class GravityShiftMode implements Mode {
|
|||
private final Random random;
|
||||
private final Map<UUID, Integer> jumpCounts;
|
||||
|
||||
public GravityShiftGenerator(@NotNull Session session) {
|
||||
GravityShiftGenerator(@NotNull Session session) {
|
||||
super(session);
|
||||
this.random = new Random();
|
||||
this.jumpCounts = new HashMap<>();
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public class InvisibleBarrierMode implements Mode {
|
|||
private final Map<Location, Particle.DustOptions> blockColors = new HashMap<>();
|
||||
private int particleTick = 0;
|
||||
|
||||
public BarrierGenerator(@NotNull Session session) {
|
||||
BarrierGenerator(@NotNull Session session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
|
|
@ -114,13 +114,17 @@ public class InvisibleBarrierMode implements Mode {
|
|||
}
|
||||
|
||||
private void convertLastBlockToBarrier() {
|
||||
if (state.history.isEmpty()) return;
|
||||
if (state.history.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
convertBlockToBarrier(state.history.get(state.history.size() - 1));
|
||||
}
|
||||
|
||||
private void convertBlockToBarrier(@NotNull Block block) {
|
||||
Location loc = block.getLocation();
|
||||
if (block.getType() == Material.BARRIER) return;
|
||||
if (block.getType() == Material.BARRIER) {
|
||||
return;
|
||||
}
|
||||
block.setType(Material.BARRIER, false);
|
||||
activeBarriers.add(loc);
|
||||
Color color = Color.fromRGB(random.nextInt(256), random.nextInt(256), random.nextInt(256));
|
||||
|
|
@ -128,7 +132,9 @@ public class InvisibleBarrierMode implements Mode {
|
|||
}
|
||||
|
||||
private void renderOutlines() {
|
||||
if (activeBarriers.isEmpty()) return;
|
||||
if (activeBarriers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Self-clean invalid entries
|
||||
Iterator<Map.Entry<Location, Particle.DustOptions>> it = blockColors.entrySet().iterator();
|
||||
|
|
@ -145,53 +151,70 @@ public class InvisibleBarrierMode implements Mode {
|
|||
Location playerLoc = player.getLocation();
|
||||
|
||||
for (Location loc : activeBarriers) {
|
||||
if (loc.getWorld() != playerLoc.getWorld()) continue;
|
||||
if (loc.distanceSquared(playerLoc) > RENDER_DISTANCE * RENDER_DISTANCE) continue;
|
||||
if (loc.getWorld() != playerLoc.getWorld()) {
|
||||
continue;
|
||||
}
|
||||
if (loc.distanceSquared(playerLoc) > RENDER_DISTANCE * RENDER_DISTANCE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Particle.DustOptions options = blockColors.get(loc);
|
||||
if (options == null) continue;
|
||||
if (options == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
drawBlockOutline(player, loc, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record Point(double x, double y, double z) {}
|
||||
|
||||
private void drawBlockOutline(@NotNull Player player, @NotNull Location loc, @NotNull Particle.DustOptions options) {
|
||||
double x = loc.getX();
|
||||
double y = loc.getY();
|
||||
double z = loc.getZ();
|
||||
Point p = new Point(x, y, z);
|
||||
Point q = new Point(x + 1, y, z);
|
||||
Point r = new Point(x + 1, y, z + 1);
|
||||
Point s = new Point(x, y, z + 1);
|
||||
|
||||
// Bottom edges (y offset = 0)
|
||||
drawEdge(player, x, y, z, x + 1, y, z, options);
|
||||
drawEdge(player, x + 1, y, z, x + 1, y, z + 1, options);
|
||||
drawEdge(player, x + 1, y, z + 1, x, y, z + 1, options);
|
||||
drawEdge(player, x, y, z + 1, x, y, z, options);
|
||||
drawEdge(player, p, q, options);
|
||||
drawEdge(player, q, r, options);
|
||||
drawEdge(player, r, s, options);
|
||||
drawEdge(player, s, p, options);
|
||||
|
||||
// Top edges (y offset = 1)
|
||||
drawEdge(player, x, y + 1, z, x + 1, y + 1, z, options);
|
||||
drawEdge(player, x + 1, y + 1, z, x + 1, y + 1, z + 1, options);
|
||||
drawEdge(player, x + 1, y + 1, z + 1, x, y + 1, z + 1, options);
|
||||
drawEdge(player, x, y + 1, z + 1, x, y + 1, z, options);
|
||||
Point pt = new Point(x, y + 1, z);
|
||||
Point qt = new Point(x + 1, y + 1, z);
|
||||
Point rt = new Point(x + 1, y + 1, z + 1);
|
||||
Point st = new Point(x, y + 1, z + 1);
|
||||
drawEdge(player, pt, qt, options);
|
||||
drawEdge(player, qt, rt, options);
|
||||
drawEdge(player, rt, st, options);
|
||||
drawEdge(player, st, pt, options);
|
||||
|
||||
// Vertical edges
|
||||
drawEdge(player, x, y, z, x, y + 1, z, options);
|
||||
drawEdge(player, x + 1, y, z, x + 1, y + 1, z, options);
|
||||
drawEdge(player, x + 1, y, z + 1, x + 1, y + 1, z + 1, options);
|
||||
drawEdge(player, x, y, z + 1, x, y + 1, z + 1, options);
|
||||
drawEdge(player, p, pt, options);
|
||||
drawEdge(player, q, qt, options);
|
||||
drawEdge(player, r, rt, options);
|
||||
drawEdge(player, s, st, options);
|
||||
}
|
||||
|
||||
private void drawEdge(@NotNull Player player, double x1, double y1, double z1, double x2, double y2, double z2, @NotNull Particle.DustOptions options) {
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double dz = z2 - z1;
|
||||
private void drawEdge(@NotNull Player player, @NotNull Point start, @NotNull Point end,
|
||||
@NotNull Particle.DustOptions options) {
|
||||
double dx = end.x - start.x;
|
||||
double dy = end.y - start.y;
|
||||
double dz = end.z - start.z;
|
||||
double length = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
int steps = Math.max(1, (int) (length / PARTICLE_STEP));
|
||||
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
double t = (double) i / steps;
|
||||
double px = x1 + dx * t;
|
||||
double py = y1 + dy * t;
|
||||
double pz = z1 + dz * t;
|
||||
double px = start.x + dx * t;
|
||||
double py = start.y + dy * t;
|
||||
double pz = start.z + dz * t;
|
||||
player.spawnParticle(Particle.REDSTONE, px, py, pz, 1, options);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ public class RaceMode implements Mode {
|
|||
private final int targetScore;
|
||||
private boolean raceFinished = false;
|
||||
|
||||
public RaceGenerator(@NotNull Session session) {
|
||||
RaceGenerator(@NotNull Session session) {
|
||||
super(session);
|
||||
this.targetScore = Config.CONFIG.getInt("modes.race.target-score");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package dev.loki.loparkour.mode.impl;
|
|||
import dev.loki.loparkour.mode.base.ModeMessages;
|
||||
import dev.loki.loparkour.mode.base.Mode;
|
||||
|
||||
import dev.loki.loparkour.config.core.Config;
|
||||
import dev.loki.loparkour.config.locale.Locales;
|
||||
import dev.loki.loparkour.leaderboard.core.Leaderboard;
|
||||
import dev.loki.loparkour.menu.core.Menus;
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ public class SpeedrunMode implements Mode {
|
|||
/** Tracks scheduled tasks per block. Key = block, value = [warningTask, removalTask]. */
|
||||
private final Map<Block, ScheduledTask[]> scheduledTasks = new HashMap<>();
|
||||
|
||||
public SpeedrunGenerator(@NotNull Session session) {
|
||||
SpeedrunGenerator(@NotNull Session session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
|
|
@ -100,11 +100,17 @@ public class SpeedrunMode implements Mode {
|
|||
// The block the player just landed on is the previous-to-last in history
|
||||
// (history.size()-1 is the leading block, size()-2 is where player stands)
|
||||
int histSize = state.history.size();
|
||||
if (histSize < 2) return;
|
||||
if (histSize < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block stepped = state.history.get(histSize - 2);
|
||||
if (stepped.getType() == Material.AIR) return;
|
||||
if (scheduledTasks.containsKey(stepped)) return; // already scheduled
|
||||
if (stepped.getType() == Material.AIR) {
|
||||
return;
|
||||
}
|
||||
if (scheduledTasks.containsKey(stepped)) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleBlockRemoval(stepped);
|
||||
}
|
||||
|
|
@ -144,7 +150,9 @@ public class SpeedrunMode implements Mode {
|
|||
// Cancel every pending warning and removal task
|
||||
scheduledTasks.values().forEach(tasks -> {
|
||||
for (ScheduledTask t : tasks) {
|
||||
if (t != null) t.cancel();
|
||||
if (t != null) {
|
||||
t.cancel();
|
||||
}
|
||||
}
|
||||
});
|
||||
scheduledTasks.clear();
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@ package dev.loki.loparkour.player.core;
|
|||
import com.google.gson.annotations.Expose;
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.config.core.Config;
|
||||
import dev.loki.loparkour.config.options.Option;
|
||||
import dev.loki.loparkour.generator.core.coordinator.ParkourGenerator;
|
||||
import dev.loki.loparkour.generator.core.model.Profile;
|
||||
import dev.loki.loparkour.menu.core.ParkourOption;
|
||||
import dev.loki.loparkour.config.locale.Locales;
|
||||
import dev.loki.loparkour.mode.base.MultiMode;
|
||||
import dev.loki.loparkour.player.data.PreviousData;
|
||||
import dev.loki.loparkour.player.service.ParkourHotbar;
|
||||
|
|
@ -24,7 +22,10 @@ import org.bukkit.potion.PotionEffect;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
|
|
@ -48,7 +49,7 @@ public class ParkourPlayer extends ParkourUser {
|
|||
public @Expose Boolean showScoreboard;
|
||||
public @Expose Integer selectedTime;
|
||||
public @Expose String style;
|
||||
public @Expose String _locale;
|
||||
public @Expose String locale;
|
||||
public @Expose List<String> collectedRewards;
|
||||
/**
|
||||
* Creates a new instance of a ParkourPlayer<br>
|
||||
|
|
@ -57,8 +58,6 @@ public class ParkourPlayer extends ParkourUser {
|
|||
public ParkourPlayer(@NotNull Player player, @NotNull Session session, @Nullable PreviousData previousData) {
|
||||
super(player, session, previousData);
|
||||
|
||||
this._locale = locale;
|
||||
|
||||
// generic player settings
|
||||
player.setFlying(false);
|
||||
player.setAllowFlight(false);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package dev.loki.loparkour.player.core;
|
||||
import dev.loki.loparkour.player.service.UserRegistry;
|
||||
import dev.loki.loparkour.player.service.ScoreboardManager;
|
||||
import dev.loki.loparkour.player.core.ParkourPlayer;
|
||||
|
||||
import dev.loki.loparkour.config.locale.Locales;
|
||||
import dev.loki.loparkour.config.options.Option;
|
||||
|
|
@ -112,9 +111,17 @@ public abstract class ParkourUser {
|
|||
}
|
||||
}
|
||||
|
||||
public UUID getUUID() { return player.getUniqueId(); }
|
||||
public Location getLocation() { return player.getLocation(); }
|
||||
public String getName() { return player.getName(); }
|
||||
public UUID getUUID() {
|
||||
return player.getUniqueId();
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return player.getLocation();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return player.getName();
|
||||
}
|
||||
|
||||
public static boolean isBedrockPlayer(Player player) {
|
||||
return Bukkit.getPluginManager().isPluginEnabled("floodgate") && FloodgateHook.isBedrockPlayer(player);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ import org.bukkit.inventory.ItemStack;
|
|||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
|
@ -95,7 +98,9 @@ public class InventoryData {
|
|||
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());
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while reading inventory of %s from file %s".formatted(player.getName(), file.getName())
|
||||
+ " - " + ex.getMessage());
|
||||
onFinish.accept(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -132,7 +137,9 @@ public class InventoryData {
|
|||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
} catch (IOException ex) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while creating file to save inventory of %s to file %s".formatted(player.getName(), file.getName()) + " - " + ex.getMessage());
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while creating file to save inventory of %s to file %s".formatted(player.getName(), file.getName())
|
||||
+ " - " + ex.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -143,7 +150,9 @@ public class InventoryData {
|
|||
}
|
||||
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());
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while saving inventory of %s to file %s".formatted(player.getName(), file.getName())
|
||||
+ " - " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ public class PreviousData {
|
|||
public void apply(Player player, boolean urgent) {
|
||||
var to = Config.CONFIG.getBoolean("bungeecord.go-back-enabled") ? Option.GO_BACK_LOC : location;
|
||||
|
||||
if (!urgent)
|
||||
if (!urgent) {
|
||||
PaperLib.teleportAsync(player, to).thenRun(() -> apply(player));
|
||||
else {
|
||||
} else {
|
||||
player.teleport(to);
|
||||
|
||||
apply(player);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ import org.bukkit.plugin.messaging.ChannelNotRegisteredException;
|
|||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
class BungeeUtil {
|
||||
final class BungeeUtil {
|
||||
|
||||
private BungeeUtil() {
|
||||
}
|
||||
|
||||
public static void sendPlayerToServer(Player player, String server) {
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ import java.util.function.BiConsumer;
|
|||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public class PlayerSettingsManager {
|
||||
public final class PlayerSettingsManager {
|
||||
|
||||
private PlayerSettingsManager() {
|
||||
}
|
||||
|
||||
private static final Map<String, OptionContainer> COLUMN_MAPPINGS = new HashMap<>();
|
||||
|
||||
|
|
@ -41,7 +44,6 @@ public class PlayerSettingsManager {
|
|||
if ("true".equals(v) || "false".equals(v)) {
|
||||
sanitized = Option.OPTIONS_DEFAULTS.getOrDefault(ParkourOption.LANG, "en");
|
||||
}
|
||||
p._locale = sanitized;
|
||||
p.locale = sanitized;
|
||||
}));
|
||||
COLUMN_MAPPINGS.put("schematicDifficulty", new OptionContainer(ParkourOption.SCHEMATICS, (p, v) ->
|
||||
|
|
@ -73,7 +75,7 @@ public class PlayerSettingsManager {
|
|||
}
|
||||
|
||||
private static boolean parseBoolean(String string) {
|
||||
return string == null || string.equals("1") || string.equalsIgnoreCase("true");
|
||||
return string == null || "1".equals(string) || "true".equalsIgnoreCase(string);
|
||||
}
|
||||
|
||||
private static int defaultBlockLead() {
|
||||
|
|
|
|||
|
|
@ -53,13 +53,17 @@ public class ScoreboardManager {
|
|||
}
|
||||
|
||||
private Score getTopScore(Leaderboard leaderboard) {
|
||||
if (leaderboard == null) return createDefaultScore();
|
||||
if (leaderboard == null) {
|
||||
return createDefaultScore();
|
||||
}
|
||||
Score score = leaderboard.getScoreAtRank(1);
|
||||
return score != null ? score : createDefaultScore();
|
||||
}
|
||||
|
||||
private Score getHighScore(Leaderboard leaderboard) {
|
||||
if (leaderboard == null) return createDefaultScore();
|
||||
if (leaderboard == null) {
|
||||
return createDefaultScore();
|
||||
}
|
||||
Score score = leaderboard.get(playerUUID);
|
||||
return score != null ? score : createDefaultScore();
|
||||
}
|
||||
|
|
@ -83,7 +87,9 @@ public class ScoreboardManager {
|
|||
|
||||
private void updateLines(Score top, Score high, ParkourGenerator generator) {
|
||||
Objective obj = board.getObjective("lp_sidebar");
|
||||
if (obj == null) return;
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> lines = Locales.getStringList(locale, "scoreboard.lines").stream()
|
||||
.map(line -> replacePlaceholders(line, top, high, generator))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
package dev.loki.loparkour.player.service;
|
||||
import dev.loki.loparkour.player.spectator.ParkourSpectator;
|
||||
import dev.loki.loparkour.player.core.ParkourUser;
|
||||
import dev.loki.loparkour.player.core.ParkourPlayer;
|
||||
|
||||
|
|
@ -25,7 +24,10 @@ import java.util.stream.Collectors;
|
|||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public class UserRegistry {
|
||||
public final class UserRegistry {
|
||||
|
||||
private UserRegistry() {
|
||||
}
|
||||
|
||||
private static int joinCount = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ public class ParkourSpectator extends ParkourUser {
|
|||
}
|
||||
|
||||
closest = session.getPlayers().stream()
|
||||
.min(Comparator.comparing(other -> other.getLocation().distanceSquared(player.getLocation()))) // x or x^2 doesn't matter in getting smallest
|
||||
.min(Comparator.comparing(
|
||||
other -> other.getLocation().distanceSquared(player.getLocation()))) // x or x^2 doesn't matter in getting smallest
|
||||
.orElse(closest);
|
||||
}, 1, 10);
|
||||
}
|
||||
|
|
@ -71,7 +72,8 @@ public class ParkourSpectator extends ParkourUser {
|
|||
*/
|
||||
@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"))));
|
||||
String actionBar = ColorUtil.color(Locales.getString(player, "play.spectator.action_bar"));
|
||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(actionBar));
|
||||
player.setGameMode(GameMode.SPECTATOR);
|
||||
updateScoreboard(session.generator);
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,9 @@ public record Reward(@NotNull String string) {
|
|||
try {
|
||||
VaultHook.deposit(player.player, Double.parseDouble(string));
|
||||
} catch (NumberFormatException ex) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while trying to process Vault reward - check your rewards file for incorrect numbers - " + ex.getMessage());
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while trying to process Vault reward - check your rewards file for incorrect numbers - "
|
||||
+ ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), string);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ import java.util.Map;
|
|||
*/
|
||||
public class Rewards {
|
||||
|
||||
private Rewards() {
|
||||
}
|
||||
|
||||
public static boolean REWARDS_ENABLED;
|
||||
|
||||
/**
|
||||
|
|
@ -71,13 +74,17 @@ public class Rewards {
|
|||
int value = Integer.parseInt(score);
|
||||
|
||||
if (value < 1) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while trying to read rewards - check the rewards file for incorrect numbers - " + value + " is not a valid score");
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while trying to read rewards - check the rewards file for incorrect numbers - "
|
||||
+ value + " is not a valid score");
|
||||
continue;
|
||||
}
|
||||
|
||||
rewardMap.put(value, rewardStrings);
|
||||
} catch (NumberFormatException ex) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while trying to read rewards - check the rewards file for incorrect numbers - " + ex.getMessage());
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while trying to read rewards - check the rewards file for incorrect numbers - "
|
||||
+ ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import java.io.File;
|
|||
*/
|
||||
public class Schematics {
|
||||
|
||||
private Schematics() {
|
||||
}
|
||||
|
||||
private static final File FOLDER = LoParkour.getInFolder("schematics");
|
||||
|
||||
public static void init() {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ import java.util.UUID;
|
|||
*/
|
||||
public class Storage {
|
||||
|
||||
private Storage() {
|
||||
}
|
||||
|
||||
public static void init(String mode) {
|
||||
if (Option.SQL) {
|
||||
StorageSQL.init(mode);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ import java.util.UUID;
|
|||
*/
|
||||
public class StorageDisk {
|
||||
|
||||
private StorageDisk() {
|
||||
}
|
||||
|
||||
public static @NotNull Map<UUID, Score> readScores(@NotNull String mode) {
|
||||
File file = getLeaderboardFile(mode);
|
||||
|
||||
|
|
@ -43,7 +46,8 @@ public class StorageDisk {
|
|||
|
||||
return scores;
|
||||
} catch (IOException ex) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while trying to read leaderboard file %s".formatted(mode) + " - " + ex.getMessage());
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while trying to read leaderboard file %s".formatted(mode) + " - " + ex.getMessage());
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +86,8 @@ public class StorageDisk {
|
|||
ParkourPlayer from = LoParkour.getGson().fromJson(reader, ParkourPlayer.class);
|
||||
|
||||
if (from == null) {
|
||||
LoParkour.getPlugin().getLogger().warning("Player data file for %s is empty or corrupted, using defaults".formatted(player.getName()));
|
||||
LoParkour.getPlugin().getLogger().warning(
|
||||
"Player data file for %s is empty or corrupted, using defaults".formatted(player.getName()));
|
||||
player.setSettings(new HashMap<>());
|
||||
return;
|
||||
}
|
||||
|
|
@ -99,7 +104,7 @@ public class StorageDisk {
|
|||
settings.put("collectedRewards", from.collectedRewards);
|
||||
|
||||
// Sanitize legacy Boolean locale values
|
||||
String locale = from._locale;
|
||||
String locale = from.locale;
|
||||
if (locale == null || "true".equals(locale) || "false".equals(locale) || "1".equals(locale) || "0".equals(locale)) {
|
||||
locale = "en";
|
||||
}
|
||||
|
|
@ -109,7 +114,8 @@ public class StorageDisk {
|
|||
|
||||
player.setSettings(settings);
|
||||
} catch (IOException ex) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while trying to read disk data of %s".formatted(player.getName()) + " - " + ex.getMessage());
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while trying to read disk data of %s".formatted(player.getName()) + " - " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +128,9 @@ public class StorageDisk {
|
|||
LoParkour.getGson().toJson(player, writer);
|
||||
writer.flush();
|
||||
} catch (IOException ex) {
|
||||
LoParkour.getPlugin().getLogger().severe("Error while trying to write disk data of %s to file %s".formatted(player.getName(), file) + " - " + ex.getMessage());
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
"Error while trying to write disk data of %s to file %s".formatted(player.getName(), file)
|
||||
+ " - " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ import java.util.UUID;
|
|||
* Maps data between Java objects and SQL result sets.
|
||||
*/
|
||||
public class SQLDataMapper {
|
||||
|
||||
|
||||
private SQLDataMapper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Map ResultSet to Score objects.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ import org.jetbrains.annotations.NotNull;
|
|||
* Builds SQL queries for parkour storage operations.
|
||||
*/
|
||||
public class SQLQueryBuilder {
|
||||
|
||||
|
||||
private SQLQueryBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build CREATE TABLE query for scores.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ class SQLQueryExecutor {
|
|||
connectionManager.validateConnection();
|
||||
try (Connection conn = connectionManager.getConnection();
|
||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
if (stmt != null) stmt.executeUpdate();
|
||||
if (stmt != null) {
|
||||
stmt.executeUpdate();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
if (!suppressErrors) {
|
||||
LoParkour.getPlugin().getLogger().severe(
|
||||
|
|
@ -62,7 +64,9 @@ class SQLQueryExecutor {
|
|||
connectionManager.validateConnection();
|
||||
try (Connection conn = connectionManager.getConnection();
|
||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
if (stmt == null) return;
|
||||
if (stmt == null) {
|
||||
return;
|
||||
}
|
||||
bindParams(stmt, params);
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException ex) {
|
||||
|
|
|
|||
|
|
@ -17,8 +17,11 @@ import java.util.logging.Logger;
|
|||
* Coordinates connection management, query building, and data mapping.
|
||||
*/
|
||||
public class StorageSQL {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(StorageSQL.class.getName());
|
||||
|
||||
private StorageSQL() {
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(StorageSQL.class.getName());
|
||||
private static SQLConnectionManager connectionManager;
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +46,7 @@ public class StorageSQL {
|
|||
if (isConnected()) {
|
||||
callback.run();
|
||||
} else {
|
||||
logger.warning("Database not connected, skipping operation");
|
||||
LOGGER.warning("Database not connected, skipping operation");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,9 +70,9 @@ public class StorageSQL {
|
|||
|
||||
createTables(mode);
|
||||
|
||||
logger.info("Database initialized successfully for mode: " + mode);
|
||||
LOGGER.info("Database initialized successfully for mode: " + mode);
|
||||
} catch (SQLException e) {
|
||||
logger.severe("Failed to initialize database: " + e.getMessage());
|
||||
LOGGER.severe("Failed to initialize database: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +95,7 @@ public class StorageSQL {
|
|||
return SQLDataMapper.mapScores(rs);
|
||||
|
||||
} catch (SQLException e) {
|
||||
logger.severe("Failed to read scores for mode " + mode + ": " + e.getMessage());
|
||||
LOGGER.severe("Failed to read scores for mode " + mode + ": " + e.getMessage());
|
||||
return Map.of();
|
||||
}
|
||||
}
|
||||
|
|
@ -117,10 +120,10 @@ public class StorageSQL {
|
|||
}
|
||||
|
||||
stmt.executeBatch();
|
||||
logger.info("Wrote " + scores.size() + " scores for mode: " + mode);
|
||||
LOGGER.info("Wrote " + scores.size() + " scores for mode: " + mode);
|
||||
|
||||
} catch (SQLException e) {
|
||||
logger.severe("Failed to write scores for mode " + mode + ": " + e.getMessage());
|
||||
LOGGER.severe("Failed to write scores for mode " + mode + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +150,7 @@ public class StorageSQL {
|
|||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
logger.severe("Failed to read player data: " + e.getMessage());
|
||||
LOGGER.severe("Failed to read player data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +171,7 @@ public class StorageSQL {
|
|||
stmt.executeUpdate();
|
||||
|
||||
} catch (SQLException e) {
|
||||
logger.severe("Failed to write player data: " + e.getMessage());
|
||||
LOGGER.severe("Failed to write player data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public class Item {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NoClone")
|
||||
public Item clone() {
|
||||
Item cloned = new Item(item.getType(), "");
|
||||
cloned.item.setItemMeta(item.getItemMeta());
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||
*/
|
||||
public class Probs {
|
||||
|
||||
private Probs() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a random key from a map based on weighted probabilities
|
||||
*
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ import org.bukkit.inventory.meta.SkullMeta;
|
|||
* Utility for setting player heads
|
||||
*/
|
||||
public class SkullSetter {
|
||||
|
||||
|
||||
private SkullSetter() {
|
||||
}
|
||||
|
||||
public static void setPlayerHead(OfflinePlayer player, SkullMeta meta) {
|
||||
if (meta != null && player != null) {
|
||||
meta.setOwningPlayer(player);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package dev.loki.loparkour.util.particle;
|
||||
|
||||
import dev.loki.loparkour.util.particle.ParticleData;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ import org.bukkit.util.BoundingBox;
|
|||
*/
|
||||
public class ParticleUtil {
|
||||
|
||||
private ParticleUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a box outline with particles
|
||||
*
|
||||
|
|
@ -89,7 +92,9 @@ public class ParticleUtil {
|
|||
* @param points Number of points
|
||||
*/
|
||||
public static void circle(Location center, Particle particle, int radius, int points) {
|
||||
if (center.getWorld() == null) return;
|
||||
if (center.getWorld() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < points; i++) {
|
||||
double angle = 2 * Math.PI * i / points;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ import java.util.regex.Pattern;
|
|||
*/
|
||||
public class ColorUtil {
|
||||
|
||||
private ColorUtil() {
|
||||
}
|
||||
|
||||
private static final Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})");
|
||||
/** Legacy fallback for old strings; do not use in new code. */
|
||||
private static final Pattern MINIMESSAGE_HEX_PATTERN = Pattern.compile("<#([A-Fa-f0-9]{6})>");
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import org.bukkit.Location;
|
|||
*/
|
||||
public class Locations {
|
||||
|
||||
private Locations() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum location from two locations (highest x, y, z)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ import java.util.stream.IntStream;
|
|||
*/
|
||||
public class Divider {
|
||||
|
||||
private Divider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Map with all session ids map to the session instances.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ package dev.loki.loparkour.world.core;
|
|||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.config.core.Config;
|
||||
import dev.lolib.worlds.VoidGenerator;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.WorldType;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
|
@ -14,6 +18,9 @@ import java.util.stream.Stream;
|
|||
|
||||
public class World {
|
||||
|
||||
private World() {
|
||||
}
|
||||
|
||||
private static String name;
|
||||
private static org.bukkit.World world;
|
||||
|
||||
|
|
@ -35,7 +42,9 @@ public class World {
|
|||
}
|
||||
|
||||
if (world != null) {
|
||||
LoParkour.getPlugin().getLogger().warning("Crash detected! The parkour world loading twice is not usual behaviour. This only happens after a server crash.");
|
||||
LoParkour.getPlugin().getLogger().warning(
|
||||
"Crash detected! The parkour world loading twice is not usual behaviour. " +
|
||||
"This only happens after a server crash.");
|
||||
World.world = world; // ensure static field is populated
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue