diff --git a/core/pom.xml b/core/pom.xml index d5e6e4fed..d9a98ece5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -7,7 +7,7 @@ dev.nandi0813 practice-parent - 7.5.0-SNAPSHOT + 7.6.0-SNAPSHOT practice-core diff --git a/core/src/main/java/dev/nandi0813/practice/ZonePractice.java b/core/src/main/java/dev/nandi0813/practice/ZonePractice.java index 4f61f78bc..b5c0ef60f 100644 --- a/core/src/main/java/dev/nandi0813/practice/ZonePractice.java +++ b/core/src/main/java/dev/nandi0813/practice/ZonePractice.java @@ -43,11 +43,6 @@ import dev.nandi0813.practice.manager.profile.cosmetics.CosmeticsPermissionManager; import dev.nandi0813.practice.manager.server.ServerManager; import dev.nandi0813.practice.manager.sidebar.SidebarManager; -import dev.nandi0813.practice.telemetry.bootstrap.TelemetryBootstrap; -import dev.nandi0813.practice.telemetry.collector.TelemetryMatchListener; -import dev.nandi0813.practice.telemetry.transport.ai.AiTrainingLogger; -import dev.nandi0813.practice.telemetry.transport.regular.TelemetryLogger; -import dev.nandi0813.practice.telemetry.transport.stats.PracticeStatsTelemetryLogger; import dev.nandi0813.practice.util.*; import dev.nandi0813.practice.util.placeholderapi.PlayerExpansion; import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; @@ -62,7 +57,6 @@ import java.util.Comparator; import java.util.EnumMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; public final class ZonePractice extends JavaPlugin { @@ -83,7 +77,6 @@ public final class ZonePractice extends JavaPlugin { // BStats private Metrics metrics; - private final AtomicBoolean telemetryListenerRegistered = new AtomicBoolean(false); public static final ErrorTracker ERROR_TRACKER = ErrorTracker.contextAware(); private final BukkitMetrics faststats_metrics = BukkitMetrics.factory() @@ -122,30 +115,6 @@ public void onEnable() { ConfigManager.createFile(); BackendManager.createFile(this); - TelemetryBootstrap.initializeAsync() - .thenApply(regularEnabled -> regularEnabled - || TelemetryBootstrap.isAiCollectionActive() - || TelemetryBootstrap.isPracticeStatsActive()) - .thenAccept(enabled -> { - if (!enabled) { - return; - } - - Bukkit.getScheduler().runTask(this, () -> { - if (!isEnabled()) { - return; - } - - if (TelemetryBootstrap.isPracticeStatsActive()) { - PracticeStatsTelemetryLogger.initialize(); - } - - if ((TelemetryBootstrap.isActive() || TelemetryBootstrap.isAiCollectionActive()) - && telemetryListenerRegistered.compareAndSet(false, true)) { - Bukkit.getPluginManager().registerEvents(new TelemetryMatchListener(), this); - } - }); - }); LanguageManager.createFile(this); GUIFile.createFile(this); MysqlManager.openConnection(); @@ -187,10 +156,6 @@ public void onEnable() { ProfileManager.getInstance().loadAllProfileInformations(); startUpProgress.replace(StartUpTypes.PROFILE_LOADING, true); - if (TelemetryBootstrap.isPracticeStatsActive()) { - PracticeStatsTelemetryLogger.onProfilesLoaded(); - } - LeaderboardManager.getInstance().createAllLB(() -> { startUpProgress.replace(StartUpTypes.LEADERBOARD_LOADING, true); @@ -252,11 +217,6 @@ public void onDisable() { faststats_metrics.shutdown(); MysqlManager.closeConnection(); BackendManager.save(); - - // Flush async telemetry writes at shutdown so completed matches are persisted. - TelemetryLogger.shutdown(); - AiTrainingLogger.shutdown(); - PracticeStatsTelemetryLogger.shutdown(); } /** diff --git a/core/src/main/java/dev/nandi0813/practice/ZonePracticeApiImpl.java b/core/src/main/java/dev/nandi0813/practice/ZonePracticeApiImpl.java index d9acf41df..3ad3a0974 100644 --- a/core/src/main/java/dev/nandi0813/practice/ZonePracticeApiImpl.java +++ b/core/src/main/java/dev/nandi0813/practice/ZonePracticeApiImpl.java @@ -12,7 +12,6 @@ import dev.nandi0813.practice.manager.profile.Profile; import dev.nandi0813.practice.manager.profile.ProfileManager; import dev.nandi0813.practice.manager.profile.group.Group; -import dev.nandi0813.practice.util.StringUtil; import org.bukkit.entity.Player; public class ZonePracticeApiImpl extends ZonePracticeApi { @@ -28,8 +27,8 @@ public String getPlayerDivision(Player player, DivisionName divisionName) { if (profile.getStats().getDivision() == null) return null; return switch (divisionName) { - case FULL -> StringUtil.CC(profile.getStats().getDivision().getFullName()); - case SHORT -> StringUtil.CC(profile.getStats().getDivision().getShortName()); + case FULL -> profile.getStats().getDivision().getFullName(); + case SHORT -> profile.getStats().getDivision().getShortName(); }; } diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/CreateArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/CreateArg.java index eb2218510..dcce97ac5 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/CreateArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/CreateArg.java @@ -8,8 +8,9 @@ import java.text.Normalizer; -public enum CreateArg { - ; +public final class CreateArg { + + private CreateArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/DeleteArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/DeleteArg.java index 378d5eadd..aa647e051 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/DeleteArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/DeleteArg.java @@ -12,8 +12,9 @@ import java.util.ArrayList; import java.util.List; -public enum DeleteArg { - ; +public final class DeleteArg { + + private DeleteArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/DisableArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/DisableArg.java index 5699af862..fac9a481d 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/DisableArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/DisableArg.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.List; -public enum DisableArg { - ; +public final class DisableArg { + + private DisableArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/EnableArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/EnableArg.java index 17186969a..e231aa95e 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/EnableArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/EnableArg.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.List; -public enum EnableArg { - ; +public final class EnableArg { + + private EnableArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/FreezeArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/FreezeArg.java index d78951bd1..60a3e4184 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/FreezeArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/FreezeArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum FreezeArg { - ; +public final class FreezeArg { + + private FreezeArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.arena.freeze")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/HelpArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/HelpArg.java index 29c1ea0bf..3d05df170 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/HelpArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/HelpArg.java @@ -4,8 +4,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum HelpArg { - ; +public final class HelpArg { + + private HelpArg() {} public static void run(Player player, String label) { if (player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/InfoArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/InfoArg.java index ffee928b1..8e1a320d5 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/InfoArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/InfoArg.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.List; -public enum InfoArg { - ; +public final class InfoArg { + + private InfoArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { @@ -37,12 +38,13 @@ public static void run(Player player, String label, String[] args) { .replace("%arena%", arena.getName()) .replace("%type%", arena.getType().getName()) .replace("%icon%", arena.getIcon() != null ? LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.INFO.STATUS-NAMES.SET") : LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.INFO.STATUS-NAMES.NOT-SET")) - .replace("%displayName%", StringUtil.legacyColorToMiniMessage(arena.getDisplayName())) + .replace("%displayName%", arena.getDisplayName()) .replace("%ladders%", (ladderNames.isEmpty() ? StringUtil.CC("NULL") : ladderNames.toString().replace("]", "").replace("[", ""))) .replace("%corner1%", ArenaUtil.convertLocation(arena.getCorner1())) .replace("%corner2%", ArenaUtil.convertLocation(arena.getCorner2())) .replace("%position1%", ArenaUtil.convertLocation(arena.getPosition1())) .replace("%position2%", ArenaUtil.convertLocation(arena.getPosition2())) + .replace("%partyFfaCenter%", ArenaUtil.convertLocation(arena.getPartyFfaCenter())) .replace("%status%", arena.isEnabled() ? LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.INFO.STATUS-NAMES.ENABLED") : LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.INFO.STATUS-NAMES.DISABLED")) ); } diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/IconArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/IconArg.java index d9d4b194d..a3178fa85 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/IconArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/IconArg.java @@ -2,6 +2,7 @@ import dev.nandi0813.practice.manager.arena.ArenaManager; import dev.nandi0813.practice.manager.arena.arenas.interfaces.DisplayArena; +import dev.nandi0813.practice.manager.backend.ConfigManager; import dev.nandi0813.practice.manager.backend.LanguageManager; import dev.nandi0813.practice.manager.fight.util.PlayerUtil; import dev.nandi0813.practice.manager.gui.GUIManager; @@ -16,8 +17,9 @@ import java.util.ArrayList; import java.util.List; -public enum IconArg { - ; +public final class IconArg { + + private IconArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { @@ -36,7 +38,7 @@ public static void run(Player player, String label, String[] args) { return; } - if (arena.isEnabled()) { + if (arena.isEnabled() && !ConfigManager.getBoolean("SETUP.ALLOW-ICON-EDIT-WHILE-ENABLED")) { Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.ICON.CANT-EDIT").replace("%arena%", arena.getName())); return; } diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/PartyFfaCenterArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/PartyFfaCenterArg.java new file mode 100644 index 000000000..bbbb793b5 --- /dev/null +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/PartyFfaCenterArg.java @@ -0,0 +1,77 @@ +package dev.nandi0813.practice.command.arena.arguments.Set; + +import dev.nandi0813.practice.manager.arena.ArenaManager; +import dev.nandi0813.practice.manager.arena.arenas.Arena; +import dev.nandi0813.practice.manager.backend.LanguageManager; +import dev.nandi0813.practice.manager.gui.GUIType; +import dev.nandi0813.practice.manager.gui.setup.arena.ArenaGUISetupManager; +import dev.nandi0813.practice.util.Common; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.util.StringUtil; + +import java.util.ArrayList; +import java.util.List; + +public final class PartyFfaCenterArg { + + private PartyFfaCenterArg() {} + + public static void run(Player player, String label, String[] args) { + if (!player.hasPermission("zpp.setup")) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.NO-PERMISSION")); + return; + } + + if (args.length != 3) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.PARTYFFACENTER.COMMAND-HELP").replace("%label%", label)); + return; + } + + Arena arena = ArenaManager.getInstance().getNormalArena(args[2]); + if (arena == null) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.PARTYFFACENTER.ARENA-NOT-EXISTS").replace("%arena%", args[2])); + return; + } + + if (arena.isEnabled()) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.PARTYFFACENTER.ARENA-ENABLED").replace("%arena%", arena.getName())); + return; + } + + if (arena.isBuild() && !arena.getCopies().isEmpty()) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.PARTYFFACENTER.CANT-EDIT").replace("%arena%", arena.getName())); + return; + } + + if (arena.getCuboid() == null) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.PARTYFFACENTER.NO-REGION")); + return; + } + + Location center = player.getLocation().clone(); + if (!arena.getCuboid().contains(center)) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.PARTYFFACENTER.POS-OUTSIDE-REGION")); + return; + } + + arena.setPartyFfaCenter(center); + ArenaGUISetupManager.getInstance().getArenaSetupGUIs().get(arena).get(GUIType.Arena_Main).update(); + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.ARENA.ARGUMENTS.PARTYFFACENTER.SET") + .replace("%arena%", arena.getName())); + } + + public static List tabComplete(Player player, String[] args) { + List arguments = new ArrayList<>(); + if (!player.hasPermission("zpp.setup")) return arguments; + + if (args.length == 3) { + for (Arena arena : ArenaManager.getInstance().getNormalArenas()) + arguments.add(arena.getName()); + + return StringUtil.copyPartialMatches(args[2], arguments, new ArrayList<>()); + } + + return arguments; + } +} diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/PortalProtArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/PortalProtArg.java index 442c1bd45..e407f09ef 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/PortalProtArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/PortalProtArg.java @@ -10,8 +10,9 @@ import java.util.ArrayList; import java.util.List; -public enum PortalProtArg { - ; +public final class PortalProtArg { + + private PortalProtArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/SideBuildLimitArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/SideBuildLimitArg.java index 6d2c5b940..ad17b7fa0 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/SideBuildLimitArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/Set/SideBuildLimitArg.java @@ -12,8 +12,9 @@ import java.util.ArrayList; import java.util.List; -public enum SideBuildLimitArg { - ; +public final class SideBuildLimitArg { + + private SideBuildLimitArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/SetArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/SetArg.java index 4de51121b..e2db0998e 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/SetArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/SetArg.java @@ -1,6 +1,7 @@ package dev.nandi0813.practice.command.arena.arguments; import dev.nandi0813.practice.command.arena.arguments.Set.IconArg; +import dev.nandi0813.practice.command.arena.arguments.Set.PartyFfaCenterArg; import dev.nandi0813.practice.command.arena.arguments.Set.PortalProtArg; import dev.nandi0813.practice.command.arena.arguments.Set.SideBuildLimitArg; import org.bukkit.entity.Player; @@ -10,8 +11,9 @@ import java.util.Collections; import java.util.List; -public enum SetArg { - ; +public final class SetArg { + + private SetArg() {} public static void run(Player player, String label, String[] args) { if (args.length > 1) { @@ -25,6 +27,9 @@ public static void run(Player player, String label, String[] args) { case "sidebuildlimit": SideBuildLimitArg.run(player, label, args); break; + case "partyffacenter": + PartyFfaCenterArg.run(player, label, args); + break; } } else HelpArg.run_setCommand(player, label); @@ -39,6 +44,7 @@ public static List tabComplete(Player player, String[] args) { arguments.add("icon"); arguments.add("portalprot"); arguments.add("sidebuildlimit"); + arguments.add("partyffacenter"); StringUtil.copyPartialMatches(args[1], arguments, completion); } else if (args.length > 2) { @@ -46,6 +52,7 @@ public static List tabComplete(Player player, String[] args) { case "icon" -> IconArg.tabComplete(player, args); case "portalprot" -> PortalProtArg.tabComplete(player, args); case "sidebuildlimit" -> SideBuildLimitArg.tabComplete(player, args); + case "partyffacenter" -> PartyFfaCenterArg.tabComplete(player, args); default -> completion; }; } diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/SetupArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/SetupArg.java index 7940eb6ab..14b53d389 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/SetupArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/SetupArg.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.List; -public enum SetupArg { - ; +public final class SetupArg { + + private SetupArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/StopArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/StopArg.java index c9a1913cc..8b1b405c1 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/StopArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/StopArg.java @@ -12,8 +12,9 @@ import java.util.ArrayList; import java.util.List; -public enum StopArg { - ; +public final class StopArg { + + private StopArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.arena.stop")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/TeleportArg.java b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/TeleportArg.java index fbb14311c..09fb9636e 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/TeleportArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/arena/arguments/TeleportArg.java @@ -10,8 +10,9 @@ import java.util.ArrayList; import java.util.List; -public enum TeleportArg { - ; +public final class TeleportArg { + + private TeleportArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/BracketsArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/BracketsArg.java index e86ad0641..dbd3c6740 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/BracketsArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/BracketsArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum BracketsArg { - ; +public final class BracketsArg { + + private BracketsArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/JuggernautArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/JuggernautArg.java index fbb0ec2b5..d910b5292 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/JuggernautArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/JuggernautArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum JuggernautArg { - ; +public final class JuggernautArg { + + private JuggernautArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/LMSArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/LMSArg.java index 67e3dbb1b..484e9a444 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/LMSArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/LMSArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum LMSArg { - ; +public final class LMSArg { + + private LMSArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/OITCArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/OITCArg.java index 2b137d937..b2afea938 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/OITCArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/OITCArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum OITCArg { - ; +public final class OITCArg { + + private OITCArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/SpleggArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/SpleggArg.java index 08702e011..9336af999 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/SpleggArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/SpleggArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum SpleggArg { - ; +public final class SpleggArg { + + private SpleggArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/SumoArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/SumoArg.java index 8a3df0756..9fc36708e 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/SumoArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/SumoArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum SumoArg { - ; +public final class SumoArg { + + private SumoArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/TNTTagArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/TNTTagArg.java index d708a24a1..34209818b 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/TNTTagArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/Events/TNTTagArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum TNTTagArg { - ; +public final class TNTTagArg { + + private TNTTagArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/HelpArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/HelpArg.java index 16cd506fa..f504d4240 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/HelpArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/HelpArg.java @@ -4,8 +4,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum HelpArg { - ; +public final class HelpArg { + + private HelpArg() {} public static void run(Player player, String label) { if (player.hasPermission("zpp.setup") && player.hasPermission("zpp.event.stop")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/HostArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/HostArg.java index 60383d442..c18a023c2 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/HostArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/HostArg.java @@ -10,8 +10,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum HostArg { - ; +public final class HostArg { + + private HostArg() {} public static void run(Player player, String label, String[] args) { if (args.length != 1) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/JoinArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/JoinArg.java index 74ec700d7..bb458d048 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/JoinArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/JoinArg.java @@ -10,8 +10,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum JoinArg { - ; +public final class JoinArg { + + private JoinArg() {} public static void run(Player player, String label, String[] args) { if (args.length != 1) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/SpawnPointArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/SpawnPointArg.java index eef8e4b68..69c3ea83d 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/SpawnPointArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/SpawnPointArg.java @@ -6,8 +6,9 @@ import org.bukkit.Location; import org.bukkit.entity.Player; -public enum SpawnPointArg { - ; +public final class SpawnPointArg { + + private SpawnPointArg() {} public static void spawnPointCommand(Player player, String label1, EventData eventData, String[] args) { if (args.length == 3) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/StopArg.java b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/StopArg.java index b31c66c7c..7c451bbce 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/event/arguments/StopArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/event/arguments/StopArg.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.List; -public enum StopArg { - ; +public final class StopArg { + + private StopArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.event.stop.collecting") && !player.hasPermission("zpp.event.stop.live")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/HelpArg.java b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/HelpArg.java index d8ed76ee7..b9541c4b9 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/HelpArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/HelpArg.java @@ -4,8 +4,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum HelpArg { - ; +public final class HelpArg { + + private HelpArg() {} public static void run(Player player, String label) { for (String line : LanguageManager.getList("FFA.COMMAND.HELP")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/KitArg.java b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/KitArg.java index d5f7197b7..b5d6d719f 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/KitArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/KitArg.java @@ -6,8 +6,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum KitArg { - ; +public final class KitArg { + + private KitArg() {} public static void run(Player player) { FFA ffa = FFAManager.getInstance().getFFAByPlayer(player); diff --git a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/LeaveArg.java b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/LeaveArg.java index b66aa1431..db18ffd94 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/LeaveArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/LeaveArg.java @@ -6,8 +6,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum LeaveArg { - ; +public final class LeaveArg { + + private LeaveArg() {} public static void run(Player player) { // First check if player is in an FFA as a participant diff --git a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/ListArg.java b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/ListArg.java index d5f4f7af1..32dc43ce6 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/ListArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/ListArg.java @@ -9,8 +9,9 @@ import java.util.ArrayList; import java.util.List; -public enum ListArg { - ; +public final class ListArg { + + private ListArg() {} public static void run(Player player) { List ffas = new ArrayList<>(); diff --git a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/SpectateArg.java b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/SpectateArg.java index abda51fe9..6ba57a86d 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/SpectateArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ffa/arguments/SpectateArg.java @@ -14,8 +14,9 @@ import java.util.ArrayList; import java.util.List; -public enum SpectateArg { - ; +public final class SpectateArg { + + private SpectateArg() {} public static void run(Player player, String label, String[] args) { if (args.length != 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/CreateArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/CreateArg.java index 5b162e9df..790d5b04c 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/CreateArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/CreateArg.java @@ -1,5 +1,6 @@ package dev.nandi0813.practice.command.ladder.arguments; +import dev.nandi0813.practice.manager.backend.ConfigManager; import dev.nandi0813.practice.manager.backend.LanguageManager; import dev.nandi0813.practice.manager.gui.guis.ladder.LadderCreateGui; import dev.nandi0813.practice.manager.ladder.LadderManager; @@ -8,8 +9,11 @@ import java.text.Normalizer; -public enum CreateArg { - ; +public final class CreateArg { + + private CreateArg() {} + + private static final int MAX_LADDERS = ConfigManager.getInt("SETUP.MAX-LADDERS"); public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { @@ -22,8 +26,9 @@ public static void run(Player player, String label, String[] args) { return; } - if (LadderManager.getInstance().getLadders().size() == 45) { - Common.sendMMMessage(player, LanguageManager.getString("COMMAND.LADDER.ARGUMENTS.CREATE.REACHED-MAX")); + if (MAX_LADDERS > 0 && LadderManager.getInstance().getLadders().size() >= MAX_LADDERS) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.LADDER.ARGUMENTS.CREATE.REACHED-MAX") + .replace("%max%", String.valueOf(MAX_LADDERS))); return; } diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/DeleteArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/DeleteArg.java index ae984aa71..ce1feb130 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/DeleteArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/DeleteArg.java @@ -19,8 +19,9 @@ import java.util.List; import java.util.Map; -public enum DeleteArg { - ; +public final class DeleteArg { + + private DeleteArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/EffectArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/EffectArg.java index 2ff05f7fe..5b4ff9bb9 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/EffectArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/EffectArg.java @@ -12,8 +12,9 @@ import java.util.ArrayList; import java.util.List; -public enum EffectArg { - ; +public final class EffectArg { + + private EffectArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/FreezeArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/FreezeArg.java index 2c6a065d8..faf514d77 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/FreezeArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/FreezeArg.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.List; -public enum FreezeArg { - ; +public final class FreezeArg { + + private FreezeArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.ladder.freeze")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/HelpArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/HelpArg.java index 73d20ead9..a94cee3f0 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/HelpArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/HelpArg.java @@ -4,8 +4,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum HelpArg { - ; +public final class HelpArg { + + private HelpArg() {} public static void run(Player player, String label) { if (player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/IconArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/IconArg.java index cc6a1f915..d66c39ff3 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/IconArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/IconArg.java @@ -1,5 +1,6 @@ package dev.nandi0813.practice.command.ladder.arguments; +import dev.nandi0813.practice.manager.backend.ConfigManager; import dev.nandi0813.practice.manager.backend.LanguageManager; import dev.nandi0813.practice.manager.fight.util.PlayerUtil; import dev.nandi0813.practice.manager.gui.GUIManager; @@ -17,8 +18,9 @@ import java.util.ArrayList; import java.util.List; -public enum IconArg { - ; +public final class IconArg { + + private IconArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { @@ -37,7 +39,7 @@ public static void run(Player player, String label, String[] args) { return; } - if (ladder.isEnabled()) { + if (ladder.isEnabled() && !ConfigManager.getBoolean("SETUP.ALLOW-ICON-EDIT-WHILE-ENABLED")) { Common.sendMMMessage(player, LanguageManager.getString("COMMAND.LADDER.ARGUMENTS.ICON.LADDER-ENABLED").replace("%ladder%", ladder.getDisplayName())); return; } diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/InfoArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/InfoArg.java index aad281dd0..974c43087 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/InfoArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/InfoArg.java @@ -9,8 +9,9 @@ import java.util.ArrayList; import java.util.List; -public enum InfoArg { - ; +public final class InfoArg { + + private InfoArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/InventoryArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/InventoryArg.java index 9753231e1..dc31a61d8 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/InventoryArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/InventoryArg.java @@ -12,8 +12,9 @@ import java.util.ArrayList; import java.util.List; -public enum InventoryArg { - ; +public final class InventoryArg { + + private InventoryArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/SetArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/SetArg.java index 34dd9071a..a11aae65b 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/SetArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/SetArg.java @@ -7,8 +7,9 @@ import java.util.Collections; import java.util.List; -public enum SetArg { - ; +public final class SetArg { + + private SetArg() {} public static void run(Player player, String label, String[] args) { if (args.length > 1) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/StopArg.java b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/StopArg.java index 9d1161548..27035ca5c 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/StopArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/ladder/arguments/StopArg.java @@ -12,8 +12,9 @@ import java.util.ArrayList; import java.util.List; -public enum StopArg { - ; +public final class StopArg { + + private StopArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.ladder.stop")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyAcceptArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyAcceptArg.java index 07ccaf99d..484891769 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyAcceptArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyAcceptArg.java @@ -10,8 +10,9 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; -public enum PartyAcceptArg { - ; +public final class PartyAcceptArg { + + private PartyAcceptArg() {} public static void AcceptCommand(Player player, String label, String[] args) { if (args.length != 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyDisbandArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyDisbandArg.java index b7a815aee..0828c5ac8 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyDisbandArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyDisbandArg.java @@ -6,8 +6,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum PartyDisbandArg { - ; +public final class PartyDisbandArg { + + private PartyDisbandArg() {} public static void DisbandCommand(Player player, String label, String[] args) { if (args.length != 1) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyHelpArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyHelpArg.java index 6d82e398e..71b46dd74 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyHelpArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyHelpArg.java @@ -4,8 +4,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum PartyHelpArg { - ; +public final class PartyHelpArg { + + private PartyHelpArg() {} public static void HelpCommand(Player player, String label) { for (String line : LanguageManager.getList("COMMAND.PARTY.ARGUMENTS.HELP")) diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyInfoArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyInfoArg.java index 6b25644fb..fb2b7fc7d 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyInfoArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyInfoArg.java @@ -7,8 +7,9 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; -public enum PartyInfoArg { - ; +public final class PartyInfoArg { + + private PartyInfoArg() {} public static void InfoCommand(Player player, String label, String[] args) { if (args.length != 1 && args.length != 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyInviteArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyInviteArg.java index 9b8dc9cf8..871573072 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyInviteArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyInviteArg.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum PartyInviteArg { - ; +public final class PartyInviteArg { + + private PartyInviteArg() {} public static void InviteCommand(Player player, String label, String[] args) { if (args.length != 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyJoinArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyJoinArg.java index 4615a8f81..78519710d 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyJoinArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyJoinArg.java @@ -4,8 +4,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum PartyJoinArg { - ; +public final class PartyJoinArg { + + private PartyJoinArg() {} public static void JoinCommand(Player player, String label, String[] args) { if (args.length != 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyKickArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyKickArg.java index 8d8f8fc39..7aed7ed11 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyKickArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyKickArg.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.List; -public enum PartyKickArg { - ; +public final class PartyKickArg { + + private PartyKickArg() {} public static void KickCommand(Player player, String label, String[] args) { if (args.length != 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyLeaderArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyLeaderArg.java index 798cdbea0..10bff7a93 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyLeaderArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyLeaderArg.java @@ -11,8 +11,9 @@ import java.util.ArrayList; import java.util.List; -public enum PartyLeaderArg { - ; +public final class PartyLeaderArg { + + private PartyLeaderArg() {} public static void LeaderCommand(Player player, String label, String[] args) { if (args.length != 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyLeaveArg.java b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyLeaveArg.java index d2924093c..909865db4 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyLeaveArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/party/arguments/PartyLeaveArg.java @@ -6,8 +6,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum PartyLeaveArg { - ; +public final class PartyLeaveArg { + + private PartyLeaveArg() {} public static void LeaveCommand(Player player, String label, String[] args) { if (args.length != 1) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ArenasArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ArenasArg.java index 3bbcd5fa5..22dbc5b20 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ArenasArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ArenasArg.java @@ -7,8 +7,9 @@ import org.bukkit.GameMode; import org.bukkit.entity.Player; -public enum ArenasArg { - ; +public final class ArenasArg { + + private ArenasArg() {} public static void run(Player player) { if (!player.hasPermission("zpp.practice.arenas")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/EloArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/EloArg.java index 97b9a6484..f3793cb4f 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/EloArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/EloArg.java @@ -16,8 +16,9 @@ import java.util.ArrayList; import java.util.List; -public enum EloArg { - ; +public final class EloArg { + + private EloArg() {} public static void run(Player player, String label, String[] args) { if (args.length < 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/Exp.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/Exp.java index 9e50ad323..4c4831bad 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/Exp.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/Exp.java @@ -13,8 +13,9 @@ import java.util.ArrayList; import java.util.List; -public enum Exp { - ; +public final class Exp { + + private Exp() {} public static void run(Player player, String label, String[] args) { if (args.length < 2) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/GoldenHeadArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/GoldenHeadArg.java index c7829e725..4b28ca62f 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/GoldenHeadArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/GoldenHeadArg.java @@ -8,8 +8,9 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -public enum GoldenHeadArg { - ; +public final class GoldenHeadArg { + + private GoldenHeadArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/HelpArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/HelpArg.java index beea7cea0..182ee77df 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/HelpArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/HelpArg.java @@ -4,8 +4,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum HelpArg { - ; +public final class HelpArg { + + private HelpArg() {} public static void run(Player player, String label) { if (player.hasPermission("zpp.admin")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/HologramArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/HologramArg.java index 576e9da15..71dbe2bf5 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/HologramArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/HologramArg.java @@ -2,11 +2,13 @@ import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.backend.LanguageManager; +import dev.nandi0813.practice.manager.gui.GUIManager; import dev.nandi0813.practice.manager.gui.GUIType; import dev.nandi0813.practice.manager.gui.setup.hologram.HologramSetupManager; import dev.nandi0813.practice.manager.leaderboard.hologram.Hologram; import dev.nandi0813.practice.manager.leaderboard.hologram.HologramManager; import dev.nandi0813.practice.manager.leaderboard.hologram.HologramType; +import dev.nandi0813.practice.manager.leaderboard.hologram.SetupHologramType; import dev.nandi0813.practice.manager.leaderboard.hologram.holograms.GlobalHologram; import dev.nandi0813.practice.manager.leaderboard.hologram.holograms.LadderDynamicHologram; import dev.nandi0813.practice.manager.leaderboard.hologram.holograms.LadderStaticHologram; @@ -22,8 +24,9 @@ import java.util.ArrayList; import java.util.List; -public enum HologramArg { - ; +public final class HologramArg { + + private HologramArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { @@ -51,8 +54,38 @@ public static void run(Player player, String label, String[] args) { return; } + if (args.length >= 2 && args[1].equalsIgnoreCase("teleport")) { + if (args.length != 3) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.HOLOGRAM.TELEPORT.COMMAND-HELP").replace("%label%", label + " hologram")); + return; + } + + Hologram hologram = HologramManager.getInstance().findHologram(args[2]).orElse(null); + if (hologram == null) { + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.HOLOGRAM.TELEPORT.HOLOGRAM-NOT-EXISTS").replace("%hologram%", args[2])); + return; + } + + boolean enabled = hologram.isEnabled(); + hologram.despawn(); + hologram.moveTo(player.getLocation()); + hologram.setData(); + + if (enabled) { + hologram.updateContent(); + } else { + hologram.setSetupHologram(SetupHologramType.SETUP); + } + + GUIManager.getInstance().searchGUI(GUIType.Hologram_Summary).update(); + Common.sendMMMessage(player, LanguageManager.getString("COMMAND.HOLOGRAM.TELEPORT.TELEPORTED").replace("%hologram%", hologram.getName())); + return; + } + if (args.length != 4 || !args[1].equalsIgnoreCase("create")) { - Common.sendMMMessage(player, LanguageManager.getString("COMMAND.HOLOGRAM.COMMAND-HELP").replace("%label%", label + " hologram")); + for (String line : LanguageManager.getList("COMMAND.HOLOGRAM.COMMAND-HELP")) { + Common.sendMMMessage(player, line.replace("%label%", label + " hologram")); + } return; } @@ -111,9 +144,15 @@ public static List tabComplete(Player player, String[] args) { if (args.length == 2) { arguments.add("create"); + arguments.add("teleport"); return StringUtil.copyPartialMatches(args[1], arguments, new ArrayList<>()); } + if (args.length == 3 && args[1].equalsIgnoreCase("teleport")) { + HologramManager.getInstance().getHolograms().forEach(hologram -> arguments.add(hologram.getName())); + return StringUtil.copyPartialMatches(args[2], arguments, new ArrayList<>()); + } + if (args.length == 4 && args[1].equalsIgnoreCase("create")) { arguments.add("global"); arguments.add("ladder_static"); diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/InfoArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/InfoArg.java index 21f79a086..76511b547 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/InfoArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/InfoArg.java @@ -14,8 +14,9 @@ import java.util.ArrayList; import java.util.List; -public enum InfoArg { - ; +public final class InfoArg { + + private InfoArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.practice.info")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/LobbyArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/LobbyArg.java index b8d541f35..8b5a57a29 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/LobbyArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/LobbyArg.java @@ -12,8 +12,9 @@ import java.util.ArrayList; import java.util.List; -public enum LobbyArg { - ; +public final class LobbyArg { + + private LobbyArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.practice.lobby")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/NametagArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/NametagArg.java index c877fdb5d..411a1d1d9 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/NametagArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/NametagArg.java @@ -14,8 +14,9 @@ import java.util.ArrayList; import java.util.List; -public enum NametagArg { - ; +public final class NametagArg { + + private NametagArg() {} private static String joinArgs(String[] args, int start) { StringBuilder builder = new StringBuilder(); diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/RankedArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/RankedArg.java index 7129b3bf3..d93432344 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/RankedArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/RankedArg.java @@ -14,8 +14,9 @@ import java.util.ArrayList; import java.util.List; -public enum RankedArg { - ; +public final class RankedArg { + + private RankedArg() {} public static void run(Player player, String label, String[] args) { if (args.length == 3 && args[1].equalsIgnoreCase("reset")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ReloadArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ReloadArg.java index 8710b393a..21cbdb604 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ReloadArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ReloadArg.java @@ -5,8 +5,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum ReloadArg { - ; +public final class ReloadArg { + + private ReloadArg() {} private static String message(String path, String fallback) { String value = LanguageManager.getString(path); diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/RenameArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/RenameArg.java index f11847207..48713407d 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/RenameArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/RenameArg.java @@ -11,8 +11,9 @@ import java.util.Arrays; import java.util.List; -public enum RenameArg { - ; +public final class RenameArg { + + private RenameArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.practice.rename")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ResetArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ResetArg.java index 91acaa9bb..b5bddb53a 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ResetArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/ResetArg.java @@ -15,8 +15,9 @@ import java.util.ArrayList; import java.util.List; -public enum ResetArg { - ; +public final class ResetArg { + + private ResetArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.practice.reset")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/TeleportArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/TeleportArg.java index 6257a4856..f288118de 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/TeleportArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/TeleportArg.java @@ -10,8 +10,9 @@ import java.util.ArrayList; import java.util.List; -public enum TeleportArg { - ; +public final class TeleportArg { + + private TeleportArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.setup")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/UnrankedArg.java b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/UnrankedArg.java index e541d2e47..b5d227e67 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/UnrankedArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/practice/arguments/UnrankedArg.java @@ -14,8 +14,9 @@ import java.util.ArrayList; import java.util.List; -public enum UnrankedArg { - ; +public final class UnrankedArg { + + private UnrankedArg() {} public static void run(Player player, String label, String[] args) { if (args.length == 3 && args[1].equalsIgnoreCase("reset")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/ChatArg.java b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/ChatArg.java index 791f512b7..fd1c73c2b 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/ChatArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/ChatArg.java @@ -8,8 +8,9 @@ import dev.nandi0813.practice.util.playerutil.PlayerUtil; import org.bukkit.entity.Player; -public enum ChatArg { - ; +public final class ChatArg { + + private ChatArg() {} public static void run(Player player, String[] args) { if (!player.hasPermission("zpp.staffmode.chat")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/EnableArg.java b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/EnableArg.java index e89930f6b..92b54594d 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/EnableArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/EnableArg.java @@ -8,8 +8,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum EnableArg { - ; +public final class EnableArg { + + private EnableArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.staff")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/FollowArg.java b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/FollowArg.java index 2c44ca900..586f11b2f 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/FollowArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/FollowArg.java @@ -1,18 +1,19 @@ package dev.nandi0813.practice.command.staff.arguments; -import dev.nandi0813.practice.util.StringUtil; +import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum FollowArg { - ; +public final class FollowArg { + + private FollowArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.staffmode.follow")) { - player.sendMessage(StringUtil.CC("&cYou don't have permission.")); + Common.sendMMMessage(player, "You don't have permission."); return; } - player.sendMessage(StringUtil.CC("&cCurrently not a feature of the plugin.")); + Common.sendMMMessage(player, "Currently not a feature of the plugin."); /* if (args.length == 2) @@ -28,13 +29,13 @@ public static void run(Player player, String label, String[] args) { } else - player.sendMessage(StringUtil.CC("&cPlayer is not online.")); + Common.sendMMMessage(player, "Player is not online."); } else - player.sendMessage(StringUtil.CC("&cYou can only use this command in staff mode.")); + Common.sendMMMessage(player, "You can only use this command in staff mode."); } else - player.sendMessage(StringUtil.CC("&c/" + label + " follow ")); + Common.sendMMMessage(player, "/" + label + " follow ")); */ } diff --git a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/ForceEndArg.java b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/ForceEndArg.java index aea0f9ec7..c3ccf775e 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/ForceEndArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/ForceEndArg.java @@ -17,8 +17,9 @@ import java.util.ArrayList; import java.util.List; -public enum ForceEndArg { - ; +public final class ForceEndArg { + private ForceEndArg() { + } public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.staffmode.forceend")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/HelpArg.java b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/HelpArg.java index 0dfa3c3b3..4c061109b 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/HelpArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/HelpArg.java @@ -4,8 +4,9 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.entity.Player; -public enum HelpArg { - ; +public final class HelpArg { + + private HelpArg() {} public static void run(Player player, String label) { if (!player.hasPermission("zpp.staffmode")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/StopArg.java b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/StopArg.java index 69a65dac0..6b7a5bb4b 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/StopArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/StopArg.java @@ -5,6 +5,7 @@ import dev.nandi0813.practice.manager.fight.event.interfaces.Event; import dev.nandi0813.practice.manager.fight.match.Match; import dev.nandi0813.practice.manager.fight.match.MatchManager; +import dev.nandi0813.practice.manager.fight.match.runnable.round.RoundEndRunnable; import dev.nandi0813.practice.manager.profile.Profile; import dev.nandi0813.practice.manager.profile.ProfileManager; import dev.nandi0813.practice.manager.profile.enums.ProfileStatus; @@ -18,8 +19,9 @@ import java.util.ArrayList; import java.util.List; -public enum StopArg { - ; +public final class StopArg { + private StopArg() { + } public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.staffmode.stop")) { diff --git a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/VanishArg.java b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/VanishArg.java index 585a975bd..ba3605daf 100644 --- a/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/VanishArg.java +++ b/core/src/main/java/dev/nandi0813/practice/command/staff/arguments/VanishArg.java @@ -9,8 +9,9 @@ import dev.nandi0813.practice.util.entityhider.PlayerHider; import org.bukkit.entity.Player; -public enum VanishArg { - ; +public final class VanishArg { + + private VanishArg() {} public static void run(Player player, String label, String[] args) { if (!player.hasPermission("zpp.staffmode")) { diff --git a/core/src/main/java/dev/nandi0813/practice/listener/EntityDamage.java b/core/src/main/java/dev/nandi0813/practice/listener/EntityDamage.java index 72533254d..2da5654a5 100644 --- a/core/src/main/java/dev/nandi0813/practice/listener/EntityDamage.java +++ b/core/src/main/java/dev/nandi0813/practice/listener/EntityDamage.java @@ -15,9 +15,9 @@ public void onEntityDamage(EntityDamageEvent e) { if (!(e.getEntity() instanceof Player player)) return; if (!e.getCause().equals(EntityDamageEvent.DamageCause.VOID)) return; - if (!ServerManager.getInstance().getInWorld().containsKey(player)) return; - if (ServerManager.getInstance().getInWorld().get(player).equals(WorldEnum.LOBBY)) { + WorldEnum worldEnum = ServerManager.getInstance().getInWorld().get(player); + if (worldEnum == WorldEnum.LOBBY) { Location lobbyLocation = ServerManager.getLobby(); if (lobbyLocation != null) player.teleport(lobbyLocation); diff --git a/core/src/main/java/dev/nandi0813/practice/listener/PlayerChatListener.java b/core/src/main/java/dev/nandi0813/practice/listener/PlayerChatListener.java index 85879eac7..8bf579a31 100644 --- a/core/src/main/java/dev/nandi0813/practice/listener/PlayerChatListener.java +++ b/core/src/main/java/dev/nandi0813/practice/listener/PlayerChatListener.java @@ -15,6 +15,7 @@ import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.PAPIUtil; import dev.nandi0813.practice.util.SoftDependUtil; +import dev.nandi0813.practice.util.StringUtil; import io.papermc.paper.event.player.AsyncChatEvent; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; @@ -133,7 +134,7 @@ private void applyRenderer(AsyncChatEvent e, String miniMessageString) { if (SoftDependUtil.isPAPI_ENABLED && viewer instanceof Player viewerPlayer) { return PAPIUtil.runThroughFormat(viewerPlayer, miniMessageString); } - return ZonePractice.getMiniMessage().deserialize(miniMessageString); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(miniMessageString)); }); } } diff --git a/core/src/main/java/dev/nandi0813/practice/listener/PlayerJoin.java b/core/src/main/java/dev/nandi0813/practice/listener/PlayerJoin.java index 861e31d03..bf4671a48 100644 --- a/core/src/main/java/dev/nandi0813/practice/listener/PlayerJoin.java +++ b/core/src/main/java/dev/nandi0813/practice/listener/PlayerJoin.java @@ -2,6 +2,8 @@ import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.backend.ConfigManager; +import dev.nandi0813.practice.manager.fight.match.Match; +import dev.nandi0813.practice.manager.fight.match.MatchManager; import dev.nandi0813.practice.manager.inventory.InventoryManager; import dev.nandi0813.practice.manager.nametag.NametagManager; import dev.nandi0813.practice.manager.profile.Profile; @@ -9,10 +11,10 @@ import dev.nandi0813.practice.manager.profile.cosmetics.armortrim.CosmeticsPermissionSanitizer; import dev.nandi0813.practice.manager.profile.enums.ProfileStatus; import dev.nandi0813.practice.manager.sidebar.SidebarManager; -import dev.nandi0813.practice.telemetry.transport.stats.PracticeStatsTelemetryLogger; import dev.nandi0813.practice.util.PermanentConfig; import dev.nandi0813.practice.util.UpdateChecker; import dev.nandi0813.practice.util.playerutil.PlayerUtil; +import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -28,8 +30,9 @@ public class PlayerJoin implements Listener { public void onPlayerJoin(PlayerJoinEvent e) { final Player player = e.getPlayer(); final UUID uuid = player.getUniqueId(); + e.joinMessage(Component.empty()); - Profile profile = ProfileManager.getInstance().getProfile(uuid); + Profile profile = ProfileManager.getInstance().getProfile(player); if (profile == null) profile = ProfileManager.getInstance().newProfile(player, uuid); @@ -42,7 +45,6 @@ public void onPlayerJoin(PlayerJoinEvent e) { NametagManager.getInstance().sendTeams(player); profile.setLastJoin(System.currentTimeMillis()); - PracticeStatsTelemetryLogger.markDirty(profile); // Check how many custom kits the player is allowed to save. int customKitPerm = profile.getCustomKitPerm(); @@ -61,6 +63,14 @@ public void onPlayerJoin(PlayerJoinEvent e) { profile1.setHideFromPlayers(true); }, 10L); + // If the player was disconnected while in a match, remove them from it + // to prevent ending up in the match with lobby items on rejoin + if (profile.getStatus() == ProfileStatus.MATCH) { + Match liveMatch = MatchManager.getInstance().getLiveMatchByPlayer(player); + if (liveMatch != null) + liveMatch.removePlayer(player, true); + } + InventoryManager.getInstance().setLobbyInventory(player, true); } else { ProfileManager.getInstance().getProfile(player).setStatus(ProfileStatus.OFFLINE); diff --git a/core/src/main/java/dev/nandi0813/practice/listener/PlayerQuit.java b/core/src/main/java/dev/nandi0813/practice/listener/PlayerQuit.java index fab348180..00cad7a64 100644 --- a/core/src/main/java/dev/nandi0813/practice/listener/PlayerQuit.java +++ b/core/src/main/java/dev/nandi0813/practice/listener/PlayerQuit.java @@ -10,8 +10,8 @@ import dev.nandi0813.practice.manager.profile.ProfileManager; import dev.nandi0813.practice.manager.profile.enums.ProfileStatus; import dev.nandi0813.practice.manager.server.ServerManager; -import dev.nandi0813.practice.telemetry.transport.stats.PracticeStatsTelemetryLogger; import dev.nandi0813.practice.util.cooldown.PlayerCooldown; +import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -20,11 +20,13 @@ import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerQuitEvent; +import java.util.UUID; + public class PlayerQuit implements Listener { @EventHandler ( priority = EventPriority.LOWEST ) public void onPlayerQuit(PlayerQuitEvent e) { - e.setQuitMessage(null); + e.quitMessage(Component.empty()); final Player player = e.getPlayer(); NametagManager.getInstance().onPlayerQuit(player); ServerManager.getInstance().onPlayerQuit(player); @@ -36,6 +38,7 @@ public void onPlayerQuit(PlayerQuitEvent e) { MessageCommand.latestMessage.remove(player); MessageCommand.latestMessage.values().removeIf(target -> target.equals(player)); + ProfileManager.getInstance().clearPlayerReference(player); final Profile profile = ProfileManager.getInstance().getProfile(player); final Party party = PartyManager.getInstance().getParty(player); @@ -49,7 +52,6 @@ public void onPlayerQuit(PlayerQuitEvent e) { profile.getActionBar().resetForReconnect(); profile.setLastJoin(System.currentTimeMillis()); - PracticeStatsTelemetryLogger.markDirty(profile); // Check how many custom kits the player is allowed to save. int customKitPerm = profile.getCustomKitPerm(); @@ -60,6 +62,10 @@ public void onPlayerQuit(PlayerQuitEvent e) { if (ZonePractice.getInstance().isEnabled()) { Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> profile.setStatus(ProfileStatus.OFFLINE), 5L); + + UUID uuid = player.getUniqueId(); + Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> + ProfileManager.getInstance().demoteOfflineProfile(uuid), 40L); } } } @@ -77,12 +83,19 @@ public void onPlayerKick(PlayerKickEvent e) { MessageCommand.latestMessage.remove(player); MessageCommand.latestMessage.values().removeIf(target -> target.equals(player)); + ProfileManager.getInstance().clearPlayerReference(player); MatchManager.getInstance().invalidateRematchByPlayer(player); Profile profile = ProfileManager.getInstance().getProfile(player); if (profile != null) { profile.getActionBar().resetForReconnect(); + + if (ZonePractice.getInstance().isEnabled()) { + UUID uuid = player.getUniqueId(); + Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> + ProfileManager.getInstance().demoteOfflineProfile(uuid), 40L); + } } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/ArenaManager.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/ArenaManager.java index ea2447616..433e06db8 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/ArenaManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/ArenaManager.java @@ -17,13 +17,13 @@ import dev.nandi0813.practice.util.StartUpCallback; import lombok.Getter; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.Listener; import java.io.File; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; @Getter public class ArenaManager implements Listener { @@ -37,7 +37,7 @@ public static ArenaManager getInstance() { } public static final boolean LOAD_CHUNKS = ConfigManager.getBoolean("ARENA.LOAD-CHUNKS"); - public static final List LOADED_CHUNKS = new ArrayList<>(); + public static final Set LOADED_CHUNK_KEYS = ConcurrentHashMap.newKeySet(); private final List arenaList = new ArrayList<>(); private final Map arenaCuboids = new HashMap<>(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/BasicArena.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/BasicArena.java index 2f336d17a..cb1977756 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/BasicArena.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/BasicArena.java @@ -97,13 +97,6 @@ public void loadChunks() { if (this.cuboid != null) { Bukkit.getScheduler().runTask(ZonePractice.getInstance(), () -> { ArenaUtil.loadArenaChunks(this); - - if (ArenaManager.LOAD_CHUNKS) { - // Collect only chunks that are already loaded — this avoids - // synchronous chunk loading on the main thread which caused - // server hangs of 10-15+ seconds. - ArenaManager.LOADED_CHUNKS.addAll(this.cuboid.getChunks()); - } }); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/DisplayArena.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/DisplayArena.java index 808421022..a6913b2e7 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/DisplayArena.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/DisplayArena.java @@ -17,7 +17,6 @@ import dev.nandi0813.practice.manager.gui.setup.arena.ArenaGUISetupManager; import dev.nandi0813.practice.manager.ladder.abstraction.normal.NormalLadder; import dev.nandi0813.practice.util.Common; -import dev.nandi0813.practice.util.StringUtil; import lombok.Getter; import lombok.Setter; import org.bukkit.Material; @@ -60,10 +59,12 @@ public void setIcon(final ItemStack icon) { this.icon = icon.clone(); - if (icon.hasItemMeta()) - this.displayName = StringUtil.CC(Common.getItemDisplayName(icon)); - else + if (icon.hasItemMeta()) { + String iconDisplayName = Common.getItemDisplayNameMiniMessage(icon); + this.displayName = iconDisplayName.isBlank() ? name : iconDisplayName; + } else { this.displayName = name; + } } public ItemStack getIcon() { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/NormalArena.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/NormalArena.java index 40cb04946..0a6c8218a 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/NormalArena.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/arenas/interfaces/NormalArena.java @@ -27,6 +27,9 @@ public abstract class NormalArena extends BasicArena implements DisplayName { protected PortalLocation portalLoc1; protected PortalLocation portalLoc2; + // Optional shared spawn point used by Party FFA style modes. + protected Location partyFfaCenter; + protected NormalArena(String name) { super(name); } @@ -105,6 +108,11 @@ public void setBasicData(YamlConfiguration config, String path) { config.set(path + "portallocation.2", portalLoc2.getCenter()); else config.set(path + "portallocation.2", null); + + if (partyFfaCenter != null) + config.set(path + "party-ffa-center", partyFfaCenter); + else + config.set(path + "party-ffa-center", null); } public void getBasicData(YamlConfiguration config, String path) { @@ -142,6 +150,9 @@ public void getBasicData(YamlConfiguration config, String path) { portalLoc1 = new PortalLocation((Location) config.get(path + "portallocation.1")); if (config.get(path + "portallocation.2") != null) portalLoc2 = new PortalLocation((Location) config.get(path + "portallocation.2")); + + if (config.get(path + "party-ffa-center") != null) + partyFfaCenter = (Location) config.get(path + "party-ffa-center"); } public List getPortalLocations() { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/listener/ArenaListener.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/listener/ArenaListener.java index d6029b626..7997d866c 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/listener/ArenaListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/listener/ArenaListener.java @@ -27,7 +27,7 @@ import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.WorldUnloadEvent; -import static dev.nandi0813.practice.manager.arena.ArenaManager.LOADED_CHUNKS; +import static dev.nandi0813.practice.manager.arena.ArenaManager.LOADED_CHUNK_KEYS; import static dev.nandi0813.practice.manager.arena.ArenaManager.LOAD_CHUNKS; public class ArenaListener implements Listener { @@ -167,7 +167,8 @@ public void onPlayerInteract(PlayerInteractEvent e) { @EventHandler public void onChunkUnload(ChunkUnloadEvent e) { if (LOAD_CHUNKS) { - if (LOADED_CHUNKS.contains(e.getChunk())) { + long chunkKey = ArenaUtil.chunkKey(e.getChunk().getX(), e.getChunk().getZ()); + if (LOADED_CHUNK_KEYS.contains(chunkKey)) { // Use addPluginChunkTicket to force-keep the chunk loaded. // This is safe from recursion (unlike getChunkAtAsync which can // trigger chunk scheduling → more unloads → StackOverflowError). diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/ArenaSetupListener.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/ArenaSetupListener.java index b1dc8e6df..bd6151940 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/ArenaSetupListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/ArenaSetupListener.java @@ -54,7 +54,7 @@ public void onInteract(PlayerInteractEvent event) { DisplayArena displayArena = session.getArena(); if (displayArena == null) { - player.sendMessage(Common.colorize("&cArena not found!")); + Common.sendMMMessage(player, "Arena not found!"); setupManager.stopSetup(player); return; } @@ -125,7 +125,7 @@ private void handleModeSwitch(Player player, ArenaSetupManager.SetupSession sess return; } setupManager.updateWand(player); - player.sendMessage(Common.colorize("&eSwitched to: &f" + session.getCurrentMode().getDisplayName())); + Common.sendMMMessage(player, "Switched to: " + session.getCurrentMode().getDisplayName()); } private void handleStandardPositions(Player player, Arena arena, Action action, PlayerInteractEvent event) { @@ -145,7 +145,7 @@ private void handleStandardPositions(Player player, Arena arena, Action action, if (action == Action.LEFT_CLICK_BLOCK) { // Check minimum distance from position 2 if (arena.getPosition2() != null && arena.getPosition2().distance(loc) < 1.0) { - player.sendMessage(Common.colorize("&cSpawn positions must be at least 1 block apart!")); + Common.sendMMMessage(player, "Spawn positions must be at least 1 block apart!"); return; } arena.setPosition1(loc); @@ -154,7 +154,7 @@ private void handleStandardPositions(Player player, Arena arena, Action action, } else { // Check minimum distance from position 1 if (arena.getPosition1() != null && arena.getPosition1().distance(loc) < 1.0) { - player.sendMessage(Common.colorize("&cSpawn positions must be at least 1 block apart!")); + Common.sendMMMessage(player, "Spawn positions must be at least 1 block apart!"); return; } arena.setPosition2(loc); @@ -183,8 +183,8 @@ private void handleFFAPositions(Player player, FFAArena ffaArena, Action action, // Check minimum distance from all existing spawns (must be at least 1 block apart) for (Location existingSpawn : ffaArena.getFfaPositions()) { if (existingSpawn.distance(loc) < 1.0) { - player.sendMessage(Common.colorize("&cSpawn positions must be at least 1 block apart from each other!")); - player.sendMessage(Common.colorize("&7Too close to an existing spawn position.")); + Common.sendMMMessage(player, "Spawn positions must be at least 1 block apart from each other!"); + Common.sendMMMessage(player, "Too close to an existing spawn position."); return; } } @@ -203,9 +203,9 @@ private void handleFFAPositions(Player player, FFAArena ffaArena, Action action, ffaArena.getFfaPositions().remove(index); SpawnMarkerManager.getInstance().updateMarkers(ffaArena); updateGui(ffaArena); - player.sendMessage(Common.colorize("&cRemoved last FFA spawn point. Remaining: " + index)); + Common.sendMMMessage(player, "Removed last FFA spawn point. Remaining: " + index); } else { - player.sendMessage(Common.colorize("&cNo spawn points to remove.")); + Common.sendMMMessage(player, "No spawn points to remove."); } } } @@ -330,7 +330,7 @@ private void handleBuildMax(Player player, DisplayArena arena, Action action) { if (action.name().contains("LEFT")) { arena.setBuildMax(false); arena.setBuildMaxValue(ConfigManager.getInt("MATCH-SETTINGS.BUILD-LIMIT-DEFAULT")); - player.sendMessage(Common.colorize("&cBuild Height Limit disabled for " + arena.getName())); + Common.sendMMMessage(player, "Build Height Limit disabled for " + arena.getName()); return; } @@ -352,7 +352,7 @@ private void handleDeadZone(Player player, DisplayArena arena, Action action) { if (action.name().contains("LEFT")) { arena.setDeadZone(false); - player.sendMessage(Common.colorize("&cDead Zone disabled for " + arena.getName())); + Common.sendMMMessage(player, "Dead Zone disabled for " + arena.getName()); return; } @@ -550,34 +550,34 @@ public void onMarkerInteract(PlayerInteractAtEntityEvent event) { // Check if player is in setup mode if (!setupManager.isSettingUp(player)) { - player.sendMessage(Common.colorize("&cYou must be in setup mode to remove spawn markers.")); + Common.sendMMMessage(player, "You must be in setup mode to remove spawn markers."); return; } // Find which arena this marker belongs to DisplayArena arena = SpawnMarkerManager.getInstance().getArenaForMarker(mannequin); if (arena == null) { - player.sendMessage(Common.colorize("&cCould not find arena for this marker.")); + Common.sendMMMessage(player, "Could not find arena for this marker."); return; } // ONLY allow for FFA arenas if (!(arena instanceof FFAArena ffaArena)) { - player.sendMessage(Common.colorize("&cDirect marker removal only works for FFA arenas.")); - player.sendMessage(Common.colorize("&7Use left/right click on blocks to set standard arena spawn positions.")); + Common.sendMMMessage(player, "Direct marker removal only works for FFA arenas."); + Common.sendMMMessage(player, "Use left/right click on blocks to set standard arena spawn positions."); return; } // Check if player is setting up this arena ArenaSetupManager.SetupSession session = setupManager.getSession(player); if (session == null || !session.getArena().equals(arena)) { - player.sendMessage(Common.colorize("&cYou are not currently setting up this arena.")); + Common.sendMMMessage(player, "You are not currently setting up this arena."); return; } // Check if in correct mode if (session.getCurrentMode() != SetupMode.FFA_POSITIONS) { - player.sendMessage(Common.colorize("&cSwitch to FFA Positions mode to remove spawn markers.")); + Common.sendMMMessage(player, "Switch to FFA Positions mode to remove spawn markers."); return; } @@ -587,9 +587,9 @@ public void onMarkerInteract(PlayerInteractAtEntityEvent event) { SpawnMarkerManager.getInstance().updateMarkers(arena); updateGui(arena); - player.sendMessage(Common.colorize("&cRemoved FFA spawn. Remaining: " + ffaArena.getFfaPositions().size())); + Common.sendMMMessage(player, "Removed FFA spawn. Remaining: " + ffaArena.getFfaPositions().size()); } else { - player.sendMessage(Common.colorize("&cFailed to remove spawn marker.")); + Common.sendMMMessage(player, "Failed to remove spawn marker."); } } @@ -629,9 +629,9 @@ public void onMarkerDamage(EntityDamageByEntityEvent event) { ffaArena.getFfaPositions().remove(index); SpawnMarkerManager.getInstance().updateMarkers(ffaArena); updateGui(ffaArena); - player.sendMessage(Common.colorize("&cRemoved last FFA spawn point. Remaining: " + index)); + Common.sendMMMessage(player, "Removed last FFA spawn point. Remaining: " + index); } else { - player.sendMessage(Common.colorize("&cNo spawn points to remove.")); + Common.sendMMMessage(player, "No spawn points to remove."); } } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/ArenaSetupManager.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/ArenaSetupManager.java index 56b891b54..f6241301a 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/ArenaSetupManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/ArenaSetupManager.java @@ -73,7 +73,7 @@ public boolean startSetup(Player player, DisplayArena arena) { // Show spawn position markers SpawnMarkerManager.getInstance().showMarkers(arena); - player.sendMessage(Common.colorize("&aSetup mode started for arena: &e" + arena.getName() + "&a.")); + Common.sendMMMessage(player, "Setup mode started for arena: " + arena.getName() + "."); return true; } @@ -95,7 +95,7 @@ public void stopSetup(Player player) { SpawnMarkerManager.getInstance().clearMarkers(arena); } - player.sendMessage(Common.colorize("&cSetup mode ended for arena: &c" + arena.getName() + ".")); + Common.sendMMMessage(player, "Setup mode ended for arena: " + arena.getName() + "."); } public SetupSession getSession(Player player) { @@ -178,25 +178,25 @@ public void updateWand(Player player) { ItemMeta meta = wand.getItemMeta(); SetupMode mode = session.getCurrentMode(); - meta.displayName(Common.legacyToComponent(Common.colorize("&6Arena Wand &7(&e" + mode.getDisplayName() + "&7)"))); + meta.displayName(Common.legacyToComponent(Common.colorize("Arena Wand (" + mode.getDisplayName() + ")"))); List lore = new ArrayList<>(); - lore.add(Common.colorize("&7Editing: &a" + arena.getName())); - lore.add(Common.colorize("&7Type: &b" + (arena instanceof FFAArena ? "FFA" : "Standard"))); + lore.add(Common.colorize("Editing: " + arena.getName())); + lore.add(Common.colorize("Type: " + (arena instanceof FFAArena ? "FFA" : "Standard"))); lore.add(""); - lore.add(Common.colorize("&eCurrent Mode: &f" + mode.getDisplayName())); + lore.add(Common.colorize("Current Mode: " + mode.getDisplayName())); lore.add(""); - lore.add(Common.colorize("&7Controls:")); + lore.add(Common.colorize("Controls:")); for (String line : mode.getDescription()) { lore.add(Common.colorize(line)); } lore.add(""); - lore.add(Common.colorize("&dShift + Left: &7Next Mode")); - lore.add(Common.colorize("&dShift + Right: &7Prev Mode")); + lore.add(Common.colorize("Shift + Left: Next Mode")); + lore.add(Common.colorize("Shift + Right: Prev Mode")); lore.add(""); - lore.add(Common.colorize("&cDrop (Q): &7Exit Setup")); + lore.add(Common.colorize("Drop (Q): Exit Setup")); meta.lore(lore.stream().map(Common::legacyToComponent).collect(Collectors.toList())); wand.setItemMeta(meta); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/SetupMode.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/SetupMode.java index 5926619bd..a7ccec357 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/SetupMode.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/SetupMode.java @@ -6,43 +6,43 @@ public enum SetupMode { CORNERS("Corner Selection", new String[]{ - "&b Left Click: &fSet Corner 1", - "&b Right Click: &fSet Corner 2" + " Left Click: Set Corner 1", + " Right Click: Set Corner 2" }), POSITIONS("Spawn Points (Standard)", new String[]{ - "&b Left Click Block: &fSet Position 1 (Blue)", - "&b Right Click Block: &fSet Position 2 (Red)" + " Left Click Block: Set Position 1 (Blue)", + " Right Click Block: Set Position 2 (Red)" }), FFA_POSITIONS("Spawn Points (FFA)", new String[]{ - "&b Right Click Block: &fAdd Spawn Point", - "&b Right Click Armor Stand: &fRemove That Spawn", - "&b Left Click (Anywhere): &fRemove Last Spawn" + " Right Click Block: Add Spawn Point", + " Right Click Armor Stand: Remove That Spawn", + " Left Click (Anywhere): Remove Last Spawn" }), BUILD_MAX("Build Height Limit", new String[]{ - "&b Right Click: &fSet to Current Y-Level", - "&b Left Click: &fDisable Build Limit" + " Right Click: Set to Current Y-Level", + " Left Click: Disable Build Limit" }), DEAD_ZONE("Dead Zone (Void)", new String[]{ - "&b Right Click: &fSet to Current Y-Level", - "&b Left Click: &fDisable Dead Zone" + " Right Click: Set to Current Y-Level", + " Left Click: Disable Dead Zone" }), BED_LOCATIONS("Bed Locations", new String[]{ - "&b Left Click: &fSet Blue Bed", - "&b Right Click: &fSet Red Bed" + " Left Click: Set Blue Bed", + " Right Click: Set Red Bed" }), PORTALS("Portal Setup", new String[]{ - "&b Right Click: &fAdd Portal Region", - "&b Left Click: &fRemove Portal Region" + " Right Click: Add Portal Region", + " Left Click: Remove Portal Region" }), TOGGLE_STATUS("Arena Status", new String[]{ - "&b Right Click: &fEnable Arena", + " Right Click: Enable Arena", }); private final String displayName; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/SpawnMarkerManager.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/SpawnMarkerManager.java index 37a171923..4082534b3 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/SpawnMarkerManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/setup/SpawnMarkerManager.java @@ -59,13 +59,13 @@ public void showMarkers(DisplayArena arena) { if (arena instanceof Arena standardArena) { // Show position 1 if (standardArena.getPosition1() != null) { - Mannequin marker = createMarker(standardArena.getPosition1(), "&c&lSpawn 1"); + Mannequin marker = createMarker(standardArena.getPosition1(), "Spawn 1"); if (marker != null) markers.add(marker); } // Show position 2 if (standardArena.getPosition2() != null) { - Mannequin marker = createMarker(standardArena.getPosition2(), "&c&lSpawn 2"); + Mannequin marker = createMarker(standardArena.getPosition2(), "Spawn 2"); if (marker != null) markers.add(marker); } } else if (arena instanceof FFAArena ffaArena) { @@ -73,7 +73,7 @@ public void showMarkers(DisplayArena arena) { int index = 0; // Use 0-based index to match the list for (Location spawnLoc : ffaArena.getFfaPositions()) { // Create main marker with player model - Mannequin marker = createMarker(spawnLoc, "&c&lFFA Spawn #" + (index + 1)); // Display as 1-based + Mannequin marker = createMarker(spawnLoc, "FFA Spawn #" + (index + 1)); // Display as 1-based if (marker != null) { markers.add(marker); // Track this main marker to its spawn index @@ -81,7 +81,7 @@ public void showMarkers(DisplayArena arena) { // Create second mannequin above for instruction text (closer spacing) Location labelLoc = spawnLoc.clone().add(0, 2.3, 0); - Mannequin labelStand = createLabelOnly(labelLoc, "&7(Right-click to remove)"); + Mannequin labelStand = createLabelOnly(labelLoc, "(Right-click to remove)"); if (labelStand != null) { markers.add(labelStand); } @@ -108,7 +108,7 @@ private Mannequin createMarker(@NotNull Location location, @NotNull String name) mannequin.setGravity(false); mannequin.setCanPickupItems(false); mannequin.setCustomNameVisible(true); - mannequin.customName(Component.text(dev.nandi0813.practice.util.StringUtil.CC(name))); + mannequin.customName(dev.nandi0813.practice.util.Common.deserializeMiniMessage(name)); mannequin.setAI(false); mannequin.setCollidable(false); mannequin.setSilent(true); @@ -152,7 +152,7 @@ private Mannequin createLabelOnly(Location location, String text) { labelStand.setGravity(false); labelStand.setCanPickupItems(false); labelStand.setCustomNameVisible(true); - labelStand.customName(Component.text(dev.nandi0813.practice.util.StringUtil.CC(text))); + labelStand.customName(dev.nandi0813.practice.util.Common.deserializeMiniMessage(text)); labelStand.setAI(false); labelStand.setCollidable(false); labelStand.setSilent(true); @@ -319,7 +319,7 @@ public boolean removeMarker(Mannequin mannequin, DisplayArena arena) { * or were not properly removed due to timing issues. *

* Orphaned markers are identified by: - * - Having a custom name starting with "&c&l" (our marker naming pattern) + * - Having a custom name starting with "" (our marker naming pattern) * - Being in the arenas world * - Not being tracked in our current marker lists * diff --git a/core/src/main/java/dev/nandi0813/practice/manager/arena/util/ArenaUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/arena/util/ArenaUtil.java index 07e3f4175..004cbf47d 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/arena/util/ArenaUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/arena/util/ArenaUtil.java @@ -1,5 +1,6 @@ package dev.nandi0813.practice.manager.arena.util; +import dev.nandi0813.practice.manager.arena.ArenaManager; import dev.nandi0813.practice.manager.arena.arenas.Arena; import dev.nandi0813.practice.manager.arena.arenas.ArenaCopy; import dev.nandi0813.practice.manager.arena.arenas.FFAArena; @@ -146,7 +147,7 @@ public static boolean changeStatus(Player player, DisplayArena arena) { List editors = new ArrayList<>(setupManager.getPlayersSettingUpArena(arena)); for (Player editor : editors) { setupManager.stopSetup(editor); - editor.sendMessage(Common.colorize("&cSetup mode force ended because the arena has been &aENABLED&c!")); + Common.sendMMMessage(editor, "Setup mode force ended because the arena has been ENABLED!"); } } @@ -273,6 +274,9 @@ public static void loadArenaChunks(BasicArena arena) { org.bukkit.plugin.Plugin plugin = dev.nandi0813.practice.ZonePractice.getInstance(); for (int cx = minCX; cx <= maxCX; cx++) { for (int cz = minCZ; cz <= maxCZ; cz++) { + if (ArenaManager.LOAD_CHUNKS) { + ArenaManager.LOADED_CHUNK_KEYS.add(chunkKey(cx, cz)); + } // addPluginChunkTicket loads the chunk asynchronously if needed // and prevents it from being unloaded — no main-thread stall. world.addPluginChunkTicket(cx, cz, plugin); @@ -280,6 +284,10 @@ public static void loadArenaChunks(BasicArena arena) { } } + public static long chunkKey(int cx, int cz) { + return ((long) cx << 32) ^ (cz & 0xffffffffL); + } + public static void setMannequinItemInHand(Mannequin mannequin, ItemStack item, boolean rightHand) { if (mannequin == null) return; if (mannequin.getEquipment() == null) return; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/backend/ConfigManager.java b/core/src/main/java/dev/nandi0813/practice/manager/backend/ConfigManager.java index fcdc34a15..192f9031c 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/backend/ConfigManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/backend/ConfigManager.java @@ -3,7 +3,6 @@ import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.gui.GUIItem; import dev.nandi0813.practice.util.Common; -import dev.nandi0813.practice.util.StringUtil; import lombok.Getter; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; @@ -51,7 +50,7 @@ public static Object get(String loc) { public static String getString(String loc) { String s = config.getString(loc); if (s != null) - return StringUtil.CC(s); + return s; return ""; } @@ -80,7 +79,7 @@ public static Set getConfigSectionKeys(String loc) { } public static List getList(String loc) { - return StringUtil.CC(getConfig().getStringList(loc)); + return getConfig().getStringList(loc); } public static Set getConfigList(String loc) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/backend/GUIFile.java b/core/src/main/java/dev/nandi0813/practice/manager/backend/GUIFile.java index ed52dbe0d..f00e47d4f 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/backend/GUIFile.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/backend/GUIFile.java @@ -3,7 +3,6 @@ import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.gui.GUIItem; import dev.nandi0813.practice.util.Common; -import dev.nandi0813.practice.util.StringUtil; import lombok.Getter; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; @@ -42,7 +41,7 @@ public static void reload() { } public static String getString(String loc) { - return StringUtil.CC(config.getString(loc.toUpperCase())); + return config.getString(loc.toUpperCase()); } public static int getInt(String loc) { @@ -50,7 +49,7 @@ public static int getInt(String loc) { } public static List getStringList(String loc) { - return StringUtil.CC(config.getStringList(loc.toUpperCase())); + return config.getStringList(loc.toUpperCase()); } public static GUIItem getGuiItem(String loc) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/backend/MysqlManager.java b/core/src/main/java/dev/nandi0813/practice/manager/backend/MysqlManager.java index 0cb512021..dab3cd820 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/backend/MysqlManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/backend/MysqlManager.java @@ -56,6 +56,9 @@ public enum MysqlManager { "rankedWins=VALUES(rankedWins), rankedLosses=VALUES(rankedLosses), rankedWinStreak=VALUES(rankedWinStreak), " + "rankedBestWinStreak=VALUES(rankedBestWinStreak), rankedLoseStreak=VALUES(rankedLoseStreak), " + "rankedBestLoseStreak=VALUES(rankedBestLoseStreak), elo=VALUES(elo), `rank`=VALUES(`rank`), kills=VALUES(kills), deaths=VALUES(deaths);"; + private static final int RETRYABLE_WRITE_MAX_ATTEMPTS = 3; + private static final long RETRYABLE_WRITE_BASE_DELAY_MS = 40L; + private static final Object[] PROFILE_WRITE_LOCKS = createLockStripes(64); public static void openConnection() { if (!ConfigManager.getBoolean("MYSQL-DATABASE.ENABLED")) return; @@ -71,7 +74,7 @@ public static void openConnection() { try { // Explicitly load the MariaDB driver to ensure it's available for JDBC DriverManager - Class.forName("org.mariadb.jdbc.Driver"); + Class.forName("dev.nandi0813.practice.dependencies.mariadb.Driver"); HikariConfig config = new HikariConfig(); config.setJdbcUrl(url); @@ -150,18 +153,15 @@ public static Connection getConnection() throws SQLException { } public static CompletableFuture saveProfileAsync(Profile profile) { - if (!isConnected(true)) { + if (profile == null || !isConnected(true)) { return CompletableFuture.completedFuture(null); } - return CompletableFuture.runAsync(() -> { - try (Connection connection = getConnection()) { + return CompletableFuture.runAsync(() -> + executeProfileWriteWithRetry(profile.getUuid(), "[MySQL] save profile", connection -> { saveGlobalStats(connection, profile); saveLadderStats(connection, profile); - } catch (SQLException e) { - Common.sendConsoleMMMessage("Error: " + e.getMessage()); - } - }, getExecutor()); + }), getExecutor()); } public static CompletableFuture saveProfilesAsync(Collection profiles) { @@ -170,6 +170,7 @@ public static CompletableFuture saveProfilesAsync(Collection prof } CompletableFuture[] futures = profiles.stream() + .filter(Objects::nonNull) .map(MysqlManager::saveProfileAsync) .toArray(CompletableFuture[]::new); return CompletableFuture.allOf(futures); @@ -180,18 +181,21 @@ public static void saveProfilesBlocking(Collection profiles) { return; } - try (Connection connection = getConnection()) { - int saved = 0; - for (Profile profile : profiles) { + int saved = 0; + for (Profile profile : profiles) { + if (profile == null) { + continue; + } + + if (executeProfileWriteWithRetry(profile.getUuid(), "[MySQL] save profile", connection -> { saveGlobalStats(connection, profile); saveLadderStats(connection, profile); + })) { saved++; } - - Common.sendConsoleMMMessage("MySQL shutdown flush completed: " + saved + " profiles saved."); - } catch (SQLException e) { - Common.sendConsoleMMMessage("Error: " + e.getMessage()); } + + Common.sendConsoleMMMessage("MySQL shutdown flush completed: " + saved + " profiles saved."); } public static CompletableFuture loadProfileAsync(Profile profile) { @@ -225,8 +229,8 @@ public static CompletableFuture deleteProfileStatsAsync(UUID uuid) { return CompletableFuture.completedFuture(null); } - return CompletableFuture.runAsync(() -> { - try (Connection connection = getConnection()) { + return CompletableFuture.runAsync(() -> + executeProfileWriteWithRetry(uuid, "[MySQL] delete profile stats", connection -> { try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM global_stats WHERE uuid=?;")) { stmt.setString(1, uuid.toString()); stmt.executeUpdate(); @@ -236,10 +240,7 @@ public static CompletableFuture deleteProfileStatsAsync(UUID uuid) { stmt.setString(1, uuid.toString()); stmt.executeUpdate(); } - } catch (SQLException e) { - Common.sendConsoleMMMessage("Error: " + e.getMessage()); - } - }, getExecutor()); + }), getExecutor()); } public static CompletableFuture deleteLadderStatsAsync(String ladderName) { @@ -247,15 +248,13 @@ public static CompletableFuture deleteLadderStatsAsync(String ladderName) return CompletableFuture.completedFuture(null); } - return CompletableFuture.runAsync(() -> { - try (Connection connection = getConnection(); - PreparedStatement stmt = connection.prepareStatement("DELETE FROM ladder_stats WHERE ladder=?;")) { - stmt.setString(1, ladderName); - stmt.executeUpdate(); - } catch (SQLException e) { - Common.sendConsoleMMMessage("Error: " + e.getMessage()); - } - }, getExecutor()); + return CompletableFuture.runAsync(() -> + executeWriteWithRetry("[MySQL] delete ladder stats", connection -> { + try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM ladder_stats WHERE ladder=?;")) { + stmt.setString(1, ladderName); + stmt.executeUpdate(); + } + }), getExecutor()); } private static void initDB() throws IOException, SQLException { @@ -398,10 +397,14 @@ private static void saveLadderStats(Connection connection, Profile profile) thro return; } + List> orderedLadderStats = + new ArrayList<>(profile.getStats().getLadderStats().entrySet()); + orderedLadderStats.sort(Comparator.comparing(entry -> entry.getKey().getName(), String.CASE_INSENSITIVE_ORDER)); + try (PreparedStatement stmt = connection.prepareStatement(LADDER_STATS_UPSERT)) { String username = profile.getPlayer().getName() != null ? profile.getPlayer().getName() : profile.getUuid().toString(); - for (Map.Entry entry : profile.getStats().getLadderStats().entrySet()) { + for (Map.Entry entry : orderedLadderStats) { NormalLadder ladder = entry.getKey(); LadderStats ladderStats = entry.getValue(); @@ -431,6 +434,73 @@ private static void saveLadderStats(Connection connection, Profile profile) thro } } + @FunctionalInterface + private interface SqlWriteOperation { + void run(Connection connection) throws SQLException; + } + + private static boolean executeProfileWriteWithRetry(UUID uuid, String operation, SqlWriteOperation writeOperation) { + if (uuid == null) { + return executeWriteWithRetry(operation, writeOperation); + } + + synchronized (getProfileWriteLock(uuid)) { + return executeWriteWithRetry(operation, writeOperation); + } + } + + private static boolean executeWriteWithRetry(String operation, SqlWriteOperation writeOperation) { + int attempt = 1; + while (attempt <= RETRYABLE_WRITE_MAX_ATTEMPTS) { + try (Connection connection = getConnection()) { + writeOperation.run(connection); + return true; + } catch (SQLException e) { + if (isRetryableWriteError(e) && attempt < RETRYABLE_WRITE_MAX_ATTEMPTS) { + sleepBeforeRetry(attempt); + attempt++; + continue; + } + Common.sendConsoleMMMessage("" + operation + " error: " + e.getMessage()); + return false; + } + } + return false; + } + + private static boolean isRetryableWriteError(SQLException e) { + for (SQLException sqlException = e; sqlException != null; sqlException = sqlException.getNextException()) { + int errorCode = sqlException.getErrorCode(); + String sqlState = sqlException.getSQLState(); + if (errorCode == 1213 || errorCode == 1205 || "40001".equals(sqlState) || "41000".equals(sqlState)) { + return true; + } + } + return false; + } + + private static void sleepBeforeRetry(int attempt) { + long delay = RETRYABLE_WRITE_BASE_DELAY_MS * attempt + + ThreadLocalRandom.current().nextLong(20L, 81L); + try { + Thread.sleep(delay); + } catch (InterruptedException interruptedException) { + Thread.currentThread().interrupt(); + } + } + + private static Object getProfileWriteLock(UUID uuid) { + return PROFILE_WRITE_LOCKS[Math.floorMod(uuid.hashCode(), PROFILE_WRITE_LOCKS.length)]; + } + + private static Object[] createLockStripes(int size) { + Object[] locks = new Object[size]; + for (int i = 0; i < size; i++) { + locks[i] = new Object(); + } + return locks; + } + private static void loadGlobalStats(Connection connection, Profile profile) throws SQLException { try (PreparedStatement stmt = connection.prepareStatement("SELECT * FROM global_stats WHERE uuid=? LIMIT 1;")) { stmt.setString(1, profile.getUuid().toString()); @@ -525,17 +595,14 @@ public static void saveMatchHistoryAsync(UUID playerUuid, UUID opponentUuid, UUID winnerUuid, int matchDuration, long playedAt) { if (!isConnected(false)) return; - CompletableFuture.runAsync(() -> { - try (Connection conn = getConnection()) { - insertMatchHistoryRow(conn, playerUuid, opponentUuid, playerName, opponentName, - kitName, arenaName, playerScore, opponentScore, - playerFinalHealth, opponentFinalHealth, winnerUuid, matchDuration, playedAt); - pruneMatchHistory(conn, playerUuid); - pruneMatchHistory(conn, opponentUuid); - } catch (SQLException e) { - Common.sendConsoleMMMessage("[MatchHistory] MySQL save error: " + e.getMessage()); - } - }, getExecutor()); + CompletableFuture.runAsync(() -> + executeWriteWithRetry("[MatchHistory] MySQL save", conn -> { + insertMatchHistoryRow(conn, playerUuid, opponentUuid, playerName, opponentName, + kitName, arenaName, playerScore, opponentScore, + playerFinalHealth, opponentFinalHealth, winnerUuid, matchDuration, playedAt); + pruneMatchHistory(conn, playerUuid); + pruneMatchHistory(conn, opponentUuid); + }), getExecutor()); } /** diff --git a/core/src/main/java/dev/nandi0813/practice/manager/division/Division.java b/core/src/main/java/dev/nandi0813/practice/manager/division/Division.java index 4c0c0545c..306d28c7d 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/division/Division.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/division/Division.java @@ -1,6 +1,7 @@ package dev.nandi0813.practice.manager.division; import dev.nandi0813.practice.ZonePractice; +import dev.nandi0813.practice.util.StringUtil; import lombok.Getter; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -48,11 +49,11 @@ public boolean isValid() { } public Component getComponentFullName() { - return ZonePractice.getMiniMessage().deserialize(fullName); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(fullName)); } public Component getComponentShortName() { - return ZonePractice.getMiniMessage().deserialize(shortName); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(shortName)); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/EventManager.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/EventManager.java index be7c2c56a..e3518a56a 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/EventManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/EventManager.java @@ -37,7 +37,6 @@ import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.KitData; import dev.nandi0813.practice.util.StartUpCallback; -import dev.nandi0813.practice.util.StringUtil; import lombok.Getter; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; @@ -313,10 +312,6 @@ private Component toTitleComponent(String line) { return Component.empty(); } - if (line.contains("&") || line.contains("§")) { - line = StringUtil.legacyColorToMiniMessage(line); - } - return Common.deserializeMiniMessage(line); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/enums/EventType.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/enums/EventType.java index 25c4a1da4..8039baab1 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/enums/EventType.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/enums/EventType.java @@ -15,7 +15,7 @@ public enum EventType { LMS( 10, ConfigManager.getString("EVENT.LMS.NAME"), - ItemCreateUtil.createItem("&eLast Man Standing", Material.DIAMOND_SWORD), + ItemCreateUtil.createItem("Last Man Standing", Material.DIAMOND_SWORD), 15, LanguageManager.getString("COMMAND.EVENT.ARGUMENTS.LMS.BROADCAST"), ConfigManager.getList("EVENT.LMS.WINNER-COMMAND"), @@ -29,7 +29,7 @@ public enum EventType { OITC( 11, ConfigManager.getString("EVENT.OITC.NAME"), - ItemCreateUtil.createItem("&6One In The Chamber", Material.BOW), + ItemCreateUtil.createItem("One In The Chamber", Material.BOW), 15, LanguageManager.getString("COMMAND.EVENT.ARGUMENTS.OITC.BROADCAST"), ConfigManager.getList("EVENT.OITC.WINNER-COMMAND"), @@ -43,7 +43,7 @@ public enum EventType { TNTTAG( 12, ConfigManager.getString("EVENT.TNTTAG.NAME"), - ItemCreateUtil.createItem("&cTNT Tag", Material.TNT), + ItemCreateUtil.createItem("TNT Tag", Material.TNT), 15, LanguageManager.getString("COMMAND.EVENT.ARGUMENTS.TNTTAG.BROADCAST"), ConfigManager.getList("EVENT.TNTTAG.WINNER-COMMAND"), @@ -57,7 +57,7 @@ public enum EventType { BRACKETS( 13, ConfigManager.getString("EVENT.BRACKETS.NAME"), - ItemCreateUtil.createItem("&aBrackets", Material.POTION, Short.valueOf("34")), + ItemCreateUtil.createItem("Brackets", Material.POTION, Short.valueOf("34")), 15, LanguageManager.getString("COMMAND.EVENT.ARGUMENTS.BRACKETS.BROADCAST"), ConfigManager.getList("EVENT.BRACKETS.WINNER-COMMAND"), @@ -71,7 +71,7 @@ public enum EventType { SUMO( 14, ConfigManager.getString("EVENT.SUMO.NAME"), - ItemCreateUtil.createItem("&6Sumo", Material.STICK), + ItemCreateUtil.createItem("Sumo", Material.STICK), 15, LanguageManager.getString("COMMAND.EVENT.ARGUMENTS.SUMO.BROADCAST"), ConfigManager.getList("EVENT.SUMO.WINNER-COMMAND"), @@ -85,7 +85,7 @@ public enum EventType { SPLEGG( 15, ConfigManager.getString("EVENT.SPLEGG.NAME"), - ItemCreateUtil.createItem("&bSplegg", Material.EGG), + ItemCreateUtil.createItem("Splegg", Material.EGG), 15, LanguageManager.getString("COMMAND.EVENT.ARGUMENTS.SPLEGG.BROADCAST"), ConfigManager.getList("EVENT.SPLEGG.WINNER-COMMAND"), @@ -99,7 +99,7 @@ public enum EventType { JUGGERNAUT( 16, ConfigManager.getString("EVENT.JUGGERNAUT.NAME"), - ItemCreateUtil.createItem("&6Juggernaut", Material.GOLDEN_APPLE), + ItemCreateUtil.createItem("Juggernaut", Material.GOLDEN_APPLE), 15, LanguageManager.getString("COMMAND.EVENT.ARGUMENTS.JUGGERNAUT.BROADCAST"), ConfigManager.getList("EVENT.JUGGERNAUT.WINNER-COMMAND"), diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/events/ffa/interfaces/FFAEvent.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/events/ffa/interfaces/FFAEvent.java index 52795e26c..127625c00 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/events/ffa/interfaces/FFAEvent.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/events/ffa/interfaces/FFAEvent.java @@ -35,7 +35,7 @@ public FFAEvent(Object starter, EventData eventData, String languagePath) { public void teleport(final Player player) { // Safety check: ensure spawns list is not empty if (eventData.getSpawns() == null || eventData.getSpawns().isEmpty()) { - player.sendMessage(Common.colorize("&cError: No spawn points configured for this event!")); + Common.sendMMMessage(player, "Error: No spawn points configured for this event!"); return; } @@ -49,7 +49,7 @@ public void teleport(final Player player) { // Safety check: ensure spawn location is valid if (spawnLocation == null || spawnLocation.getWorld() == null) { - player.sendMessage(Common.colorize("&cError: Invalid spawn location!")); + Common.sendMMMessage(player, "Error: Invalid spawn location!"); return; } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/events/onevsall/tnttag/TNTTagListener.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/events/onevsall/tnttag/TNTTagListener.java index 387ab1274..69ae30680 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/events/onevsall/tnttag/TNTTagListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/events/onevsall/tnttag/TNTTagListener.java @@ -70,7 +70,7 @@ public void onPlayerQuit(Event event, PlayerQuitEvent e) { continue; } - tntTag.sendMessage("&cSince " + player.getName() + " left the game, the new IT will be " + eventPlayer.getName() + ".", true); + tntTag.sendMessage("Since " + player.getName() + " left the game, the new IT will be " + eventPlayer.getName() + ".", true); tntTag.setTag(null, eventPlayer); break; } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSetupListener.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSetupListener.java index f5b5bd908..845eefd90 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSetupListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSetupListener.java @@ -71,7 +71,7 @@ public void onInteract(PlayerInteractEvent event) { EventData eventData = session.getEventData(); if (eventData == null) { - player.sendMessage(Common.colorize("&cEvent not found!")); + Common.sendMMMessage(player, "Event not found!"); setupManager.stopSetup(player); return; } @@ -193,7 +193,7 @@ public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) { if (spawnIndex < 0 || spawnIndex >= eventData.getSpawns().size()) { markerManager.updateMarkers(eventData); updateGui(eventData); - player.sendMessage(Common.colorize("&cThis spawn marker is outdated. Markers have been refreshed.")); + Common.sendMMMessage(player, "This spawn marker is outdated. Markers have been refreshed."); return; } @@ -202,7 +202,7 @@ public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) { updateGui(eventData); scheduleSave(eventData); - player.sendMessage(Common.colorize("&aRemoved spawn point #" + (spawnIndex + 1) + ". Remaining: " + eventData.getSpawns().size())); + Common.sendMMMessage(player, "Removed spawn point #" + (spawnIndex + 1) + ". Remaining: " + eventData.getSpawns().size()); } // Prevent damage to marker mannequins @@ -244,9 +244,9 @@ public void onMarkerDamage(EntityDamageByEntityEvent event) { EventSpawnMarkerManager.getInstance().updateMarkers(eventData); updateGui(eventData); scheduleSave(eventData); - player.sendMessage(Common.colorize("&cRemoved last spawn point. Remaining: " + index)); + Common.sendMMMessage(player, "Removed last spawn point. Remaining: " + index); } else { - player.sendMessage(Common.colorize("&cNo spawn points to remove.")); + Common.sendMMMessage(player, "No spawn points to remove."); } } @@ -270,7 +270,7 @@ private void handleModeSwitch(Player player, EventWandSetupManager.SetupSession } setupManager.updateWand(player); - player.sendMessage(Common.colorize("&eSwitched to mode: &f" + session.getCurrentMode().getDisplayName())); + Common.sendMMMessage(player, "Switched to mode: " + session.getCurrentMode().getDisplayName()); } private void handleCornerSelection(Player player, EventData eventData, Action action, PlayerInteractEvent event) { @@ -281,7 +281,7 @@ private void handleCornerSelection(Player player, EventData eventData, Action ac Block targetBlock = event.getClickedBlock(); if (targetBlock == null || targetBlock.getType().equals(Material.AIR)) { - player.sendMessage(Common.colorize("&cBlock location cannot be found!")); + Common.sendMMMessage(player, "Block location cannot be found!"); return; } @@ -313,7 +313,7 @@ private void handleSpawnPoints(Player player, EventData eventData, Action action } if (eventData.getCuboid() == null) { - player.sendMessage(Common.colorize("&cYou must set corners first!")); + Common.sendMMMessage(player, "You must set corners first!"); return; } @@ -325,7 +325,7 @@ private void handleSpawnPoints(Player player, EventData eventData, Action action Location spawnLoc = getSnappedLocation(block, player); if (!eventData.getCuboid().contains(spawnLoc)) { - player.sendMessage(Common.colorize("&cSpawn point must be within the event cuboid!")); + Common.sendMMMessage(player, "Spawn point must be within the event cuboid!"); return; } @@ -333,7 +333,7 @@ private void handleSpawnPoints(Player player, EventData eventData, Action action eventData.addSpawn(spawnLoc); } catch (IllegalStateException ex) { // Ignore duplicate/invalid add attempts and show the setup error to the player. - player.sendMessage(Common.colorize("&c" + ex.getMessage())); + Common.sendMMMessage(player, "" + ex.getMessage()); return; } @@ -341,7 +341,7 @@ private void handleSpawnPoints(Player player, EventData eventData, Action action updateGui(eventData); scheduleSave(eventData); - player.sendMessage(Common.colorize("&aAdded spawn point #" + eventData.getSpawns().size() + " at your location.")); + Common.sendMMMessage(player, "Added spawn point #" + eventData.getSpawns().size() + " at your location."); } // Left-click anywhere to remove the last spawn point else if (action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK) { @@ -351,9 +351,9 @@ else if (action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK) { EventSpawnMarkerManager.getInstance().updateMarkers(eventData); updateGui(eventData); scheduleSave(eventData); - player.sendMessage(Common.colorize("&cRemoved last spawn point. Remaining: " + index)); + Common.sendMMMessage(player, "Removed last spawn point. Remaining: " + index); } else { - player.sendMessage(Common.colorize("&cNo spawn points to remove.")); + Common.sendMMMessage(player, "No spawn points to remove."); } } } @@ -366,19 +366,19 @@ private void handleToggleStatus(Player player, EventData eventData, Action actio try { if (eventData.isEnabled()) { eventData.setEnabled(false); - player.sendMessage(Common.colorize("&cDisabled event: &e" + eventData.getType().getName())); + Common.sendMMMessage(player, "Disabled event: " + eventData.getType().getName()); } else { if (eventData.getCuboidLoc1() == null || eventData.getCuboidLoc2() == null) { - player.sendMessage(Common.colorize("&cYou must set both corners first!")); + Common.sendMMMessage(player, "You must set both corners first!"); return; } if (eventData.getSpawns().isEmpty()) { - player.sendMessage(Common.colorize("&cYou must set at least one spawn point!")); + Common.sendMMMessage(player, "You must set at least one spawn point!"); return; } eventData.setEnabled(true); - player.sendMessage(Common.colorize("&aEnabled event: &e" + eventData.getType().getName())); + Common.sendMMMessage(player, "Enabled event: " + eventData.getType().getName()); // End setup mode for all players currently setting up this event List playersSettingUp = new ArrayList<>(setupManager.getPlayersSettingUpEvent(eventData)); @@ -390,7 +390,7 @@ private void handleToggleStatus(Player player, EventData eventData, Action actio updateGui(eventData); scheduleSave(eventData); } catch (Exception e) { - player.sendMessage(Common.colorize("&cError toggling status: " + e.getMessage())); + Common.sendMMMessage(player, "Error toggling status: " + e.getMessage()); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSetupMode.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSetupMode.java index f7abc938a..134dccd27 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSetupMode.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSetupMode.java @@ -6,18 +6,18 @@ public enum EventSetupMode { CORNERS("Corner Selection", new String[]{ - "&b Left Click: &fSet Corner 1", - "&b Right Click: &fSet Corner 2" + " Left Click: Set Corner 1", + " Right Click: Set Corner 2" }), SPAWN_POINTS("Spawn Points", new String[]{ - "&b Right Click Block: &fAdd Spawn Point", - "&b Right Click Armor Stand: &fRemove That Spawn", - "&b Left Click (Anywhere): &fRemove Last Spawn" + " Right Click Block: Add Spawn Point", + " Right Click Armor Stand: Remove That Spawn", + " Left Click (Anywhere): Remove Last Spawn" }), TOGGLE_STATUS("Event Status", new String[]{ - "&b Right Click: &fEnable Event", + " Right Click: Enable Event", }); private final String displayName; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSpawnMarkerManager.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSpawnMarkerManager.java index 2b8156d6f..c9b1e2793 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSpawnMarkerManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventSpawnMarkerManager.java @@ -5,7 +5,6 @@ import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.ItemCreateUtil; import lombok.Getter; -import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.EntityType; @@ -73,7 +72,7 @@ public void showMarkers(EventData eventData) { if (!spawns.isEmpty()) { int index = 0; for (Location spawnLoc : spawns) { - Mannequin marker = createMarker(spawnLoc, "&c&lSpawn #" + (index + 1)); + Mannequin marker = createMarker(spawnLoc, "Spawn #" + (index + 1)); if (marker != null) { markers.add(marker); // Track this main marker to its spawn index @@ -110,7 +109,7 @@ private Mannequin createMarker(Location location, String name) { mannequin.setGravity(false); mannequin.setCanPickupItems(false); mannequin.setCustomNameVisible(true); - mannequin.customName(Component.text(Common.colorize(name))); + mannequin.customName(Common.deserializeMiniMessage(name)); mannequin.setAI(false); mannequin.setCollidable(false); mannequin.setSilent(true); @@ -123,7 +122,7 @@ private Mannequin createMarker(Location location, String name) { mannequin.teleport(facingLoc); // Give it a sword to hold (to make it more visible) - ItemStack sword = ItemCreateUtil.createItem("&cSpawn Marker", org.bukkit.Material.DIAMOND_SWORD); + ItemStack sword = ItemCreateUtil.createItem("Spawn Marker", org.bukkit.Material.DIAMOND_SWORD); mannequin.getEquipment().setItemInMainHand(sword); // Make it invulnerable and non-persistent. @@ -145,7 +144,7 @@ private Mannequin createLabelOnly(Location location) { labelStand.setGravity(false); labelStand.setCanPickupItems(false); labelStand.setCustomNameVisible(true); - labelStand.customName(Component.text(Common.colorize("&7(Right-click to remove)"))); + labelStand.customName(Common.deserializeMiniMessage("(Right-click to remove)")); labelStand.setAI(false); labelStand.setCollidable(false); labelStand.setSilent(true); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventWandSetupManager.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventWandSetupManager.java index 4bee54170..ef2d507c7 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventWandSetupManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/event/setup/EventWandSetupManager.java @@ -80,7 +80,7 @@ public void startSetup(Player player, EventData eventData) { // Show spawn position markers EventSpawnMarkerManager.getInstance().showMarkers(eventData); - player.sendMessage(Common.colorize("&aSetup mode started for event: &e" + eventData.getType().getName() + "&a.")); + Common.sendMMMessage(player, "Setup mode started for event: " + eventData.getType().getName() + "."); } public void stopSetup(Player player) { @@ -101,7 +101,7 @@ public void stopSetup(Player player) { EventSpawnMarkerManager.getInstance().clearMarkers(eventData); } - player.sendMessage(Common.colorize("&cSetup mode ended for event: &c" + eventData.getType().getName() + ".")); + Common.sendMMMessage(player, "Setup mode ended for event: " + eventData.getType().getName() + "."); } public SetupSession getSession(Player player) { @@ -153,24 +153,24 @@ public void updateWand(Player player) { ItemMeta meta = wand.getItemMeta(); EventSetupMode mode = session.getCurrentMode(); - meta.displayName(Common.legacyToComponent(Common.colorize("&6Event Wand &7(&e" + mode.getDisplayName() + "&7)"))); + meta.displayName(Common.legacyToComponent(Common.colorize("Event Wand (" + mode.getDisplayName() + ")"))); List lore = new ArrayList<>(); - lore.add(Common.colorize("&7Editing: &a" + eventData.getType().getName())); + lore.add(Common.colorize("Editing: " + eventData.getType().getName())); lore.add(""); - lore.add(Common.colorize("&eCurrent Mode: &f" + mode.getDisplayName())); + lore.add(Common.colorize("Current Mode: " + mode.getDisplayName())); lore.add(""); - lore.add(Common.colorize("&7Controls:")); + lore.add(Common.colorize("Controls:")); for (String line : mode.getDescription()) { lore.add(Common.colorize(line)); } lore.add(""); - lore.add(Common.colorize("&dShift + Left: &7Next Mode")); - lore.add(Common.colorize("&dShift + Right: &7Prev Mode")); + lore.add(Common.colorize("Shift + Left: Next Mode")); + lore.add(Common.colorize("Shift + Right: Prev Mode")); lore.add(""); - lore.add(Common.colorize("&cDrop (Q): &7Exit Setup")); + lore.add(Common.colorize("Drop (Q): Exit Setup")); meta.lore(lore.stream().map(Common::legacyToComponent).collect(Collectors.toList())); wand.setItemMeta(meta); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/ffa/FFAListener.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/ffa/FFAListener.java index 21846997b..8f1fccd17 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/ffa/FFAListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/ffa/FFAListener.java @@ -217,14 +217,7 @@ public void onBlockBreak(BlockBreakEvent e) { Block block = e.getBlock(); - // Blocks placed during the fight — allow breaking (tracking done by BuildListener) - if (BlockUtil.hasMetadata(block, PLACED_IN_FIGHT)) { - Object mv = BlockUtil.getMetadata(block, PLACED_IN_FIGHT, Object.class); - if (ListenerUtil.checkMetaData(mv)) { - e.setCancelled(true); - } - return; - } + if (ListenerUtil.handlePlacedInFightBlock(block, e)) return; // For natural arena blocks or destroyable blocks, check build limits if (e.getBlock().getLocation().getY() >= ListenerUtil.getCalculatedBuildLimit(ffa.getArena())) { @@ -398,8 +391,11 @@ public void onPlayerDeath(PlayerDeathEvent e) { DeathCause cause = FightUtil.convert(damageSource.getDamageType()); ffa.killPlayer(player, killer, cause.getMessage().replace("%killer%", killer != null ? killer.getName() : "Unknown")); - if (killer != null) { - Statistic statistic = ffa.getStatistics().get(killer); + if (killer != null && !killer.equals(player)) { + Statistic statistic = ffa.getStatistics().computeIfAbsent( + killer, + p -> new Statistic(ProfileManager.getInstance().getUuids().get(p)) + ); statistic.setKills(statistic.getKills() + 1); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/ffa/game/FFA.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/ffa/game/FFA.java index 4b7010f66..4e7d93520 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/ffa/game/FFA.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/ffa/game/FFA.java @@ -20,9 +20,9 @@ import dev.nandi0813.practice.manager.profile.ProfileManager; import dev.nandi0813.practice.manager.profile.enums.ProfileStatus; import dev.nandi0813.practice.manager.spectator.SpectatorManager; -import dev.nandi0813.practice.telemetry.transport.stats.PracticeStatsTelemetryLogger; import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.Cuboid; +import dev.nandi0813.practice.util.LastAttackerTracker; import dev.nandi0813.practice.util.entityhider.PlayerHider; import dev.nandi0813.practice.util.fightmapchange.FightChangeOptimized; import dev.nandi0813.practice.util.interfaces.Spectatable; @@ -56,11 +56,7 @@ public class FFA implements Spectatable, dev.nandi0813.api.Interface.FFA { private boolean open; /** Tracks the last player that dealt damage to another player, for void-kill attribution. */ - private final Map lastAttackerMap = new HashMap<>(); - /** Timestamp (ms) of the last attacker hit, keyed by victim UUID. */ - private final Map lastAttackerTime = new HashMap<>(); - /** How long (ms) a last-attacker is considered valid for void attribution. */ - private static final long LAST_ATTACKER_EXPIRY_MS = 4_000L; + private final LastAttackerTracker lastAttackerTracker = new LastAttackerTracker(); public FFA(FFAArena arena) { this.arena = arena; @@ -145,7 +141,7 @@ public void addPlayer(Player player, NormalLadder ladder) { teleportPlayer(player); this.sendMessage(LanguageManager.getString("FFA.GAME.PLAYER-JOIN").replace("%player%", player.getName()), true); - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, ladder); this.addPlayerToBelowName(player); // Show kit chooser or apply default kit @@ -162,7 +158,7 @@ public void changePlayerLadder(Player player, NormalLadder ladder) { return; players.put(player, ladder); - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, ladder); KitUtil.loadDefaultLadderKit(player, TeamEnum.FFA, ladder); dev.nandi0813.practice.manager.fight.util.PlayerUtil.setAttackSpeed(player, ladder.getAttackCooldownModifier()); } @@ -225,7 +221,7 @@ public void killPlayer(Player player, Player killer, String deathMessage) { // check whether a recent attacker should be credited instead. if (killer == null) { Player lastAttacker = getLastAttacker(player); - if (lastAttacker != null && deathMessage != null + if (lastAttacker != null && !lastAttacker.equals(player) && deathMessage != null && deathMessage.equals(dev.nandi0813.practice.manager.fight.util.DeathCause.VOID.getMessage())) { killer = lastAttacker; deathMessage = dev.nandi0813.practice.manager.fight.util.DeathCause.VOID_BY_PLAYER @@ -237,12 +233,10 @@ public void killPlayer(Player player, Player killer, String deathMessage) { fightPlayers.get(player).die(deathMessage, statistics.get(player)); Profile deadProfile = fightPlayers.get(player).getProfile(); deadProfile.getStats().getLadderStat(players.get(player)).increaseDeaths(); - PracticeStatsTelemetryLogger.markDirty(deadProfile); - if (killer != null) { + if (killer != null && !killer.equals(player)) { Profile killerProfile = fightPlayers.get(killer).getProfile(); killerProfile.getStats().getLadderStat(players.get(killer)).increaseKills(); - PracticeStatsTelemetryLogger.markDirty(killerProfile); playDeathEffect(killer, player); @@ -258,7 +252,7 @@ public void killPlayer(Player player, Player killer, String deathMessage) { if (arena.isLobbyAfterDeath()) { this.removePlayer(player); } else { - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, players.get(player)); applySelectedOrDefaultKit(player); dev.nandi0813.practice.manager.fight.util.PlayerUtil.setAttackSpeed(player, players.get(player).getAttackCooldownModifier()); @@ -281,30 +275,15 @@ private void applySelectedOrDefaultKit(Player player) { } private void playDeathEffect(Player killer, Player victim) { - if (killer == null || victim == null) { - return; - } - - try { - Profile killerProfile = fightPlayers.containsKey(killer) - ? fightPlayers.get(killer).getProfile() - : ProfileManager.getInstance().getProfile(killer); + if (killer == null || victim == null) return; - if (killerProfile == null || killerProfile.getCosmeticsData() == null) { - return; - } - - var deathEffect = killerProfile.getCosmeticsData().getDeathEffect(); - if (deathEffect == null) { - return; - } + Profile killerProfile = fightPlayers.containsKey(killer) + ? fightPlayers.get(killer).getProfile() + : ProfileManager.getInstance().getProfile(killer); - List viewers = new ArrayList<>(players.keySet()); - viewers.addAll(spectators); - deathEffect.play(victim.getLocation(), viewers); - } catch (Exception ignored) { - // Cosmetic effects should never break FFA kill handling. - } + List viewers = new ArrayList<>(players.keySet()); + viewers.addAll(spectators); + Common.playDeathEffect(killerProfile, victim.getLocation(), viewers); } private void applyHealthResetOnKill(Player killer) { @@ -322,10 +301,7 @@ private void applyHealthResetOnKill(Player killer) { * Called from damage listeners so void deaths can be attributed correctly. */ public void recordAttack(Player victim, Player attacker) { - if (victim == attacker) return; - - lastAttackerMap.put(victim.getUniqueId(), attacker.getUniqueId()); - lastAttackerTime.put(victim.getUniqueId(), System.currentTimeMillis()); + lastAttackerTracker.recordAttack(victim, attacker); } /** @@ -333,14 +309,7 @@ public void recordAttack(Player victim, Player attacker) { * or {@code null} if there is none. */ public @org.jetbrains.annotations.Nullable Player getLastAttacker(Player victim) { - Long time = lastAttackerTime.get(victim.getUniqueId()); - if (time == null || System.currentTimeMillis() - time > LAST_ATTACKER_EXPIRY_MS) return null; - UUID attackerUuid = lastAttackerMap.get(victim.getUniqueId()); - if (attackerUuid == null) return null; - for (Player p : players.keySet()) { - if (attackerUuid.equals(p.getUniqueId())) return p; - } - return null; + return lastAttackerTracker.getLastAttacker(victim, players.keySet()); } public void teleportPlayer(Player player) { @@ -348,14 +317,7 @@ public void teleportPlayer(Player player) { } public void sendMessage(String message, boolean spectator) { - for (Player player : players.keySet()) { - Common.sendMMMessage(player, message); - } - if (spectator) { - for (Player spectatorPlayer : spectators) { - Common.sendMMMessage(spectatorPlayer, message); - } - } + Common.sendMessage(players.keySet(), spectators, message, spectator); } private void teleportStuckSpectatorsAfterRollback() { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/listener/BuildListener.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/listener/BuildListener.java index 1f9fe5973..6a0b16ce3 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/listener/BuildListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/listener/BuildListener.java @@ -70,9 +70,6 @@ */ public class BuildListener implements Listener { - // ========================================================================= - // HELPERS — shared by all subclasses - // ========================================================================= private final Map setFuseTick = new HashMap<>(); @@ -251,9 +248,7 @@ private static void filterAndTrackExplosionBlocks(List blockList, Spectat } } - // ========================================================================= // PLAYER-DRIVEN BLOCK EVENTS (merged from BuildBlockListener) - // ========================================================================= @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent e) { @@ -392,9 +387,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { spectatable.getFightChange().trackFirePosition(target); } - // ========================================================================= // EXPLOSIONS - // ========================================================================= /** * Tracks every block stacked directly above {@code base} that requires solid @@ -484,9 +477,6 @@ public void onEntityExplode(EntityExplodeEvent e) { handleExplosion(e, e.blockList(), spectatable); } - // ========================================================================= - // TNT ENTITY SPAWN (fallback — used as-is on 1.8.8; still fires on modern) - // ========================================================================= /** * Tracks a newly spawned {@link TNTPrimed} entity for rollback and applies @@ -577,9 +567,7 @@ protected boolean isTntBlockAlreadyTracked() { return true; } - // ========================================================================= // PISTONS - // ========================================================================= @EventHandler public void onBlockPistonExtend(BlockPistonExtendEvent e) { @@ -609,9 +597,6 @@ public void onBlockPistonRetract(BlockPistonRetractEvent e) { } } - // ========================================================================= - // BLOCK FORM (cobblestone / obsidian generators, ice, etc.) - // ========================================================================= /** * Tracks blocks that turn to dirt when another block forms on top (e.g., grass @@ -648,9 +633,7 @@ public void onBlockForm(BlockFormEvent e) { } } - // ========================================================================= // LIQUID SOURCE — bucket placement - // ========================================================================= /** * Captures the block that will become the liquid source BEFORE the bucket is emptied. @@ -676,9 +659,7 @@ public void onBucketEmpty(PlayerBucketEmptyEvent e) { BlockUtil.setMetadata(liquidSourceBlock, PLACED_IN_FIGHT, spectatable); } - // ========================================================================= // LIQUID FLOW - // ========================================================================= /** * Tracks blocks that turn to dirt when lava flows on top (e.g., grass @@ -755,9 +736,6 @@ public void onBlockFromTo(BlockFromToEvent e) { } } - // ========================================================================= - // BLOCK SPREAD (fire, mushrooms, etc.) - // ========================================================================= @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockSpread(BlockSpreadEvent e) { @@ -794,9 +772,6 @@ public void onBlockSpread(BlockSpreadEvent e) { }); } - // ========================================================================= - // BLOCK FADE (grass → dirt, ice melt, etc.) - // ========================================================================= /** * Tracks blocks that fade to another type (e.g. grass/mycelium turning to dirt when @@ -816,9 +791,6 @@ public void onBlockFade(BlockFadeEvent e) { new ChangedBlock(block, block.getType())); } - // ========================================================================= - // BLOCK BURN (fire destroying blocks) - // ========================================================================= /** * Tracks blocks destroyed by fire so they are restored during rollback. @@ -904,9 +876,7 @@ private void trackAdjacentFire(Block center, Spectatable spectatable) { } } - // ========================================================================= // FALLING BLOCKS (sand, gravel, concrete powder, anvils, etc.) - // ========================================================================= /** * Tracks falling blocks for rollback. Runs at LOWEST so the block in the world diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/listener/EPCountdownListener.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/listener/EPCountdownListener.java index 34d4ab44a..4b08f3543 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/listener/EPCountdownListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/listener/EPCountdownListener.java @@ -5,7 +5,6 @@ import dev.nandi0813.practice.manager.fight.match.Match; import dev.nandi0813.practice.manager.fight.match.MatchManager; import dev.nandi0813.practice.manager.fight.match.enums.RoundStatus; -import dev.nandi0813.practice.manager.fight.util.ModernItemCooldownHandler; import io.papermc.paper.event.player.PlayerItemCooldownEvent; import org.bukkit.Material; import org.bukkit.entity.EnderPearl; @@ -39,6 +38,11 @@ public void onEnderPearlCooldownSet(PlayerItemCooldownEvent e) { Match match = MatchManager.getInstance().getLiveMatchByPlayer(player); if (match != null) { + if (!match.getCurrentRound().getRoundStatus().equals(RoundStatus.LIVE)) { + e.setCancelled(true); + return; + } + double duration = match.getLadder().getEnderPearlCooldown(); if (duration <= 0) { e.setCancelled(true); @@ -49,7 +53,7 @@ public void onEnderPearlCooldownSet(PlayerItemCooldownEvent e) { } FFA ffa = FFAManager.getInstance().getFFAByPlayer(player); - if (ffa != null) { + if (ffa != null && ffa.getPlayers().containsKey(player)) { double duration = ffa.getPlayers().get(player).getEnderPearlCooldown(); if (duration <= 0) { e.setCancelled(true); @@ -91,28 +95,15 @@ public void onProjectileShoot(ProjectileLaunchEvent e) { FFA ffa = FFAManager.getInstance().getFFAByPlayer(player); if (ffa != null) { - double duration = ffa.getPlayers().get(player).getEnderPearlCooldown(); - if (duration <= 0) { - return; - } - - ModernItemCooldownHandler.handleEnderPearl(player, duration, e); return; } Match match = MatchManager.getInstance().getLiveMatchByPlayer(player); if (match != null) { - double duration = match.getLadder().getEnderPearlCooldown(); - if (duration <= 0) { - return; - } - if (!match.getCurrentRound().getRoundStatus().equals(RoundStatus.LIVE)) { e.setCancelled(true); return; } - - ModernItemCooldownHandler.handleEnderPearl(player, duration, e); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/Match.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/Match.java index c77eabb16..20228125a 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/Match.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/Match.java @@ -31,9 +31,9 @@ import dev.nandi0813.practice.manager.profile.ProfileManager; import dev.nandi0813.practice.manager.profile.enums.ProfileStatus; import dev.nandi0813.practice.manager.spectator.SpectatorManager; -import dev.nandi0813.practice.telemetry.transport.stats.PracticeStatsTelemetryLogger; import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.Cuboid; +import dev.nandi0813.practice.util.LastAttackerTracker; import dev.nandi0813.practice.util.PermanentConfig; import dev.nandi0813.practice.util.StringUtil; import dev.nandi0813.practice.util.entityhider.PlayerHider; @@ -84,13 +84,9 @@ public abstract class Match extends BukkitRunnable implements Spectatable, dev.n private final FightChangeOptimized fightChange; /** Tracks the last player that dealt damage to another player, for void-kill attribution. */ - private final Map lastAttackerMap = new HashMap<>(); - /** Timestamp (ms) of the last attacker hit, keyed by victim UUID. */ - private final Map lastAttackerTime = new HashMap<>(); + private final LastAttackerTracker lastAttackerTracker = new LastAttackerTracker(); /** Tracks whether a player's last registered death in this match was void-related. */ private final Map lastDeathWasVoid = new HashMap<>(); - /** How long (ms) a last-attacker is considered valid for void attribution. */ - private static final long LAST_ATTACKER_EXPIRY_MS = 4_000L; /** True while the arena is being rolled back between rounds — players are frozen. */ @Getter @@ -118,7 +114,7 @@ protected Match(final Ladder ladder, final Arena arena, final List playe } this.fightChange = new FightChangeOptimized(this); - if (arena != null && arena.getSideBuildLimit() > 0) + if (arena.getSideBuildLimit() > 0) this.sideBuildLimit = MatchUtil.getSideBuildLimitCube(this.arena.getCuboid().clone(), arena.getSideBuildLimit()); else this.sideBuildLimit = null; @@ -142,7 +138,7 @@ public void startMatch() { this.allowSpectators = false; } - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, this.ladder); for (Player online : Bukkit.getOnlinePlayers()) { if (!this.players.contains(online)) { @@ -159,15 +155,7 @@ public void startMatch() { } public void sendMessage(String message, boolean spectator) { - for (Player player : this.players) { - Common.sendMMMessage(player, message); - } - - if (spectator) { - for (Player specPlayer : this.spectators) { - Common.sendMMMessage(specPlayer, message); - } - } + Common.sendMessage(players, spectators, message, spectator); } public void entityVanish(Player player) { @@ -204,8 +192,7 @@ public void entityVanish(Player player) { * Called from damage listeners so void deaths can be attributed correctly. */ public void recordAttack(Player victim, Player attacker) { - lastAttackerMap.put(victim.getUniqueId(), attacker.getUniqueId()); - lastAttackerTime.put(victim.getUniqueId(), System.currentTimeMillis()); + lastAttackerTracker.recordAttack(victim, attacker); } /** @@ -213,14 +200,7 @@ public void recordAttack(Player victim, Player attacker) { * or {@code null} if there is none. */ public @org.jetbrains.annotations.Nullable Player getLastAttacker(Player victim) { - Long time = lastAttackerTime.get(victim.getUniqueId()); - if (time == null || System.currentTimeMillis() - time > LAST_ATTACKER_EXPIRY_MS) return null; - UUID attackerUuid = lastAttackerMap.get(victim.getUniqueId()); - if (attackerUuid == null) return null; - for (Player p : players) { - if (attackerUuid.equals(p.getUniqueId())) return p; - } - return null; + return lastAttackerTracker.getLastAttacker(victim, players); } public boolean wasLastDeathVoid(Player player) { @@ -284,11 +264,9 @@ public void killPlayer(Player player, Player killer, String deathMessage) { if (killer != null) { Profile killerProfile = matchPlayers.get(killer).getProfile(); killerProfile.getStats().getLadderStat((NormalLadder) ladder).increaseKills(); - PracticeStatsTelemetryLogger.markDirty(killerProfile); } Profile deadProfile = matchPlayers.get(player).getProfile(); deadProfile.getStats().getLadderStat((NormalLadder) ladder).increaseDeaths(); - PracticeStatsTelemetryLogger.markDirty(deadProfile); } playDeathEffect(killer, player); @@ -297,28 +275,13 @@ public void killPlayer(Player player, Player killer, String deathMessage) { } private void playDeathEffect(Player killer, Player victim) { - if (killer == null || victim == null) { - return; - } - - try { - Profile killerProfile = matchPlayers.containsKey(killer) - ? matchPlayers.get(killer).getProfile() - : ProfileManager.getInstance().getProfile(killer); - - if (killerProfile == null || killerProfile.getCosmeticsData() == null) { - return; - } + if (killer == null || victim == null) return; - var deathEffect = killerProfile.getCosmeticsData().getDeathEffect(); - if (deathEffect == null) { - return; - } + Profile killerProfile = matchPlayers.containsKey(killer) + ? matchPlayers.get(killer).getProfile() + : ProfileManager.getInstance().getProfile(killer); - deathEffect.play(victim.getLocation(), getPeople()); - } catch (Exception ignored) { - // Cosmetic effects should never break combat flow. - } + Common.playDeathEffect(killerProfile, victim.getLocation(), getPeople()); } protected abstract void killPlayer(Player player, String deathMessage); @@ -346,7 +309,13 @@ public void endMatch() { removeSpectator(spectator); // Reset the arena and only make it reusable after rollback completes. - resetMap(() -> this.arena.setAvailable(true)); + // Also defer live-match removal to the rollback callback so block event listeners + // can still resolve this match via cuboid lookup during the multi-tick rollback, + // preventing untracked block changes from leaking into the next match. + resetMap(() -> { + MatchManager.getInstance().getLiveMatches().remove(this); + this.arena.setAvailable(true); + }); this.cancel(); @@ -425,7 +394,7 @@ public void addSpectator(Player player, Player target, boolean teleport, boolean return; } - if (this.status.equals(MatchStatus.OVER)) { + if (this.status.equals(MatchStatus.OVER) || this.players.isEmpty()) { Common.sendMMMessage(player, LanguageManager.getString("SPECTATE.MATCH.MATCH-ENDED")); return; } @@ -466,6 +435,7 @@ public void addSpectator(Player player, Player target, boolean teleport, boolean } Profile profile = ProfileManager.getInstance().getProfile(player); + profile.setStatus(ProfileStatus.SPECTATE); if (profile.isStaffMode()) { InventoryManager.getInstance().setStaffModeInventory(player); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/Round.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/Round.java index a7d13c76a..672156725 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/Round.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/Round.java @@ -73,7 +73,7 @@ public void startRound() { for (Player player : match.getPlayers()) { match.teleportPlayer(player); - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, match.getLadder()); MatchFightPlayer matchFightPlayer = match.getMatchPlayers().get(player); matchFightPlayer.setKitChooserOrKit(match instanceof Team ? ((Team) match).getTeam(player) : TeamEnum.TEAM1); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/enums/TeamEnum.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/enums/TeamEnum.java index 15e1f9bfe..88595881b 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/enums/TeamEnum.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/enums/TeamEnum.java @@ -2,6 +2,7 @@ import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.backend.ConfigManager; +import dev.nandi0813.practice.util.StringUtil; import lombok.Getter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -9,18 +10,18 @@ public enum TeamEnum { TEAM1( - ZonePractice.getMiniMessage().deserialize(ConfigManager.getConfig().getString("MATCH-SETTINGS.TEAMS.TEAM1.NAME")), + ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(ConfigManager.getConfig().getString("MATCH-SETTINGS.TEAMS.TEAM1.NAME"))), ConfigManager.getConfig().getString("MATCH-SETTINGS.TEAMS.TEAM1.COLOR"), - ZonePractice.getMiniMessage().deserialize(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM1.NAMETAG.PREFIX")), + ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM1.NAMETAG.PREFIX"))), NamedTextColor.NAMES.valueOr(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM1.NAMETAG.NAME-COLOR").toLowerCase(), NamedTextColor.WHITE), - ZonePractice.getMiniMessage().deserialize(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM1.NAMETAG.SUFFIX")) + ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM1.NAMETAG.SUFFIX"))) ), TEAM2( - ZonePractice.getMiniMessage().deserialize(ConfigManager.getConfig().getString("MATCH-SETTINGS.TEAMS.TEAM2.NAME")), + ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(ConfigManager.getConfig().getString("MATCH-SETTINGS.TEAMS.TEAM2.NAME"))), ConfigManager.getConfig().getString("MATCH-SETTINGS.TEAMS.TEAM2.COLOR"), - ZonePractice.getMiniMessage().deserialize(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM2.NAMETAG.PREFIX")), + ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM2.NAMETAG.PREFIX"))), NamedTextColor.NAMES.valueOr(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM2.NAMETAG.NAME-COLOR").toLowerCase(), NamedTextColor.WHITE), - ZonePractice.getMiniMessage().deserialize(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM2.NAMETAG.SUFFIX")) + ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(ConfigManager.getString("MATCH-SETTINGS.TEAMS.TEAM2.NAMETAG.SUFFIX"))) ), FFA( Component.empty(), @@ -41,7 +42,7 @@ public enum TeamEnum { private final Component suffix; TeamEnum(Component name, String color, Component prefix, NamedTextColor nameColor, Component suffix) { - this.name = ZonePractice.getMiniMessage().deserialize(color).append(name); + this.name = ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(color)).append(name); this.color = color; this.prefix = prefix; @@ -54,7 +55,7 @@ public Component getNameComponent() { } public Component getColor() { - return ZonePractice.getMiniMessage().deserialize(color); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(color)); } public String getNameMM() { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/enums/WeightClass.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/enums/WeightClass.java index f88f9e65d..f09bb8794 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/enums/WeightClass.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/enums/WeightClass.java @@ -2,7 +2,6 @@ import dev.nandi0813.practice.manager.backend.ConfigManager; import dev.nandi0813.practice.util.Common; -import dev.nandi0813.practice.util.StringUtil; public enum WeightClass { @@ -16,7 +15,7 @@ public enum WeightClass { } public String getName() { - return StringUtil.CC(this.name); + return Common.mmToNormal(this.name); } public String getMMName() { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/listener/LadderTypeListener.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/listener/LadderTypeListener.java index c043be5bf..106036234 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/listener/LadderTypeListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/listener/LadderTypeListener.java @@ -62,7 +62,6 @@ public class LadderTypeListener implements Listener { private static final int SKYWARS_KILLER_EXP_LEVEL_REWARD = 5; private static final int SKYWARS_ENCHANT_LAPIS_AMOUNT = 3; - // ========== HELPER METHODS ========== /** * Gets the match for a player if they are in MATCH status. @@ -151,7 +150,7 @@ private static Match resolveProjectileMatch(Projectile projectile) { return null; } - // ========== EVENT HANDLERS ========== + // EVENT HANDLERS protected static void arrowDisplayHearth(Player shooter, Player target, double finalDamage, EntityDamageByEntityEvent event) { if (!PermanentConfig.DISPLAY_ARROW_HIT) return; @@ -339,14 +338,7 @@ public void onBlockBreak(BlockBreakEvent e) { Block block = e.getBlock(); - // Blocks placed during the fight — allow breaking (tracking done by BuildListener) - if (BlockUtil.hasMetadata(block, PLACED_IN_FIGHT)) { - Object mv = BlockUtil.getMetadata(block, PLACED_IN_FIGHT, Object.class); - if (ListenerUtil.checkMetaData(mv)) { - e.setCancelled(true); - } - return; - } + if (ListenerUtil.handlePlacedInFightBlock(block, e)) return; // For natural arena blocks or destroyable blocks, check build limits if (!isWithinBuildLimits(block, match, player)) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/listener/MatchLifecycleListener.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/listener/MatchLifecycleListener.java index f6ab538fc..a65c556cd 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/listener/MatchLifecycleListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/listener/MatchLifecycleListener.java @@ -58,7 +58,10 @@ public void onMatchEnd(MatchEndEvent e) { if (party != null) party.setMatch(null); - MatchManager.getInstance().getLiveMatches().remove(match); + // Live match removal is deferred to after rollback completes in Match.endMatch(). + // This ensures block event listeners can still resolve the match via cuboid lookup + // during the multi-tick rollback window, preventing untracked block changes. + // MatchManager.getInstance().getLiveMatches().remove(match); // Update GUIs if (match instanceof Duel && ((Duel) match).isRanked()) diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/duel/Duel.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/duel/Duel.java index f15f8058e..18ad4659a 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/duel/Duel.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/duel/Duel.java @@ -29,6 +29,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; @Getter public class Duel extends Match implements Team { @@ -108,9 +109,11 @@ public DuelRound getCurrentRound() { @Override public int getWonRounds(Player player) { + UUID playerUuid = player.getUniqueId(); int wonRounds = 0; for (Round round : this.rounds.values()) { - if (((DuelRound) round).getRoundWinner() == player) + Player winner = ((DuelRound) round).getRoundWinner(); + if (winner != null && winner.getUniqueId().equals(playerUuid)) wonRounds++; } return wonRounds; @@ -141,7 +144,7 @@ protected void killPlayer(Player player, String deathMessage) { SoundManager.getInstance().getSound(SoundType.MATCH_PLAYER_TEMP_DEATH).play(this.getPeople()); }); dev.nandi0813.practice.manager.fight.util.PlayerUtil.clearInventory(player); - player.setHealth(20); + PlayerUtil.healToMaxHealth(player); break; case ELIMINATED: @@ -154,18 +157,18 @@ protected void killPlayer(Player player, String deathMessage) { endRound = true; SoundManager.getInstance().getSound(SoundType.MATCH_PLAYER_DEATH).play(this.getPeople()); dev.nandi0813.practice.manager.fight.util.PlayerUtil.clearInventory(player); - player.setHealth(20); + PlayerUtil.healToMaxHealth(player); } else if (isScoringLadder()) { // Scoring ladder (like Boxing) - death doesn't end round return; } else { // Default death behavior for standard ladders this.getCurrentStat(player).end(true); - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, ladder); if (ladder.isDropInventory()) addEntityChange(dev.nandi0813.practice.manager.fight.util.PlayerUtil.dropPlayerInventory(player)); dev.nandi0813.practice.manager.fight.util.PlayerUtil.clearInventory(player); - player.setHealth(20); + PlayerUtil.healToMaxHealth(player); SoundManager.getInstance().getSound(SoundType.MATCH_PLAYER_DEATH).play(this.getPeople()); endRound = true; } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/duel/DuelRound.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/duel/DuelRound.java index f92fc4d85..1427bad23 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/duel/DuelRound.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/duel/DuelRound.java @@ -11,7 +11,6 @@ import dev.nandi0813.practice.manager.ladder.abstraction.normal.NormalLadder; import dev.nandi0813.practice.manager.profile.Profile; import dev.nandi0813.practice.manager.profile.statistics.LadderStats; -import dev.nandi0813.practice.telemetry.transport.stats.PracticeStatsTelemetryLogger; import lombok.Getter; import lombok.Setter; import org.bukkit.entity.Player; @@ -51,9 +50,6 @@ public void sendEndMessage(boolean endMatch) { lLadderStats.increaseLosses(duel.isRanked()); loserProfile.getStats().increaseLoseStreak(normalLadder, duel.isRanked()); - PracticeStatsTelemetryLogger.markDirty(winnerProfile); - PracticeStatsTelemetryLogger.markDirty(loserProfile); - if (duel.isRanked()) { int eloChange = MatchUtil.getRandomElo(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/partyffa/PartyFFA.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/partyffa/PartyFFA.java index 7bf1000e7..1e801e096 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/partyffa/PartyFFA.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/partyffa/PartyFFA.java @@ -69,6 +69,11 @@ public int getWonRounds(Player player) { @Override public void teleportPlayer(Player player) { + if (arena.getPartyFfaCenter() != null) { + player.teleport(arena.getPartyFfaCenter()); + return; + } + int randomNum; if (arena.getFfaPositions().isEmpty()) { randomNum = new Random().nextInt(2); @@ -97,7 +102,7 @@ protected void killPlayer(Player player, String deathMessage) { SoundManager.getInstance().getSound(SoundType.MATCH_PLAYER_TEMP_DEATH).play(this.getPeople()); }); dev.nandi0813.practice.manager.fight.util.PlayerUtil.clearInventory(player); - player.setHealth(20); + PlayerUtil.healToMaxHealth(player); return; case ELIMINATED: @@ -110,7 +115,7 @@ protected void killPlayer(Player player, String deathMessage) { this.getCurrentStat(player).end(true); SoundManager.getInstance().getSound(SoundType.MATCH_PLAYER_DEATH).play(this.getPeople()); - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, ladder); if (ladder.isDropInventory()) addEntityChange(dev.nandi0813.practice.manager.fight.util.PlayerUtil.dropPlayerInventory(player)); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/playersvsplayers/PlayersVsPlayers.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/playersvsplayers/PlayersVsPlayers.java index 62e238152..338517eaf 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/playersvsplayers/PlayersVsPlayers.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/type/playersvsplayers/PlayersVsPlayers.java @@ -73,7 +73,7 @@ protected void killPlayer(Player player, String deathMessage) { SoundManager.getInstance().getSound(SoundType.MATCH_PLAYER_TEMP_DEATH).play(this.getPeople()); }); dev.nandi0813.practice.manager.fight.util.PlayerUtil.clearInventory(player); - player.setHealth(20); + PlayerUtil.healToMaxHealth(player); break; case ELIMINATED: @@ -89,7 +89,7 @@ protected void killPlayer(Player player, String deathMessage) { MatchPlayerUtil.hidePlayerPartyGames(player, this.players); dev.nandi0813.practice.manager.fight.util.PlayerUtil.clearInventory(player); - player.setHealth(20); + PlayerUtil.healToMaxHealth(player); } else if (isScoringLadder()) { // Scoring ladder (like Boxing) - death doesn't end round return; @@ -98,7 +98,7 @@ protected void killPlayer(Player player, String deathMessage) { this.getCurrentStat(player).end(true); SoundManager.getInstance().getSound(SoundType.MATCH_PLAYER_DEATH).play(this.getPeople()); - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, ladder); if (ladder.isDropInventory()) addEntityChange(dev.nandi0813.practice.manager.fight.util.PlayerUtil.dropPlayerInventory(player)); @@ -123,7 +123,7 @@ protected void killPlayer(Player player, String deathMessage) { MatchPlayerUtil.hidePlayerPartyGames(player, this.players); dev.nandi0813.practice.manager.fight.util.PlayerUtil.clearInventory(player); - player.setHealth(20); + PlayerUtil.healToMaxHealth(player); } break; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/KnockbackUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/KnockbackUtil.java index 9722dd991..c73d158c6 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/KnockbackUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/KnockbackUtil.java @@ -9,13 +9,20 @@ public enum KnockbackUtil { public static void setPlayerKnockback(Entity target, Entity attacker, KnockbackType knockbackType) { Vector currentVelocity = target.getVelocity().clone(); + boolean targetOnGround = target.isOnGround(); - double horizontalScale = target.isOnGround() + double horizontalScale = targetOnGround ? knockbackType.getHorizontal() : knockbackType.getAirhorizontal(); - double verticalScale = target.isOnGround() + double verticalScale = targetOnGround ? knockbackType.getVertical() : knockbackType.getAirvertical(); + double maxHorizontal = targetOnGround + ? knockbackType.getMaxHorizontal() + : knockbackType.getMaxAirhorizontal(); + double maxVertical = targetOnGround + ? knockbackType.getMaxVertical() + : knockbackType.getMaxAirvertical(); Vector awayFromAttacker = target.getLocation().toVector().subtract(attacker.getLocation().toVector()); awayFromAttacker.setY(0); @@ -42,6 +49,12 @@ public static void setPlayerKnockback(Entity target, Entity attacker, KnockbackT if (appliedVertical < 0.08D) { appliedVertical = 0.08D * verticalScale; } + if (maxHorizontal > 0.0D) { + appliedHorizontal = Math.min(appliedHorizontal, maxHorizontal); + } + if (maxVertical > 0.0D) { + appliedVertical = Math.min(appliedVertical, maxVertical); + } Vector adjustedVelocity = new Vector( awayFromAttacker.getX() * appliedHorizontal, diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/MatchUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/MatchUtil.java index dcf5077fb..d2f703407 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/MatchUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/MatchUtil.java @@ -1,11 +1,16 @@ package dev.nandi0813.practice.manager.fight.match.util; import dev.nandi0813.practice.manager.backend.ConfigManager; +import dev.nandi0813.practice.manager.fight.match.Match; +import dev.nandi0813.practice.manager.fight.match.MatchManager; import dev.nandi0813.practice.manager.fight.match.type.partyffa.PartyFFA; import dev.nandi0813.practice.manager.fight.util.Stats.Statistic; import dev.nandi0813.practice.manager.ladder.abstraction.Ladder; import dev.nandi0813.practice.manager.ladder.enums.LadderType; import dev.nandi0813.practice.manager.ladder.type.SkyWars; +import dev.nandi0813.practice.manager.profile.Profile; +import dev.nandi0813.practice.manager.profile.ProfileManager; +import dev.nandi0813.practice.manager.profile.enums.ProfileStatus; import dev.nandi0813.practice.util.Cuboid; import dev.nandi0813.practice.util.NumberUtil; import dev.nandi0813.practice.util.playerutil.PlayerUtil; @@ -14,15 +19,25 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.*; -public enum MatchUtil { - ; +public final class MatchUtil { + private MatchUtil() { + } public static String getMatchID() { return "match-" + System.currentTimeMillis() + NumberUtil.getRandomNumber(100, 999); } + @Nullable + public static Match getMatchIfInMatch(Player player) { + Profile profile = ProfileManager.getInstance().getProfile(player); + if (profile == null || profile.getStatus() != ProfileStatus.MATCH) + return null; + return MatchManager.getInstance().getLiveMatchByPlayer(player); + } + public static boolean isLadderBedRelated(Ladder ladder) { LadderType ladderType = ladder.getType(); return ladderType.equals(LadderType.BEDWARS) diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/TempKillPlayer.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/TempKillPlayer.java index 1dffe95a6..7d9cabe42 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/TempKillPlayer.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/match/util/TempKillPlayer.java @@ -110,7 +110,7 @@ public void cancel(boolean setPlayer) { dev.nandi0813.practice.manager.fight.util.PlayerUtil.setCollidesWithEntities(player, true); match.teleportPlayer(player); - PlayerUtil.setFightPlayer(player); + PlayerUtil.setFightPlayer(player, match.getLadder()); match.getMatchPlayers().get(player).setKitChooserOrKit(playerTeam); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/util/KitSelectionHandler.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/util/KitSelectionHandler.java index 7e144d642..12d28f419 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/util/KitSelectionHandler.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/util/KitSelectionHandler.java @@ -128,22 +128,6 @@ public void showKitChooserOrApplyKit(TeamEnum team) { ItemStack[] inventory = kit.getInventory(); ItemStack[] armor = kit.getArmor(); - // Legacy safeguard: old kits may still have armor appended into inventory[36..39]. - if (inventory != null && inventory.length > 36) { - if (armor == null) { - armor = new ItemStack[]{ - inventory[36], - inventory.length > 37 ? inventory[37] : null, - inventory.length > 38 ? inventory[38] : null, - inventory.length > 39 ? inventory[39] : null - }; - } - - ItemStack[] trimmed = new ItemStack[36]; - System.arraycopy(inventory, 0, trimmed, 0, 36); - inventory = trimmed; - } - if (armor == null) { armor = ladder.getKitData().getArmor(); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/util/ListenerUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/util/ListenerUtil.java index b3d1ffe2e..8393f0df3 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/util/ListenerUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/util/ListenerUtil.java @@ -4,10 +4,30 @@ import dev.nandi0813.practice.manager.arena.arenas.interfaces.BasicArena; import dev.nandi0813.practice.manager.fight.match.Match; import dev.nandi0813.practice.manager.fight.match.enums.RoundStatus; +import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockBreakEvent; -public enum ListenerUtil { - ; +import static dev.nandi0813.practice.util.PermanentConfig.PLACED_IN_FIGHT; + +public final class ListenerUtil { + private ListenerUtil() { + } + + /** + * If the block was placed during the fight, cancels the event when the + * metadata owner is null (stale/ orphaned data) and returns true. + * Returns false if the block is not a fight-placed block (caller should + * continue with normal block-break validation). + */ + public static boolean handlePlacedInFightBlock(Block block, BlockBreakEvent e) { + if (!BlockUtil.hasMetadata(block, PLACED_IN_FIGHT)) return false; + Object mv = BlockUtil.getMetadata(block, PLACED_IN_FIGHT, Object.class); + if (checkMetaData(mv)) { + e.setCancelled(true); + } + return true; + } public static boolean cancelEvent(Match match, Player player) { if (match.getCurrentStat(player).isSet()) diff --git a/core/src/main/java/dev/nandi0813/practice/manager/fight/util/PlayerUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/fight/util/PlayerUtil.java index 4f5ad5bf6..7db45779b 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/fight/util/PlayerUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/fight/util/PlayerUtil.java @@ -1,6 +1,6 @@ package dev.nandi0813.practice.manager.fight.util; -import dev.nandi0813.practice.util.StringUtil; +import dev.nandi0813.practice.util.Common; import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -151,7 +151,7 @@ public static double getPlayerHealth(Player player) { @SuppressWarnings("deprecation") public static void setActiveInventoryTitle(Player player, String title) { - player.getOpenInventory().setTitle(StringUtil.CC(title)); + player.getOpenInventory().setTitle(Common.mmToNormal(title)); } public static void setPlayerListName(Player player, Component component) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/GUIItem.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/GUIItem.java index 51098374f..134ce0b71 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/GUIItem.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/GUIItem.java @@ -124,14 +124,14 @@ public GUIItem setUnbreakable(boolean unbreakable) { /** * Parses a raw name/lore string into a {@link net.kyori.adventure.text.Component}, - * supporting all color formats: legacy {@code &c}, hex {@code &#RRGGBB}, - * Bungeecord hex {@code &x&R&R&G&G&B&B}, and MiniMessage tags {@code }. + * supporting all color formats: legacy {@code }, hex {@code &#RRGGBB}, + * Bungeecord hex {@code &x&G&G}, and MiniMessage tags {@code }. */ private static net.kyori.adventure.text.Component parseColor(String raw) { if (raw == null || raw.isEmpty()) return net.kyori.adventure.text.Component.empty(); // Explicitly mark italic as false so Minecraft's default item-name italic doesn't apply. // Users can still opt back in by writing in their config. - return ZonePractice.getMiniMessage().deserialize(StringUtil.translateColorsToMiniMessage(raw)) + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(raw)) .decorationIfAbsent(net.kyori.adventure.text.format.TextDecoration.ITALIC, net.kyori.adventure.text.format.TextDecoration.State.FALSE); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/MatchHistoryGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/MatchHistoryGui.java index 8eefddec3..7e316a9b7 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/MatchHistoryGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/MatchHistoryGui.java @@ -7,6 +7,7 @@ import dev.nandi0813.practice.manager.matchhistory.MatchHistoryEntry; import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.InventoryUtil; +import dev.nandi0813.practice.util.ItemCreateUtil; import dev.nandi0813.practice.util.StringUtil; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -15,10 +16,12 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.SkullMeta; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; /** @@ -61,10 +64,10 @@ public void build() { @Override public void update() { - // ── Read config ──────────────────────────────────────── + // Read config String rawTitle = GUIFile.getString("GUIS.MATCH-HISTORY.TITLE"); if (rawTitle == null || rawTitle.isEmpty()) - rawTitle = "&8Match History &7- &6%player%"; + rawTitle = "Match History - %player%"; rawTitle = rawTitle.replace("%player%", targetName); int size = GUIFile.getInt("GUIS.MATCH-HISTORY.SIZE"); @@ -73,14 +76,14 @@ public void update() { boolean centerItems = getBooleanOrDefault("GUIS.MATCH-HISTORY.CENTER-ITEMS", true); int configuredStart = GUIFile.getInt("GUIS.MATCH-HISTORY.START-SLOT"); // -1 means auto - // ── Build inventory ──────────────────────────────────── + // Build inventory Inventory inventory = InventoryUtil.createInventory(rawTitle, size / 9); // Fill with configurable glass pane ItemStack filler = buildFillerItem(); for (int i = 0; i < size; i++) inventory.setItem(i, filler); - // ── Determine where to place the match items ─────────── + // Determine where to place the match items int startSlot; if (configuredStart >= 0) { startSlot = configuredStart; @@ -90,7 +93,7 @@ public void update() { startSlot = 0; } - // ── Place match items ────────────────────────────────── + // Place match items String materialStr = GUIFile.getString("GUIS.MATCH-HISTORY.MATCH-ITEM.MATERIAL"); Material material = Material.PAPER; if (materialStr != null && !materialStr.isBlank()) { @@ -110,8 +113,7 @@ public void update() { gui.put(1, inventory); } - // ── Item builders ──────────────────────────────────────────── - + // Item builders private ItemStack buildMatchItem(MatchHistoryEntry entry, Material fallbackMaterial, boolean usePlayerHead) { @@ -130,7 +132,7 @@ private ItemStack buildMatchItem(MatchHistoryEntry entry, : StringUtil.CC(GUIFile.getString( "GUIS.MATCH-HISTORY.MESSAGES.LOSS")); final String result = (rawResult == null || rawResult.isBlank()) - ? (won ? "§aWin" : draw ? "§eEquality" : "§cLoss") + ? (won ? "Win" : draw ? "Equality" : "Loss") : rawResult; double myHealth = getMyHealth(entry); @@ -138,14 +140,14 @@ private ItemStack buildMatchItem(MatchHistoryEntry entry, int myScore = getMyScore(entry); int oppScore = getOpponentScore(entry); - // ── Name ────────────────────────────────────────────── + // Name String rawName = GUIFile.getString("GUIS.MATCH-HISTORY.MATCH-ITEM.NAME"); if (rawName == null || rawName.isBlank()) - rawName = "&eMatch vs &f%opponent%"; + rawName = "Match vs %opponent%"; String displayName = applyPlaceholders(rawName, entry, oppName, result, myScore, oppScore, myHealth, oppHealth, won, draw); - // ── Lore ────────────────────────────────────────────── + // Lore List loreCfg = GUIFile.getStringList("GUIS.MATCH-HISTORY.MATCH-ITEM.LORE"); if (loreCfg == null || loreCfg.isEmpty()) { loreCfg = defaultLore(); @@ -156,7 +158,7 @@ private ItemStack buildMatchItem(MatchHistoryEntry entry, .map(line -> Common.legacyToComponent(StringUtil.CC(line))) .collect(Collectors.toList()); - // ── ItemStack ───────────────────────────────────────── + // ItemStack ItemStack item; if (usePlayerHead) { item = buildSkull(oppUuid, oppName); @@ -192,14 +194,8 @@ private ItemStack buildMatchItem(MatchHistoryEntry entry, } private ItemStack buildSkull(UUID uuid, String name) { - ItemStack skull = new ItemStack(Material.PLAYER_HEAD); - SkullMeta skullMeta = (SkullMeta) skull.getItemMeta(); - if (skullMeta != null) { - OfflinePlayer op = org.bukkit.Bukkit.getOfflinePlayer(uuid); - skullMeta.setOwningPlayer(op); - skull.setItemMeta(skullMeta); - } - return skull; + OfflinePlayer op = org.bukkit.Bukkit.getOfflinePlayer(uuid); + return ItemCreateUtil.getPlayerHead(op); } private ItemStack buildFillerItem() { @@ -218,8 +214,7 @@ private ItemStack buildFillerItem() { return item; } - // ── Centering logic ────────────────────────────────────────── - + // Centering logic /** * Computes the first slot so that {@code count} items are centred * inside the inventory. Works row-by-row: @@ -242,8 +237,7 @@ private int computeCenterStart(int size, int count) { return startRow * 9 + startCol; } - // ── Placeholder helpers ────────────────────────────────────── - + // Placeholder helpers private String applyPlaceholders(String text, MatchHistoryEntry entry, String oppName, String result, int myScore, int oppScore, @@ -266,8 +260,7 @@ private String formatHealth(double raw) { return String.format("%.1f❤", raw / 2.0); } - // ── Perspective helpers ────────────────────────────────────── - + // Perspective helpers private boolean isViewer(MatchHistoryEntry e) { return viewerUuid != null && e.getPlayerUuid().equals(viewerUuid); } @@ -296,25 +289,23 @@ private int getOpponentScore(MatchHistoryEntry e) { return isViewer(e) ? e.getOpponentScore() : e.getPlayerScore(); } - // ── Default lore ───────────────────────────────────────────── - + // Default lore private List defaultLore() { List lore = new ArrayList<>(); - lore.add("&8&m--------------------"); - lore.add("&7Result: %result%"); - lore.add("&7Score: %score%"); - lore.add("&7Kit: &f%kit%"); - lore.add("&7Arena: &f%arena%"); - lore.add("&7Your Health: %player_health%"); - lore.add("&7Opponent Health: %opponent_health%"); - lore.add("&7Duration: &f%duration%"); - lore.add("&7Played: &f%date%"); - lore.add("&8&m--------------------"); + lore.add("--------------------"); + lore.add("Result: %result%"); + lore.add("Score: %score%"); + lore.add("Kit: %kit%"); + lore.add("Arena: %arena%"); + lore.add("Your Health: %player_health%"); + lore.add("Opponent Health: %opponent_health%"); + lore.add("Duration: %duration%"); + lore.add("Played: %date%"); + lore.add("--------------------"); return lore; } - // ── Utility ───────────────────────────────────────────────── - + // Utility private boolean getBooleanOrDefault(String path, boolean def) { if (GUIFile.getConfig().isSet(path.toUpperCase())) return GUIFile.getConfig().getBoolean(path.toUpperCase()); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/arena/ArenaCreateGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/arena/ArenaCreateGui.java index a902d4845..e5f79045e 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/arena/ArenaCreateGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/arena/ArenaCreateGui.java @@ -61,7 +61,7 @@ public void update() { inventory.setItem(16, null); for (ArenaType type : ArenaType.values()) { - ItemStack item = ItemCreateUtil.createItem("&e" + type.getName(), type.getIcon()); + ItemStack item = ItemCreateUtil.createItem("" + type.getName(), type.getIcon()); ItemMeta itemMeta = item.getItemMeta(); itemMeta.lore(type.getDescription().stream().map(Common::legacyToComponent).toList()); item.setItemMeta(itemMeta); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/CosmeticsHubGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/CosmeticsHubGui.java index ad58f06ec..e658913da 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/CosmeticsHubGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/CosmeticsHubGui.java @@ -47,7 +47,7 @@ public CosmeticsHubGui(Profile profile) { this.profile = profile; String title = GUIFile.getConfig().getString( - "GUIS.COSMETICS.HUB.TITLE", "&8✦ Cosmetics"); + "GUIS.COSMETICS.HUB.TITLE", "✦ Cosmetics"); this.gui.put(1, InventoryUtil.createInventory(title, ROWS)); build(); } @@ -82,16 +82,15 @@ public void handleClickEvent(InventoryClickEvent e) { } } - // ── Button builders ────────────────────────────────────────────── - + // Button builders private ItemStack buildTrimsButton() { String name = GUIFile.getConfig().getString( - "GUIS.COSMETICS.HUB.BUTTONS.ARMOR-TRIMS.NAME", "&6✦ Armor Trims"); + "GUIS.COSMETICS.HUB.BUTTONS.ARMOR-TRIMS.NAME", "✦ Armor Trims"); Material mat = safeMaterial( GUIFile.getConfig().getString("GUIS.COSMETICS.HUB.BUTTONS.ARMOR-TRIMS.MATERIAL"), Material.DIAMOND_CHESTPLATE); List lore = getOrDefaultLore("GUIS.COSMETICS.HUB.BUTTONS.ARMOR-TRIMS.LORE", - List.of("&7Customize your armor tier,", "&7trim patterns and materials.")); + List.of("Customize your armor tier,", "trim patterns and materials.")); GUIItem item = new GUIItem(name, mat, lore); item.setGlowing(GUIFile.getConfig().getBoolean( @@ -101,18 +100,18 @@ private ItemStack buildTrimsButton() { private ItemStack buildShieldButton() { String name = GUIFile.getConfig().getString( - "GUIS.COSMETICS.HUB.BUTTONS.SHIELD.NAME", "&9✦ Shield"); + "GUIS.COSMETICS.HUB.BUTTONS.SHIELD.NAME", "✦ Shield"); Material mat = safeMaterial( GUIFile.getConfig().getString("GUIS.COSMETICS.HUB.BUTTONS.SHIELD.MATERIAL"), Material.SHIELD); List lore = getOrDefaultLore("GUIS.COSMETICS.HUB.BUTTONS.SHIELD.LORE", - List.of("&7Design your shield with any", "&7color and pattern combination.", "&7Save multiple layouts.")); + List.of("Design your shield with any", "color and pattern combination.", "Save multiple layouts.")); ShieldLayout active = profile.getCosmeticsData().getActiveShieldLayout(); List finalLore = new ArrayList<>(lore); finalLore.add(""); - finalLore.add("&7Active layout: &e" + (active != null ? active.getName() : "&cNone")); - finalLore.add("&7Saved layouts: &e" + finalLore.add("Active layout: " + (active != null ? active.getName() : "None")); + finalLore.add("Saved layouts: " + profile.getCosmeticsData().getShieldLayouts().size()); GUIItem item = new GUIItem(name, mat, finalLore); @@ -123,17 +122,17 @@ private ItemStack buildShieldButton() { private ItemStack buildKillEffectButton() { String name = GUIFile.getConfig().getString( - "GUIS.COSMETICS.HUB.BUTTONS.KILL-EFFECTS.NAME", "&c✦ Death Effects"); + "GUIS.COSMETICS.HUB.BUTTONS.KILL-EFFECTS.NAME", "✦ Death Effects"); Material mat = safeMaterial( GUIFile.getConfig().getString("GUIS.COSMETICS.HUB.BUTTONS.KILL-EFFECTS.MATERIAL"), Material.BLAZE_POWDER); List lore = getOrDefaultLore("GUIS.COSMETICS.HUB.BUTTONS.KILL-EFFECTS.LORE", - List.of("&7Choose a particle effect", "&7that plays when you kill someone.")); + List.of("Choose a particle effect", "that plays when you kill someone.")); DeathEffect active = profile.getCosmeticsData().getDeathEffect(); List finalLore = new ArrayList<>(lore); finalLore.add(""); - finalLore.add("&7Active effect: &e" + (active != null ? active.getDisplayName() : "&cNone")); + finalLore.add("Active effect: " + (active != null ? active.getDisplayName() : "None")); GUIItem item = new GUIItem(name, mat, finalLore); item.setGlowing(GUIFile.getConfig().getBoolean( @@ -143,17 +142,17 @@ private ItemStack buildKillEffectButton() { private ItemStack buildLobbyItemsButton() { String name = GUIFile.getConfig().getString( - "GUIS.COSMETICS.HUB.BUTTONS.LOBBY-ITEMS.NAME", "&b✦ Lobby Items"); + "GUIS.COSMETICS.HUB.BUTTONS.LOBBY-ITEMS.NAME", "✦ Lobby Items"); Material mat = safeMaterial( GUIFile.getConfig().getString("GUIS.COSMETICS.HUB.BUTTONS.LOBBY-ITEMS.MATERIAL"), Material.ELYTRA); List lore = getOrDefaultLore("GUIS.COSMETICS.HUB.BUTTONS.LOBBY-ITEMS.LORE", - List.of("&7Select movement cosmetics", "&7for your lobby loadout.")); + List.of("Select movement cosmetics", "for your lobby loadout.")); CosmeticsData.LobbyItemType active = profile.getCosmeticsData().getLobbyItemType(); List finalLore = new ArrayList<>(lore); finalLore.add(""); - finalLore.add("&7Active item: &e" + formatName(active == null ? "NONE" : active.name())); + finalLore.add("Active item: " + formatName(active == null ? "NONE" : active.name())); GUIItem item = new GUIItem(name, mat, finalLore); item.setGlowing(GUIFile.getConfig().getBoolean( @@ -161,8 +160,7 @@ private ItemStack buildLobbyItemsButton() { return item.get(); } - // ── Helpers ────────────────────────────────────────────────────── - + // Helpers private List getOrDefaultLore(String key, List defaults) { List lore = GUIFile.getConfig().getStringList(key); return lore.isEmpty() ? defaults : lore; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/LobbyItemsGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/LobbyItemsGui.java index 96430e7b2..8de1475d6 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/LobbyItemsGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/LobbyItemsGui.java @@ -38,7 +38,7 @@ public LobbyItemsGui(Profile profile, GUI backToGui) { this.profile = profile; this.backToGui = backToGui; - String title = GUIFile.getConfig().getString("GUIS.COSMETICS.LOBBY-ITEMS.TITLE", "&8✦ Lobby Items"); + String title = GUIFile.getConfig().getString("GUIS.COSMETICS.LOBBY-ITEMS.TITLE", "✦ Lobby Items"); this.gui.put(1, InventoryUtil.createInventory(title, ROWS)); build(); } @@ -120,22 +120,22 @@ private ItemStack buildOptionItem(CosmeticsData.LobbyItemType type, CosmeticsDat boolean active = type == selected; String basePath = "GUIS.COSMETICS.LOBBY-ITEMS.ENTRIES." + type.name(); - String name = GUIFile.getConfig().getString(basePath + ".NAME", "&e" + formatName(type)); + String name = GUIFile.getConfig().getString(basePath + ".NAME", "" + formatName(type)); Material material = safeMaterial(GUIFile.getConfig().getString(basePath + ".MATERIAL"), defaultMaterial(type)); List lore = GUIFile.getConfig().getStringList(basePath + ".LORE"); if (lore.isEmpty()) { lore = new ArrayList<>(List.of( "", - "&7Status: %status%", - "&7Required: &f%permission%", + "Status: %status%", + "Required: %permission%", "" )); } else { lore = new ArrayList<>(lore); } - String status = active ? "&aSelected" : (unlocked ? "&eUnlocked" : "&cLocked"); + String status = active ? "Selected" : (unlocked ? "Unlocked" : "Locked"); String permission = type == CosmeticsData.LobbyItemType.NONE ? "none" : type.getPermissionNode(); lore.replaceAll(line -> line .replace("%status%", status) @@ -143,11 +143,11 @@ private ItemStack buildOptionItem(CosmeticsData.LobbyItemType type, CosmeticsDat .replace("%type%", formatName(type))); if (active) { - lore.add("&7Click to disable."); + lore.add("Click to disable."); } else if (unlocked) { - lore.add("&eClick to select."); + lore.add("Click to select."); } else { - lore.add("&cYou do not have permission."); + lore.add("You do not have permission."); } GUIItem item = new GUIItem(name, material, lore); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/ArmorPieceHubGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/ArmorPieceHubGui.java index 69699503b..caf6c48b3 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/ArmorPieceHubGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/ArmorPieceHubGui.java @@ -50,7 +50,7 @@ public ArmorPieceHubGui(Profile profile, ArmorSlot armorSlot, GUI backToGui) { this.profile = profile; this.armorSlot = armorSlot; this.backToGui = backToGui; - this.gui.put(1, InventoryUtil.createInventory("&8" + armorSlot.getDisplayName() + " Cosmetics", INVENTORY_ROWS)); + this.gui.put(1, InventoryUtil.createInventory("" + armorSlot.getDisplayName() + " Cosmetics", INVENTORY_ROWS)); build(); } @@ -106,7 +106,7 @@ public void handleClickEvent(InventoryClickEvent e) { private ItemStack buildPreviewItem(ArmorTrimTier tier, TrimPattern pattern, TrimMaterial material) { Material previewMaterial = tier.getMaterial(armorSlot); GUIItem item = new GUIItem(previewMaterial); - item.setName(GUIFile.getConfig().getString("GUIS.COSMETICS.ARMOR-PIECE-HUB.PREVIEW-ITEM.NAME", "&eCurrent Preview")); + item.setName(GUIFile.getConfig().getString("GUIS.COSMETICS.ARMOR-PIECE-HUB.PREVIEW-ITEM.NAME", "Current Preview")); ItemStack itemStack = item.get(); if (armorSlot != ArmorSlot.SHIELD && pattern != null && material != null && itemStack.getItemMeta() instanceof ArmorMeta armorMeta) { @@ -123,7 +123,7 @@ private ItemStack buildNavigationItem(Material material, String name, String lor List lore = new ArrayList<>(); lore.add(loreLine); - lore.add("&eClick to open."); + lore.add("Click to open."); item.setLore(lore); return item.get(); @@ -139,7 +139,7 @@ private ItemStack buildPatternSelectionItem(TrimPattern activePattern) { } } - String name = GUIFile.getConfig().getString("GUIS.COSMETICS.ARMOR-PIECE-HUB.PATTERN-SELECTION-BUTTON.NAME", "&bPattern Selection"); + String name = GUIFile.getConfig().getString("GUIS.COSMETICS.ARMOR-PIECE-HUB.PATTERN-SELECTION-BUTTON.NAME", "Pattern Selection"); String loreLine = GUIFile.getConfig().getStringList("GUIS.COSMETICS.ARMOR-PIECE-HUB.PATTERN-SELECTION-BUTTON.LORE").getFirst(); return buildNavigationItem(buttonMaterial, name, loreLine); } @@ -153,7 +153,7 @@ private ItemStack buildMaterialSelectionItem(TrimMaterial activeMaterial) { } } - String name = GUIFile.getConfig().getString("GUIS.COSMETICS.ARMOR-PIECE-HUB.MATERIAL-SELECTION-BUTTON.NAME", "&6Material Selection"); + String name = GUIFile.getConfig().getString("GUIS.COSMETICS.ARMOR-PIECE-HUB.MATERIAL-SELECTION-BUTTON.NAME", "Material Selection"); String loreLine = GUIFile.getConfig().getStringList("GUIS.COSMETICS.ARMOR-PIECE-HUB.MATERIAL-SELECTION-BUTTON.LORE").getFirst(); return buildNavigationItem(buttonMaterial, name, loreLine); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/ArmorTrimMainGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/ArmorTrimMainGui.java index 4af74943c..9d54eb488 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/ArmorTrimMainGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/ArmorTrimMainGui.java @@ -188,8 +188,8 @@ private ItemStack buildArmorPreviewItem(GUIItem configuredItem, ArmorTrimTier ti for (String line : lorTemplate) { String processedLine = line .replace("%tier%", tier.getDisplayName()) - .replace("%pattern%", activePattern == null ? "&cNone" : "&b" + formatDisplayName(activePattern)) - .replace("%material%", activeMaterial == null ? "&cNone" : "&6" + formatDisplayName(activeMaterial)); + .replace("%pattern%", activePattern == null ? "None" : "" + formatDisplayName(activePattern)) + .replace("%material%", activeMaterial == null ? "None" : "" + formatDisplayName(activeMaterial)); lore.add(processedLine); } guiItem.setLore(lore); @@ -231,7 +231,7 @@ private ItemStack buildTierToggleItem(ArmorTrimTier activeTier) { guiItem.replace("%pattern_total%", String.valueOf(totalPatternPermissions)); guiItem.replace("%material_unlocked%", String.valueOf(playerMaterialPermissions)); guiItem.replace("%material_total%", String.valueOf(totalMaterialPermissions)); - guiItem.setName("&bArmor Tier: &e" + activeTier.getDisplayName()); + guiItem.setName("Armor Tier: " + activeTier.getDisplayName()); List lore = guiItem.getLore() == null ? new ArrayList<>() : new ArrayList<>(guiItem.getLore()); @@ -250,20 +250,20 @@ private ItemStack buildApplyToAllTiersItem() { guiItem.setMaterial(guiItem.getMaterial() == null ? Material.SMITHING_TABLE : guiItem.getMaterial()); if (guiItem.getName() == null || guiItem.getName().isEmpty()) { - guiItem.setName("&aApply Current Tier To All Tiers"); + guiItem.setName("Apply Current Tier To All Tiers"); } if (guiItem.getLore() == null || guiItem.getLore().isEmpty()) { List lore = new ArrayList<>(); - lore.add("&7Copies the active tier trim setup"); - lore.add("&7to every armor tier."); + lore.add("Copies the active tier trim setup"); + lore.add("to every armor tier."); lore.add(""); - lore.add("&eHelmet -> Helmet"); - lore.add("&eChestplate -> Chestplate"); - lore.add("&eLeggings -> Leggings"); - lore.add("&eBoots -> Boots"); + lore.add("Helmet -> Helmet"); + lore.add("Chestplate -> Chestplate"); + lore.add("Leggings -> Leggings"); + lore.add("Boots -> Boots"); lore.add(""); - lore.add("&aClick to apply"); + lore.add("Click to apply"); guiItem.setLore(lore); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/MaterialSelectionGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/MaterialSelectionGui.java index dd303cc62..4aec2cb3f 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/MaterialSelectionGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/MaterialSelectionGui.java @@ -42,7 +42,7 @@ public MaterialSelectionGui(Profile profile, ArmorSlot armorSlot, GUI backToGui) this.profile = profile; this.armorSlot = armorSlot; this.backToGui = backToGui; - String title = GUIFile.getConfig().getString("GUIS.COSMETICS.MATERIAL-SELECTION.INVENTORY-TITLE", "&8Select Material - %armor%") + String title = GUIFile.getConfig().getString("GUIS.COSMETICS.MATERIAL-SELECTION.INVENTORY-TITLE", "Select Material - %armor%") .replace("%armor%", armorSlot.getDisplayName()); this.gui.put(1, InventoryUtil.createInventory(title, INVENTORY_ROWS)); build(); @@ -136,7 +136,7 @@ private ItemStack buildMaterialItem(Player player, ArmorTrimTier tier, TrimMater GUIItem item = new GUIItem(resolveIcon(materialId)); - String itemName = GUIFile.getConfig().getString("GUIS.COSMETICS.MATERIAL-SELECTION.MATERIAL-ITEM.NAME", "&6%material_name% Material") + String itemName = GUIFile.getConfig().getString("GUIS.COSMETICS.MATERIAL-SELECTION.MATERIAL-ITEM.NAME", "%material_name% Material") .replace("%material_name%", StringUtil.getNormalizedName(materialId)); item.setName(itemName); @@ -144,8 +144,8 @@ private ItemStack buildMaterialItem(Player player, ArmorTrimTier tier, TrimMater List lore = new ArrayList<>(); for (String loreLine : configLore) { lore.add(loreLine - .replace("%state%", active ? "&aActive" : "&cInactive") - .replace("%access%", hasPermission ? "&aUnlocked" : "&cLocked") + .replace("%state%", active ? "Active" : "Inactive") + .replace("%access%", hasPermission ? "Unlocked" : "Locked") .replace("%permission%", permissionNode)); } item.setLore(lore); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/PatternSelectionGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/PatternSelectionGui.java index a3a1ec223..4e35d6b8d 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/PatternSelectionGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/armortrim/PatternSelectionGui.java @@ -39,7 +39,7 @@ public PatternSelectionGui(Profile profile, ArmorSlot armorSlot, GUI backToGui) this.profile = profile; this.armorSlot = armorSlot; this.backToGui = backToGui; - String title = GUIFile.getConfig().getString("GUIS.COSMETICS.PATTERN-SELECTION.INVENTORY-TITLE", "&8Select Pattern - %armor%") + String title = GUIFile.getConfig().getString("GUIS.COSMETICS.PATTERN-SELECTION.INVENTORY-TITLE", "Select Pattern - %armor%") .replace("%armor%", armorSlot.getDisplayName()); this.gui.put(1, InventoryUtil.createInventory(title, INVENTORY_ROWS)); build(); @@ -137,7 +137,7 @@ private ItemStack buildPatternItem(Player player, ArmorTrimTier tier, TrimPatter } GUIItem item = new GUIItem(templateMaterial == null ? Material.PAPER : templateMaterial); - String itemName = GUIFile.getConfig().getString("GUIS.COSMETICS.PATTERN-SELECTION.PATTERN-ITEM.NAME", "&b%pattern_name% Pattern") + String itemName = GUIFile.getConfig().getString("GUIS.COSMETICS.PATTERN-SELECTION.PATTERN-ITEM.NAME", "%pattern_name% Pattern") .replace("%pattern_name%", StringUtil.getNormalizedName(patternId)); item.setName(itemName); @@ -145,8 +145,8 @@ private ItemStack buildPatternItem(Player player, ArmorTrimTier tier, TrimPatter List lore = new ArrayList<>(); for (String loreLine : configLore) { lore.add(loreLine - .replace("%state%", active ? "&aActive" : "&cInactive") - .replace("%access%", hasPermission ? "&aUnlocked" : "&cLocked") + .replace("%state%", active ? "Active" : "Inactive") + .replace("%access%", hasPermission ? "Unlocked" : "Locked") .replace("%permission%", permissionNode)); } item.setLore(lore); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/deatheffect/DeathEffectsGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/deatheffect/DeathEffectsGui.java index fa67fb37d..6e521ad24 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/deatheffect/DeathEffectsGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/deatheffect/DeathEffectsGui.java @@ -54,7 +54,7 @@ public DeathEffectsGui(Profile profile, GUI backToGui) { this.backToGui = backToGui; String title = GUIFile.getConfig().getString( - "GUIS.COSMETICS.DEATH-EFFECTS.TITLE", "&8Death Effects"); + "GUIS.COSMETICS.DEATH-EFFECTS.TITLE", "Death Effects"); this.gui.put(1, InventoryUtil.createInventory(title, ROWS)); build(); } @@ -148,11 +148,11 @@ private ItemStack buildEffectItem(DeathEffect deathEffect, DeathEffect active, P String statusPrefix; if (isActive) { - statusPrefix = "&a&lSelected &8| &f"; + statusPrefix = "Selected | "; } else if (hasPerms) { - statusPrefix = "&e&lUnlocked &8| &f"; + statusPrefix = "Unlocked | "; } else { - statusPrefix = "&c&lLocked &8| &f"; + statusPrefix = "Locked | "; } item.setName(statusPrefix + nameTemplate); @@ -165,24 +165,24 @@ private ItemStack buildEffectItem(DeathEffect deathEffect, DeathEffect active, P "GUIS.COSMETICS.DEATH-EFFECTS.DEFAULT-LORE"); } for (String line : loreTemplate) { - lore.add(line.replace("%status%", isActive ? "&aSelected" : (hasPerms ? "&eUnlocked" : "&cLocked"))); + lore.add(line.replace("%status%", isActive ? "Selected" : (hasPerms ? "Unlocked" : "Locked"))); } - lore.add(0, "&8Status: " + (isActive ? "&aSelected" : (hasPerms ? "&eUnlocked" : "&cLocked"))); + lore.add(0, "Status: " + (isActive ? "Selected" : (hasPerms ? "Unlocked" : "Locked"))); lore.add(1, ""); if (isActive) { lore.add(""); lore.add(GUIFile.getConfig().getString( - "GUIS.COSMETICS.DEATH-EFFECTS.CLICK-TO-DESELECT", "&7Click to deselect this effect.")); + "GUIS.COSMETICS.DEATH-EFFECTS.CLICK-TO-DESELECT", "Click to deselect this effect.")); } else if (hasPerms) { lore.add(""); lore.add(GUIFile.getConfig().getString( - "GUIS.COSMETICS.DEATH-EFFECTS.CLICK-TO-SELECT", "&eClick to select this effect.")); - lore.add("&7A preview will play for you."); + "GUIS.COSMETICS.DEATH-EFFECTS.CLICK-TO-SELECT", "Click to select this effect.")); + lore.add("A preview will play for you."); } else { lore.add(""); - lore.add("&cYou do not have permission for this effect."); + lore.add("You do not have permission for this effect."); } item.setLore(lore); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldColorPickerGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldColorPickerGui.java index bfcd99c2c..7458de5d8 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldColorPickerGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldColorPickerGui.java @@ -59,8 +59,8 @@ public ShieldColorPickerGui(Profile profile, int layoutIndex, boolean isBase = (layerIndex == -1); String title = isBase - ? GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.COLOR-PICKER.BASE-TITLE", "&8Pick Base Color") - : GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.COLOR-PICKER.LAYER-TITLE", "&8Pick Layer Color"); + ? GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.COLOR-PICKER.BASE-TITLE", "Pick Base Color") + : GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.COLOR-PICKER.LAYER-TITLE", "Pick Layer Color"); this.gui.put(1, InventoryUtil.createInventory(title, ROWS)); build(); } @@ -121,10 +121,10 @@ private ItemStack buildColorItem(DyeColor color) { GUIItem item = new GUIItem(wool); boolean active = (color == preselected); - String prefix = active ? "&a✔ " : "&f"; + String prefix = active ? "✔ " : ""; item.setName(prefix + fmt(color.name())); List lore = new ArrayList<>(); - lore.add(active ? "&7Currently selected." : "&eClick to select."); + lore.add(active ? "Currently selected." : "Click to select."); item.setLore(lore); if (active) item.setGlowing(true); return item.get(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldEditorGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldEditorGui.java index 7788eb0e0..e1e6c1f65 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldEditorGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldEditorGui.java @@ -58,7 +58,7 @@ public ShieldEditorGui(Profile profile, int layoutIndex, GUI backToGui) { ShieldLayout layout = getLayout(); String layoutName = layout != null ? layout.getName() : "Shield"; String title = GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.EDITOR.TITLE", - "&8Editing: &e%name%").replace("%name%", layoutName); + "Editing: %name%").replace("%name%", layoutName); this.gui.put(1, InventoryUtil.createInventory(title, ROWS)); build(); } @@ -99,13 +99,13 @@ public void update() { boolean canAdd = layout.getLayers().size() < ShieldLayout.MAX_LAYERS; GUIItem addBtn = new GUIItem(canAdd ? Material.LIME_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE); addBtn.setName(canAdd - ? GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.EDITOR.ADD-LAYER.NAME", "&aAdd Layer") - : GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.EDITOR.MAX-LAYERS.NAME", "&cMax Layers Reached")); + ? GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.EDITOR.ADD-LAYER.NAME", "Add Layer") + : GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.EDITOR.MAX-LAYERS.NAME", "Max Layers Reached")); List addLore = new ArrayList<>(); - addLore.add("&7Layers: &f" + layout.getLayers().size() + "&7/&f" + ShieldLayout.MAX_LAYERS); + addLore.add("Layers: " + layout.getLayers().size() + "/" + ShieldLayout.MAX_LAYERS); if (canAdd) { - addLore.add("&eClick to add a new layer."); - addLore.add("&7Step 1: choose color, Step 2: choose pattern."); + addLore.add("Click to add a new layer."); + addLore.add("Step 1: choose color, Step 2: choose pattern."); } addBtn.setLore(addLore); inv.setItem(ADD_LAYER_SLOT, addBtn.get()); @@ -114,12 +114,12 @@ public void update() { boolean canRemove = !layout.getLayers().isEmpty(); GUIItem removeBtn = new GUIItem(canRemove ? Material.ORANGE_STAINED_GLASS_PANE : Material.GRAY_STAINED_GLASS_PANE); removeBtn.setName(canRemove - ? GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.EDITOR.REMOVE-LAYER.NAME", "&cRemove Top Layer") - : "&8No layers to remove"); + ? GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.EDITOR.REMOVE-LAYER.NAME", "Remove Top Layer") + : "No layers to remove"); if (canRemove) { List remLore = new ArrayList<>(); - remLore.add("&7Removes the most recently added layer."); - remLore.add("&cClick to remove."); + remLore.add("Removes the most recently added layer."); + remLore.add("Click to remove."); removeBtn.setLore(remLore); } inv.setItem(REMOVE_LAYER_SLOT, removeBtn.get()); @@ -183,8 +183,7 @@ public void handleClickEvent(InventoryClickEvent e) { } } - // ── Apply / unapply ────────────────────────────────────────────── - + // Apply / unapply private void handleApply(Player player) { int current = profile.getCosmeticsData().getActiveShieldLayoutIndex(); if (current == layoutIndex) { @@ -204,17 +203,16 @@ private void handleApply(Player player) { update(true); } - // ── Item builders ──────────────────────────────────────────────── - + // Item builders private ItemStack buildPreviewShield(ShieldLayout layout) { ItemStack shield = new ItemStack(Material.SHIELD); ShieldCosmeticsUtil.applyLayoutToItem(shield, layout); ItemMeta meta = shield.getItemMeta(); if (meta != null) { - meta.displayName(tc("&eShield Preview")); + meta.displayName(tc("Shield Preview")); List lore = new ArrayList<>(); - lore.add(tc("&7Base: &f" + (layout.getBaseColor() != null ? fmt(layout.getBaseColor().name()) : "White"))); - lore.add(tc("&7Layers: &f" + layout.getLayers().size() + "&7/&f" + ShieldLayout.MAX_LAYERS)); + lore.add(tc("Base: " + (layout.getBaseColor() != null ? fmt(layout.getBaseColor().name()) : "White"))); + lore.add(tc("Layers: " + layout.getLayers().size() + "/" + ShieldLayout.MAX_LAYERS)); meta.lore(lore); meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS); shield.setItemMeta(meta); @@ -226,10 +224,10 @@ private ItemStack buildBaseColorButton(ShieldLayout layout) { DyeColor base = layout.getBaseColor() != null ? layout.getBaseColor() : DyeColor.WHITE; Material wool = dyeToWool(base); GUIItem item = new GUIItem(wool); - item.setName("&bBase Color: &f" + fmt(base.name())); + item.setName("Base Color: " + fmt(base.name())); List lore = new ArrayList<>(); - lore.add("&7The background color of your shield."); - lore.add("&eClick to change."); + lore.add("The background color of your shield."); + lore.add("Click to change."); item.setLore(lore); return item.get(); } @@ -237,9 +235,9 @@ private ItemStack buildBaseColorButton(ShieldLayout layout) { private ItemStack buildApplyButton(boolean isActive) { Material mat = isActive ? Material.LIME_WOOL : Material.GRAY_WOOL; GUIItem item = new GUIItem(mat); - item.setName(isActive ? "&a&lLayout Active &7(Click to unapply)" : "&eApply This Layout"); + item.setName(isActive ? "Layout Active (Click to unapply)" : "Apply This Layout"); List lore = new ArrayList<>(); - lore.add(isActive ? "&7This design is on your shield." : "&7Apply this design to your shield."); + lore.add(isActive ? "This design is on your shield." : "Apply this design to your shield."); item.setLore(lore); if (isActive) item.setGlowing(true); return item.get(); @@ -248,7 +246,7 @@ private ItemStack buildApplyButton(boolean isActive) { private ItemStack buildLayerItem(ShieldLayout.PatternLayer layer, int index) { Material banner = dyeToBanner(layer.color()); GUIItem item = new GUIItem(banner); - item.setName("&fLayer " + (index + 1) + ": &e" + getPatternDisplayName(layer.pattern())); + item.setName("Layer " + (index + 1) + ": " + getPatternDisplayName(layer.pattern())); // Apply pattern to the banner icon ItemStack stack = item.get(); @@ -260,11 +258,11 @@ private ItemStack buildLayerItem(ShieldLayout.PatternLayer layer, int index) { ItemMeta meta = stack.getItemMeta(); if (meta != null) { List lore = new ArrayList<>(); - lore.add(tc("&7Color: &f" + fmt(layer.color().name()))); - lore.add(tc("&7Pattern: &f" + getPatternDisplayName(layer.pattern()))); + lore.add(tc("Color: " + fmt(layer.color().name()))); + lore.add(tc("Pattern: " + getPatternDisplayName(layer.pattern()))); lore.add(tc("")); - lore.add(tc("&eClick to edit this layer.")); - lore.add(tc("&7Use Add Layer for a new slot.")); + lore.add(tc("Click to edit this layer.")); + lore.add(tc("Use Add Layer for a new slot.")); meta.lore(lore); meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS); stack.setItemMeta(meta); @@ -272,8 +270,7 @@ private ItemStack buildLayerItem(ShieldLayout.PatternLayer layer, int index) { return stack; } - // ── Helpers ────────────────────────────────────────────────────── - + // Helpers private ShieldLayout getLayout() { List layouts = profile.getCosmeticsData().getShieldLayouts(); if (layoutIndex < 0 || layoutIndex >= layouts.size()) return null; @@ -281,7 +278,7 @@ private ShieldLayout getLayout() { } private static net.kyori.adventure.text.Component tc(String legacy) { - return net.kyori.adventure.text.Component.text(StringUtil.CC(legacy)); + return dev.nandi0813.practice.util.Common.deserializeMiniMessage(legacy); } private static String fmt(String raw) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldLayoutListGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldLayoutListGui.java index a40127956..92d9a2028 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldLayoutListGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldLayoutListGui.java @@ -54,7 +54,7 @@ public ShieldLayoutListGui(Profile profile, GUI backToGui) { super(GUIType.Cosmetics_Shield_Layouts); this.profile = profile; this.backToGui = backToGui; - String title = GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.LAYOUTS.TITLE", "&8Shield Layouts"); + String title = GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.LAYOUTS.TITLE", "Shield Layouts"); this.gui.put(1, InventoryUtil.createInventory(title, ROWS)); build(); } @@ -84,12 +84,12 @@ public void update() { boolean canCreate = layouts.size() < maxLayouts; GUIItem newItem = new GUIItem( GUIFile.getConfig().getString("GUIS.COSMETICS.SHIELD.LAYOUTS.NEW-BUTTON.NAME", - canCreate ? "&aNew Layout" : "&cLayout limit reached"), + canCreate ? "New Layout" : "Layout limit reached"), canCreate ? Material.LIME_DYE : Material.RED_DYE); List newLore = new ArrayList<>(); - newLore.add("&7Saved: &e" + layouts.size() + "&7/&e" + maxLayouts); - if (canCreate) newLore.add("&eClick to create a new layout."); - else newLore.add("&cGet a higher rank for more slots."); + newLore.add("Saved: " + layouts.size() + "/" + maxLayouts); + if (canCreate) newLore.add("Click to create a new layout."); + else newLore.add("Get a higher rank for more slots."); newItem.setLore(newLore); inv.setItem(NEW_SLOT, newItem.get()); @@ -215,37 +215,35 @@ private void handleRename(Player player, int index) { .open(player); } - // ── Builders ───────────────────────────────────────────────────── - + // Builders private ItemStack buildLayoutItem(ShieldLayout layout, int index, boolean active) { ItemStack shield = new ItemStack(Material.SHIELD); ShieldCosmeticsUtil.applyLayoutToItem(shield, layout); var meta = shield.getItemMeta(); if (meta != null) { - String nameColor = active ? "&a✔ " : "&e"; - meta.displayName(net.kyori.adventure.text.Component.text( - dev.nandi0813.practice.util.StringUtil.CC(nameColor + layout.getName()))); + String nameColor = active ? "✔ " : ""; + meta.displayName(dev.nandi0813.practice.util.Common.deserializeMiniMessage(nameColor + layout.getName())); List lore = new ArrayList<>(); String base = layout.getBaseColor() != null ? formatName(layout.getBaseColor().name()) : "White"; - lore.add(tc("&7Base color: &f" + base)); - lore.add(tc("&7Layers: &f" + layout.getLayers().size() + "&7/&f" + ShieldLayout.MAX_LAYERS)); + lore.add(tc("Base color: " + base)); + lore.add(tc("Layers: " + layout.getLayers().size() + "/" + ShieldLayout.MAX_LAYERS)); if (!layout.getLayers().isEmpty()) { - lore.add(tc("&8─────────────────")); + lore.add(tc("─────────────────")); for (int i = 0; i < layout.getLayers().size(); i++) { ShieldLayout.PatternLayer layer = layout.getLayers().get(i); - lore.add(tc("&7" + (i + 1) + ". &f" + formatName(layer.color().name()) - + " &8│ &f" + getPatternDisplayName(layer.pattern()))); + lore.add(tc("" + (i + 1) + ". " + formatName(layer.color().name()) + + " " + getPatternDisplayName(layer.pattern()))); } } - lore.add(tc("&8─────────────────")); + lore.add(tc("─────────────────")); if (active) { - lore.add(tc("&a&lCurrently Active")); + lore.add(tc("Currently Active")); } - lore.add(tc("&eLeft-click &7to edit")); - lore.add(tc("&bShift-click &7to rename")); - lore.add(tc("&cRight-click &7to delete")); + lore.add(tc("Left-click to edit")); + lore.add(tc("Shift-click to rename")); + lore.add(tc("Right-click to delete")); meta.lore(lore); meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS); shield.setItemMeta(meta); @@ -259,8 +257,7 @@ public static int getMaxLayouts(Player player) { } private static net.kyori.adventure.text.Component tc(String legacy) { - return net.kyori.adventure.text.Component.text( - dev.nandi0813.practice.util.StringUtil.CC(legacy)); + return dev.nandi0813.practice.util.Common.deserializeMiniMessage(legacy); } private static String formatName(String raw) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldPatternPickerGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldPatternPickerGui.java index 658c183e4..16a4c426f 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldPatternPickerGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/cosmetics/shield/ShieldPatternPickerGui.java @@ -72,7 +72,7 @@ public ShieldPatternPickerGui(Profile profile, int layoutIndex, this.backToGui = backToGui; String title = GUIFile.getConfig().getString( - "GUIS.COSMETICS.SHIELD.PATTERN-PICKER.TITLE", "&8Pick Pattern"); + "GUIS.COSMETICS.SHIELD.PATTERN-PICKER.TITLE", "Pick Pattern"); this.gui.put(1, InventoryUtil.createInventory(title, ROWS)); build(); } @@ -96,11 +96,11 @@ public void update() { // Navigation if (page > 0) { - GUIItem prev = new GUIItem("&ePrevious Page &8(" + page + "/" + totalPages + ")", Material.ARROW); + GUIItem prev = new GUIItem("Previous Page (" + page + "/" + totalPages + ")", Material.ARROW); inv.setItem(PREV_SLOT, prev.get()); } if (page < totalPages - 1) { - GUIItem next = new GUIItem("&eNext Page &8(" + (page + 2) + "/" + totalPages + ")", Material.ARROW); + GUIItem next = new GUIItem("Next Page (" + (page + 2) + "/" + totalPages + ")", Material.ARROW); inv.setItem(NEXT_SLOT, next.get()); } @@ -170,14 +170,13 @@ private void handlePatternPick(Player player, PatternType pattern) { backToGui.open(player); } - // ── Item builder ───────────────────────────────────────────────── - + // Item builder private ItemStack buildPatternItem(PatternType pattern) { // Material already encodes the base colour (e.g. RED_BANNER for RED). // In 1.21.1 BannerMeta no longer has setBaseColor(); the colour is the Material. Material bannerMat = ShieldEditorGui.dyeToBanner(chosenColor); GUIItem item = new GUIItem(bannerMat); - item.setName("&f" + getPatternDisplayName(pattern)); + item.setName("" + getPatternDisplayName(pattern)); ItemStack stack = item.get(); // Apply the pattern using a contrasting colour so it is visible @@ -187,15 +186,15 @@ private ItemStack buildPatternItem(PatternType pattern) { bm.addPattern(new Pattern(contrast, pattern)); bm.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS); List lore = new ArrayList<>(); - lore.add(tc("&7Color: &f" + fmt(chosenColor.name()))); - lore.add(tc("&eClick to apply.")); + lore.add(tc("Color: " + fmt(chosenColor.name()))); + lore.add(tc("Click to apply.")); bm.lore(lore); stack.setItemMeta(bm); } else if (stack.hasItemMeta()) { ItemMeta meta = stack.getItemMeta(); List lore = new ArrayList<>(); - lore.add(tc("&7Color: &f" + fmt(chosenColor.name()))); - lore.add(tc("&eClick to apply.")); + lore.add(tc("Color: " + fmt(chosenColor.name()))); + lore.add(tc("Click to apply.")); meta.lore(lore); stack.setItemMeta(meta); } @@ -209,7 +208,7 @@ private ShieldLayout getLayout() { } private static net.kyori.adventure.text.Component tc(String legacy) { - return net.kyori.adventure.text.Component.text(StringUtil.CC(legacy)); + return dev.nandi0813.practice.util.Common.deserializeMiniMessage(legacy); } private static String fmt(String raw) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/customladder/premadecustom/CustomLadderEditorGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/customladder/premadecustom/CustomLadderEditorGui.java index faf146b56..5d0217353 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/customladder/premadecustom/CustomLadderEditorGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/customladder/premadecustom/CustomLadderEditorGui.java @@ -136,18 +136,6 @@ public void update() { // Load armor BEFORE filler logic to prevent filler items from overwriting armor slots ItemStack[] customKitArmor = customKit.getArmor(); - if (customKitArmor == null) { - // Legacy fallback for old kits where armor was appended to inventory[36..39] - ItemStack[] customKitInventory = customKit.getInventory(); - if (customKitInventory != null && customKitInventory.length > 39) { - customKitArmor = new ItemStack[]{ - customKitInventory[36], - customKitInventory[37], - customKitInventory[38], - customKitInventory[39] - }; - } - } if (customKitArmor == null) { customKitArmor = ladder.getKitData().getArmor(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/customladder/premadecustom/CustomLadderSelectorGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/customladder/premadecustom/CustomLadderSelectorGui.java index 4e8f84e1d..a47f7e456 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/customladder/premadecustom/CustomLadderSelectorGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/customladder/premadecustom/CustomLadderSelectorGui.java @@ -65,6 +65,9 @@ public void update() { } int slot = gui.get(1).firstEmpty(); + if (slot == -1) { + break; + } ladderSlots.put(slot, ladder); gui.get(1).setItem(slot, icon); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/ladder/LadderCreateGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/ladder/LadderCreateGui.java index 80bc2a09d..289a315ca 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/ladder/LadderCreateGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/ladder/LadderCreateGui.java @@ -66,7 +66,7 @@ public void update() { break; } - ItemStack item = ItemCreateUtil.createItem("&e" + type.getName(), type.getIcon()); + ItemStack item = ItemCreateUtil.createItem("" + type.getName(), type.getIcon()); ItemMeta itemMeta = item.getItemMeta(); itemMeta.lore(StringUtil.CC(type.getDescription()).stream().map(Common::legacyToComponent).toList()); item.setItemMeta(itemMeta); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbEloGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbEloGui.java index 94d8bd395..2f662a62a 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbEloGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbEloGui.java @@ -51,7 +51,9 @@ public void update() { if (!ladder.isRanked()) continue; if (!ladder.getMatchTypes().contains(MatchType.DUEL)) continue; - inventory.setItem(inventory.firstEmpty(), LbGuiUtil.createEloLbItem(ladder)); + int slot = inventory.firstEmpty(); + if (slot == -1) break; + inventory.setItem(slot, LbGuiUtil.createEloLbItem(ladder)); } ItemStack fillerItem = GUIFile.getGuiItem("GUIS.STATISTICS.ELO-LEADERBOARD.ICONS.FILLER-ITEM").get(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbGuiUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbGuiUtil.java index 2ab5400c1..445d04918 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbGuiUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbGuiUtil.java @@ -31,14 +31,9 @@ public enum LbGuiUtil { ; - /** - * Parses a raw config string into a Component with full color support - * (legacy &c, hex &#RRGGBB, MiniMessage tags) and italic explicitly disabled. - */ private static Component parseColor(String raw) { if (raw == null || raw.isEmpty()) return Component.empty(); - return ZonePractice.getMiniMessage() - .deserialize(StringUtil.translateColorsToMiniMessage(raw)) + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(raw)) .decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE); } @@ -92,9 +87,9 @@ public static GUIItem createLadderStatItem(Profile profile, NormalLadder ladder) } String divisionName = profile.getStats().getDivision() != null - ? Common.mmToNormal(profile.getStats().getDivision().getFullName()) : "&cN/A"; + ? Common.mmToNormal(profile.getStats().getDivision().getFullName()) : "N/A"; String divisionShort = profile.getStats().getDivision() != null - ? Common.mmToNormal(profile.getStats().getDivision().getShortName()) : "&cN/A"; + ? Common.mmToNormal(profile.getStats().getDivision().getShortName()) : "N/A"; guiItem .replace("%ladder%", ladder.getDisplayName()) @@ -118,9 +113,9 @@ public static ItemStack createProfileAllStatItem(Profile profile) { List lore = new ArrayList<>(); String divisionName = profile.getStats().getDivision() != null - ? Common.mmToNormal(profile.getStats().getDivision().getFullName()) : "&cN/A"; + ? Common.mmToNormal(profile.getStats().getDivision().getFullName()) : "N/A"; String divisionShort = profile.getStats().getDivision() != null - ? Common.mmToNormal(profile.getStats().getDivision().getShortName()) : "&cN/A"; + ? Common.mmToNormal(profile.getStats().getDivision().getShortName()) : "N/A"; for (String line : GUIFile.getStringList("GUIS.STATISTICS.PLAYER-STATISTICS.ICONS.ALL-STAT.LORE")) { lore.add(line @@ -158,8 +153,10 @@ public static ItemStack createEloLbItem(NormalLadder ladder) { List topPlayers = new ArrayList<>(); Map list = leaderboard.getList(); for (OfflinePlayer player : list.keySet()) { - if (topPlayers.size() < showPlayers) topPlayers.add(player); - else break; + if (player.getName() != null && ProfileManager.getInstance().getProfile(player) != null) { + topPlayers.add(player); + } + if (topPlayers.size() >= showPlayers) break; } List topStrings = new ArrayList<>(); @@ -171,7 +168,7 @@ public static ItemStack createEloLbItem(NormalLadder ladder) { int stat = list.get(target); topStrings.add(GUIFile.getString("GUIS.STATISTICS.ELO-LEADERBOARD.ICONS.LADDER-LEADERBOARD.LORE.FORMAT") .replace("%number%", String.valueOf(i)) - .replace("%player%", Objects.requireNonNull(target.getName())) + .replace("%player%", target.getName()) .replace("%ladder_elo%", String.valueOf(stat)) .replace("%division%", division != null ? Common.mmToNormal(division.getFullName()) : "") .replace("%division_short%", division != null ? Common.mmToNormal(division.getShortName()) : "")); @@ -204,8 +201,10 @@ public static ItemStack createGlobalEloLb() { List topPlayers = new ArrayList<>(); Map list = leaderboard.getList(); for (OfflinePlayer player : list.keySet()) { - if (topPlayers.size() < showPlayers) topPlayers.add(player); - else break; + if (player.getName() != null && ProfileManager.getInstance().getProfile(player) != null) { + topPlayers.add(player); + } + if (topPlayers.size() >= showPlayers) break; } List topStrings = new ArrayList<>(); @@ -219,7 +218,7 @@ public static ItemStack createGlobalEloLb() { .replace("%number%", String.valueOf(i)) .replace("%division%", division != null ? Common.mmToNormal(division.getFullName()) : "") .replace("%division_short%", division != null ? Common.mmToNormal(division.getShortName()) : "") - .replace("%player%", Objects.requireNonNull(target.getName())) + .replace("%player%", target.getName()) .replace("%global_elo%", String.valueOf(stat))); } else { topStrings.add(GUIFile.getString("GUIS.STATISTICS.ELO-LEADERBOARD.ICONS.GLOBAL-LEADERBOARD.LORE.FORMAT-NULL") @@ -250,8 +249,10 @@ public static ItemStack createWinLbItem(NormalLadder ladder) { List topPlayers = new ArrayList<>(); Map list = leaderboard.getList(); for (OfflinePlayer player : list.keySet()) { - if (topPlayers.size() < showPlayers) topPlayers.add(player); - else break; + if (player.getName() != null && ProfileManager.getInstance().getProfile(player) != null) { + topPlayers.add(player); + } + if (topPlayers.size() >= showPlayers) break; } List topStrings = new ArrayList<>(); @@ -296,8 +297,10 @@ public static ItemStack createGlobalWinLb() { List topPlayers = new ArrayList<>(); Map list = leaderboard.getList(); for (OfflinePlayer player : list.keySet()) { - if (topPlayers.size() < showPlayers) topPlayers.add(player); - else break; + if (player.getName() != null && ProfileManager.getInstance().getProfile(player) != null) { + topPlayers.add(player); + } + if (topPlayers.size() >= showPlayers) break; } List topStrings = new ArrayList<>(); @@ -311,7 +314,7 @@ public static ItemStack createGlobalWinLb() { .replace("%number%", String.valueOf(i)) .replace("%division%", division != null ? Common.mmToNormal(division.getFullName()) : "") .replace("%division_short%", division != null ? Common.mmToNormal(division.getShortName()) : "") - .replace("%player%", Objects.requireNonNull(target.getName())) + .replace("%player%", target.getName()) .replace("%global_win%", String.valueOf(stat))); } else { topStrings.add(GUIFile.getString("GUIS.STATISTICS.WIN-LEADERBOARD.ICONS.GLOBAL-LEADERBOARD.LORE.FORMAT-NULL") @@ -333,18 +336,17 @@ public static ItemStack createGlobalWinLb() { public static ItemStack getCacheInfoItem() { List lore = new ArrayList<>(); - lore.add("&8&m------------------------"); - lore.add("&7This leaderboard automatically"); - lore.add("&7updates every &e5 minutes&7."); + lore.add("------------------------"); + lore.add("This leaderboard automatically"); + lore.add("updates every 5 minutes."); lore.add(""); - lore.add("&7Last update: &aRecently"); - lore.add("&7Next update: &eWithin 5 minutes"); - lore.add("&8&m------------------------"); - return buildItem(Material.CLOCK, "&eAuto-Update Info", lore); + lore.add("Last update: Recently"); + lore.add("Next update: Within 5 minutes"); + lore.add("------------------------"); + return buildItem(Material.CLOCK, "Auto-Update Info", lore); } - // ── Item building helpers ──────────────────────────────────────────────── - + // Item building helpers /** Builds an ItemStack from an existing icon with a parsed name and lore. */ private static ItemStack buildItem(ItemStack icon, String name, List lore) { ItemStack item = icon != null ? icon.clone() : new ItemStack(Material.BARRIER); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbProfileStatGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbProfileStatGui.java index 4947c441f..29f235117 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbProfileStatGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbProfileStatGui.java @@ -49,7 +49,9 @@ public void update() { for (NormalLadder ladder : LadderManager.getInstance().getLadders()) { if (!ladder.isEnabled()) continue; - inventory.setItem(inventory.firstEmpty(), LbGuiUtil.createLadderStatItem(profile, ladder).get()); + int slot = inventory.firstEmpty(); + if (slot == -1) break; + inventory.setItem(slot, LbGuiUtil.createLadderStatItem(profile, ladder).get()); } ItemStack fillerItem = GUIFile.getGuiItem("GUIS.STATISTICS.PLAYER-STATISTICS.ICONS.FILLER-ITEM").get(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbWinGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbWinGui.java index d34e5e214..fff502589 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbWinGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/leaderboard/LbWinGui.java @@ -51,7 +51,9 @@ public void update() { if (!ladder.isEnabled()) continue; if (!ladder.getMatchTypes().contains(MatchType.DUEL)) continue; - inventory.setItem(inventory.firstEmpty(), LbGuiUtil.createWinLbItem(ladder)); + int slot = inventory.firstEmpty(); + if (slot == -1) break; + inventory.setItem(slot, LbGuiUtil.createWinLbItem(ladder)); } ItemStack fillerItem = GUIFile.getGuiItem("GUIS.STATISTICS.WIN-LEADERBOARD.ICONS.FILLER-ITEM").get(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/party/PartySettingsGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/party/PartySettingsGui.java index 434850485..b50e46299 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/party/PartySettingsGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/party/PartySettingsGui.java @@ -96,6 +96,7 @@ public void handleClickEvent(InventoryClickEvent e) { update(); } else Common.sendMMMessage(player, LanguageManager.getString("PARTY.NO-PERMISSION")); + break; case 11: if (player.hasPermission("zpp.party.changelimit")) { int groupPartyLimit = PartyManager.getInstance().resolvePartyMemberLimit(party.getLeader()); @@ -118,12 +119,14 @@ public void handleClickEvent(InventoryClickEvent e) { update(); } else Common.sendMMMessage(player, LanguageManager.getString("PARTY.NO-PERMISSION")); + break; case 14: if (player.hasPermission("zpp.party.allinvite")) { party.setAllInvite(!party.isAllInvite()); update(); } else Common.sendMMMessage(player, LanguageManager.getString("PARTY.NO-PERMISSION")); + break; case 15: if (player.hasPermission("zpp.party.public")) { if (PlayerCooldown.isActive(player, CooldownObject.PUBLIC_PARTY_CHANGE)) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/profile/ProfileLadderStats.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/profile/ProfileLadderStats.java index 3189466f5..28f74ff69 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/profile/ProfileLadderStats.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/profile/ProfileLadderStats.java @@ -49,12 +49,14 @@ public void update() { { Inventory inventory = gui.get(1); inventory.clear(); + ladderSlots.clear(); for (int i = 45; i < 54; i++) inventory.setItem(i, GUIManager.getFILLER_ITEM()); for (NormalLadder ladder : LadderManager.getInstance().getLadders()) { int slot = inventory.firstEmpty(); + if (slot == -1) break; inventory.setItem(slot, getLadderStatItem(ladder)); ladderSlots.put(slot, ladder); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/profile/ProfileSetupGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/profile/ProfileSetupGui.java index 6a75daf4e..3ae754d07 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/profile/ProfileSetupGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/profile/ProfileSetupGui.java @@ -211,8 +211,8 @@ private static ItemStack getBasicInfoItem(Profile profile) { .replace("%last_played%", (profile.getStatus().equals(ProfileStatus.OFFLINE) ? StringUtil.getDate(profile.getLastJoin()) : GUIFile.getString("GUIS.PLAYER-INFORMATION.MAIN-PAGE.ICONS.BASIC-INFO.ONLINE-STATUS"))) .replace("%unranked_left%", String.valueOf(profile.getUnrankedLeft())) .replace("%ranked_left%", String.valueOf(profile.getRankedLeft())) - .replace("%division_fullName%", profile.getStats().getDivision() != null ? Common.mmToNormal(profile.getStats().getDivision().getFullName()) : "&cN/A") - .replace("%division_shortName%", profile.getStats().getDivision() != null ? Common.mmToNormal(profile.getStats().getDivision().getShortName()) : "&cN/A"); + .replace("%division_fullName%", profile.getStats().getDivision() != null ? Common.mmToNormal(profile.getStats().getDivision().getFullName()) : "N/A") + .replace("%division_shortName%", profile.getStats().getDivision() != null ? Common.mmToNormal(profile.getStats().getDivision().getShortName()) : "N/A"); return guiItem.get(); } @@ -264,8 +264,8 @@ private static ItemStack getRankedBanItem(Profile profile) { RankedBan rankedBan = profile.getRankedBan(); return GUIFile.getGuiItem("GUIS.PLAYER-INFORMATION.MAIN-PAGE.ICONS.RANKED-BAN") .replace("%player%", profile.getPlayer().getName()) - .replace("%banner%", rankedBan.getBanner() == null ? "&cConsole" : rankedBan.getBanner().getPlayer().getName()) - .replace("%reason%", rankedBan.getReason() == null ? "&cN/A" : rankedBan.getReason()) + .replace("%banner%", rankedBan.getBanner() == null ? "Console" : rankedBan.getBanner().getPlayer().getName()) + .replace("%reason%", rankedBan.getReason() == null ? "N/A" : rankedBan.getReason()) .replace("%time%", StringUtil.getDate(rankedBan.getTime())) .get(); } else diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/CustomKit/ChooseQueueTypeGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/CustomKit/ChooseQueueTypeGui.java index f14d108c3..41301c10f 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/CustomKit/ChooseQueueTypeGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/CustomKit/ChooseQueueTypeGui.java @@ -85,17 +85,17 @@ public void update() { ItemStack hostItem = GUIFile.getGuiItem(GUI_PATH + ".ICONS.QUEUE-OWN-KIT").get(); if (hostItem == null) { - hostItem = ItemCreateUtil.createItem("&aQueue Your Own Kit", Material.WRITABLE_BOOK); + hostItem = ItemCreateUtil.createItem("Queue Your Own Kit", Material.WRITABLE_BOOK); } ItemStack joinOthersItem = GUIFile.getGuiItem(GUI_PATH + ".ICONS.QUEUE-OTHERS-KITS").get(); if (joinOthersItem == null) { - joinOthersItem = ItemCreateUtil.createItem("&eQueue Others Kits", Material.BOOK); + joinOthersItem = ItemCreateUtil.createItem("Queue Others Kits", Material.BOOK); } ItemStack backItem = GUIFile.getGuiItem(GUI_PATH + ".ICONS.BACK").get(); if (backItem == null) { - backItem = ItemCreateUtil.createItem("&cBack", Material.ARROW); + backItem = ItemCreateUtil.createItem("Back", Material.ARROW); } if (hostOwnSlot() >= 0 && hostOwnSlot() < inventory.getSize()) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/CustomKit/CustomKitHostSelectorGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/CustomKit/CustomKitHostSelectorGui.java index 205d67d4d..3ae1dd2d2 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/CustomKit/CustomKitHostSelectorGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/CustomKit/CustomKitHostSelectorGui.java @@ -88,7 +88,7 @@ public void update() { ItemStack backItem = GUIFile.getGuiItem(GUI_PATH + ".ICONS.BACK").get(); if (backItem == null) { - backItem = ItemCreateUtil.createItem("&cBack", Material.ARROW); + backItem = ItemCreateUtil.createItem("Back", Material.ARROW); } if (backSlot() >= 0 && backSlot() < inventory.getSize()) { inventory.setItem(backSlot(), backItem); @@ -98,7 +98,7 @@ public void update() { if (hostableKits.isEmpty()) { ItemStack noKitsItem = GUIFile.getGuiItem(GUI_PATH + ".ICONS.NO-KITS").get(); if (noKitsItem == null) { - noKitsItem = ItemCreateUtil.createItem("&cNo Saved Custom Kits", Material.BARRIER); + noKitsItem = ItemCreateUtil.createItem("No Saved Custom Kits", Material.BARRIER); } if (noKitsSlot() >= 0 && noKitsSlot() < inventory.getSize()) { @@ -114,12 +114,12 @@ public void update() { ItemStack icon = customLadder.getIcon(); if (icon == null || icon.getType() == Material.AIR) { - icon = ItemCreateUtil.createItem("&e" + customLadder.getDisplayName(), Material.WRITABLE_BOOK); + icon = ItemCreateUtil.createItem("" + customLadder.getDisplayName(), Material.WRITABLE_BOOK); } else { icon = icon.clone(); ItemMeta itemMeta = icon.getItemMeta(); if (itemMeta != null) { - itemMeta.displayName(Common.legacyToComponent("&e" + customLadder.getDisplayName())); + itemMeta.displayName(Common.legacyToComponent("" + customLadder.getDisplayName())); icon.setItemMeta(itemMeta); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/QueueGuiUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/QueueGuiUtil.java index 24ee8647e..3a81defe7 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/QueueGuiUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/QueueGuiUtil.java @@ -35,7 +35,7 @@ static String getLbString(String format, String s, Ladder ladder) { Matcher matcher = pattern.matcher(s); if (!matcher.matches()) { - return "&cInvalid format!"; + return "Invalid format!"; } String lbType = matcher.group(1); @@ -47,35 +47,35 @@ static String getLbString(String format, String s, Ladder ladder) { lbSecondaryType = LbSecondaryType.valueOf(lbType.toUpperCase()); placement = Integer.parseInt(number); } catch (Exception e) { - return "&cInvalid format!"; + return "Invalid format!"; } Leaderboard leaderboard = LeaderboardManager.getInstance().searchLB(LbMainType.LADDER, lbSecondaryType, ladder); if (leaderboard == null) { - return "&cNo leaderboard found!"; + return "No leaderboard found!"; } List players = new ArrayList<>(leaderboard.getList().keySet()); if (players.size() < placement) { - return "&cNo player found!"; + return "No player found!"; } OfflinePlayer player = players.get(placement - 1); Profile profile = ProfileManager.getInstance().getProfile(player); - Division division = null; - if (profile != null) { - division = profile.getStats().getDivision(); + if (profile == null || player.getName() == null) { + return "No player found!"; } - + + Division division = profile.getStats().getDivision(); int score = leaderboard.getList().get(player); return format .replace("%placement%", String.valueOf(placement)) .replace("%player%", player.getName()) .replace("%score%", String.valueOf(score)) - .replace("%division%", division != null ? division.getFullName() : "&cN/A") - .replace("%division_short%", division != null ? division.getShortName() : "&cN/A"); + .replace("%division%", division != null ? division.getFullName() : "N/A") + .replace("%division_short%", division != null ? division.getShortName() : "N/A"); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/QueueSelectorGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/QueueSelectorGui.java index 105910a28..0e4431eb9 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/QueueSelectorGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/QueueSelectorGui.java @@ -459,7 +459,7 @@ private Material getCategorySelectorMaterial(CategoryConfig category, boolean se private String getCategoryLadderPreview(CategoryConfig category) { if (category.ladderNames().isEmpty()) { - return "&7No ladders"; + return "No ladders"; } List preview = new ArrayList<>(); @@ -470,7 +470,7 @@ private String getCategoryLadderPreview(CategoryConfig category) { preview.add(ladder != null ? ladder.getDisplayName() : ladderName); } - return String.join("&7, &f", preview); + return String.join(", ", preview); } private GUIItem getLadderIcon(NormalLadder ladder, GUIItem template, String guiPath) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/RankedGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/RankedGui.java index d2f3b007a..9bee437b5 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/RankedGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/RankedGui.java @@ -79,7 +79,7 @@ protected void decoratePage(int pageId, Inventory inventory) { ItemStack customQueueItem = GUIFile.getGuiItem(CUSTOM_QUEUE_ITEM_PATH).get(); if (customQueueItem == null) { - customQueueItem = ItemCreateUtil.createItem("&6Custom Kit Queue", Material.BOOK); + customQueueItem = ItemCreateUtil.createItem("Custom Kit Queue", Material.BOOK); } inventory.setItem(slot, customQueueItem); @@ -131,7 +131,7 @@ private void placeSwitchItem(Inventory inventory) { ItemStack switchItem = GUIFile.getGuiItem(SWITCH_TO_UNRANKED_ITEM_PATH).get(); if (switchItem == null) { - switchItem = ItemCreateUtil.createItem("&aSwitch to Unranked", Material.WOODEN_SWORD); + switchItem = ItemCreateUtil.createItem("Switch to Unranked", Material.WOODEN_SWORD); } inventory.setItem(switchSlot, switchItem); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/UnrankedGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/UnrankedGui.java index 7733a36f9..b4eca4b31 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/UnrankedGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/queue/UnrankedGui.java @@ -78,7 +78,7 @@ protected void decoratePage(int pageId, Inventory inventory) { ItemStack customQueueItem = GUIFile.getGuiItem(CUSTOM_QUEUE_ITEM_PATH).get(); if (customQueueItem == null) { - customQueueItem = ItemCreateUtil.createItem("&6Custom Kit Queue", Material.BOOK); + customQueueItem = ItemCreateUtil.createItem("Custom Kit Queue", Material.BOOK); } inventory.setItem(slot, customQueueItem); @@ -129,7 +129,7 @@ private void placeSwitchItem(Inventory inventory) { ItemStack switchItem = GUIFile.getGuiItem(SWITCH_TO_RANKED_ITEM_PATH).get(); if (switchItem == null) { - switchItem = ItemCreateUtil.createItem("&cSwitch to Ranked", Material.IRON_SWORD); + switchItem = ItemCreateUtil.createItem("Switch to Ranked", Material.IRON_SWORD); } inventory.setItem(switchSlot, switchItem); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/selectors/LadderSelectorGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/selectors/LadderSelectorGui.java index d95089c65..226080254 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/selectors/LadderSelectorGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/guis/selectors/LadderSelectorGui.java @@ -85,6 +85,9 @@ public void update() { ItemStack icon = ItemCreateUtil.createItem(ladder.getIcon(), GUIFile.getString("GUIS.SELECTORS.LADDER-SELECTOR.ICONS.LADDER.NAME").replace("%ladder%", ladder.getDisplayName()), lore); int slot = inventory.firstEmpty(); + if (slot == -1) { + break; + } gui.get(1).setItem(slot, icon); ladderSlots.put(slot, ladder); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/ArenaSetupUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/ArenaSetupUtil.java index 810e772fe..296dbf55d 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/ArenaSetupUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/ArenaSetupUtil.java @@ -102,8 +102,8 @@ public static ItemStack getLocationItem(Arena arena) { .replace("%portal1%", Common.mmToNormal(ArenaUtil.convertLocation(arena.getPortalLoc1()))) .replace("%portal2%", Common.mmToNormal(ArenaUtil.convertLocation(arena.getPortalLoc2()))) .replace("%sideBuildLimit%", String.valueOf(arena.getSideBuildLimit())) - .replace("%buildMaxY%", arena.isBuildMax() ? String.valueOf(arena.getBuildMaxValue()) : "&cNot Set") - .replace("%deathZoneY%", arena.isDeadZone() ? String.valueOf(arena.getDeadZoneValue()) : "&cNot Set"); + .replace("%buildMaxY%", arena.isBuildMax() ? String.valueOf(arena.getBuildMaxValue()) : "Not Set") + .replace("%deathZoneY%", arena.isDeadZone() ? String.valueOf(arena.getDeadZoneValue()) : "Not Set"); } else { guiItem = GUIFile.getGuiItem("GUIS.SETUP.ARENA.ARENA-MAIN.ICONS.LOCATION.NOT-BUILD") .replace("%arenaName%", arena.getName()) @@ -112,7 +112,7 @@ public static ItemStack getLocationItem(Arena arena) { .replace("%corner2%", Common.mmToNormal(ArenaUtil.convertLocation(arena.getCorner2()))) .replace("%position1%", Common.mmToNormal(ArenaUtil.convertLocation(arena.getPosition1()))) .replace("%position2%", Common.mmToNormal(ArenaUtil.convertLocation(arena.getPosition2()))) - .replace("%deathZoneY%", arena.isDeadZone() ? String.valueOf(arena.getDeadZoneValue()) : "&cNot Set"); + .replace("%deathZoneY%", arena.isDeadZone() ? String.valueOf(arena.getDeadZoneValue()) : "Not Set"); } return guiItem.get(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/ArenaSummaryGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/ArenaSummaryGui.java index 67524578a..f03390bda 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/ArenaSummaryGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/ArenaSummaryGui.java @@ -31,7 +31,7 @@ public class ArenaSummaryGui extends GUI { private static final String STATUS_ENABLED = GUIFile.getString("GUIS.SETUP.ARENA.ARENA-MANAGER.ICONS.ARENA-ICON.STATUS-NAMES.ENABLED"); private static final String STATUS_DISABLED = GUIFile.getString("GUIS.SETUP.ARENA.ARENA-MANAGER.ICONS.ARENA-ICON.STATUS-NAMES.DISABLED"); - private final int spaces = 27; + private final int spaces = 36; private final Map> slots = new HashMap<>(); // private final Map icons = new HashMap<>(); private final Map backToPage = new HashMap<>(); @@ -62,18 +62,18 @@ public void build() { // Re-use existing inventory object if present, otherwise create a fresh one Inventory inv = gui.containsKey(page) ? gui.get(page) - : InventoryUtil.createInventory(GUIFile.getString("GUIS.SETUP.ARENA.ARENA-MANAGER.TITLE").replace("%page%", String.valueOf(page)), 5); + : InventoryUtil.createInventory(GUIFile.getString("GUIS.SETUP.ARENA.ARENA-MANAGER.TITLE").replace("%page%", String.valueOf(page)), 6); newGui.put(page, inv); inv.clear(); // Frame - for (int i : new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44}) + for (int i : new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 45, 46, 47, 48, 49, 50, 51, 52, 53}) inv.setItem(i, GUIManager.getFILLER_ITEM()); // Arena icons Map pageSlots = new HashMap<>(); - for (Map.Entry entry : getPageItems(displayIcons, page).entrySet()) { + for (Map.Entry entry : getPageItems(displayIcons, page, spaces).entrySet()) { int slot = inv.firstEmpty(); if (slot != -1 && slot < inv.getSize()) { inv.setItem(slot, entry.getValue()); @@ -88,7 +88,7 @@ public void build() { left = GUIFile.getGuiItem("GUIS.SETUP.ARENA.ARENA-MANAGER.ICONS.PAGE-LEFT").replace("%page%", String.valueOf(page - 1)).get(); else left = GUIFile.getGuiItem("GUIS.SETUP.ARENA.ARENA-MANAGER.ICONS.BACK-TO").get(); - inv.setItem(36, left); + inv.setItem(45, left); // Right navigation ItemStack right; @@ -96,7 +96,7 @@ public void build() { right = GUIFile.getGuiItem("GUIS.SETUP.ARENA.ARENA-MANAGER.ICONS.PAGE-RIGHT").replace("%page%", String.valueOf(page + 1)).get(); else right = GUIManager.getFILLER_ITEM(); - inv.setItem(44, right); + inv.setItem(53, right); } } @@ -145,8 +145,8 @@ public void handleClickEvent(InventoryClickEvent e) { if (inventory.getSize() > slot && e.getCurrentItem() != null) { int page = inGuiPlayers.get(player); - if (slot == 36 || slot == 44) { - if (slot == 36) { + if (slot == 45 || slot == 53) { + if (slot == 45) { if (page == 1) { GUIManager.getInstance().searchGUI(GUIType.Setup_Hub).open(player); } else { @@ -216,11 +216,11 @@ private static ItemStack getArenaItem(Arena arena) { return guiItem.get(); } - private static Map getPageItems(Map items, int page) { + private static Map getPageItems(Map items, int page, int spaces) { Map sortedItems = sortByValue(items); - int upperBound = page * 27; - int lowerBound = upperBound - 27; + int upperBound = page * spaces; + int lowerBound = upperBound - spaces; // IMPORTANT: Use LinkedHashMap to preserve the sorted order! Map newItems = new LinkedHashMap<>(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/ffa/ArenaMainGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/ffa/ArenaMainGui.java index 69c6a976c..932f081f6 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/ffa/ArenaMainGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/ffa/ArenaMainGui.java @@ -111,7 +111,7 @@ public void handleClickEvent(InventoryClickEvent e) { player.performCommand("arena info " + ffaArena.getName()); } else if (clickType.isRightClick()) { if (!ArenaSetupManager.getInstance().startSetup(player, ffaArena)) { - player.sendMessage(Common.colorize("&cYou can't edit an enabled arena.")); + Common.sendMMMessage(player, "You can't edit an enabled arena."); } } break; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/ffa/LadderSingleGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/ffa/LadderSingleGui.java index 44c2709f9..eaff5c04b 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/ffa/LadderSingleGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/ffa/LadderSingleGui.java @@ -70,6 +70,9 @@ public void update() { } int slot = gui.get(1).firstEmpty(); + if (slot == -1) { + break; + } gui.get(1).setItem(slot, ladderItem); ladderSlots.put(slot, ladder.getName()); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/ArenaMainGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/ArenaMainGui.java index 1bfd1d7d9..dc3980400 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/ArenaMainGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/ArenaMainGui.java @@ -94,7 +94,7 @@ public void handleClickEvent(InventoryClickEvent e) { player.performCommand("arena info " + arena.getName()); } else if (clickType.isRightClick()) { if (!ArenaSetupManager.getInstance().startSetup(player, arena)) { - player.sendMessage(Common.colorize("&cYou can't edit an enabled arena.")); + Common.sendMMMessage(player, "You can't edit an enabled arena."); } } break; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/LadderSingleGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/LadderSingleGui.java index 3a3e2a672..467510f5f 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/LadderSingleGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/LadderSingleGui.java @@ -20,7 +20,6 @@ import org.bukkit.inventory.ItemStack; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Set; @@ -74,6 +73,9 @@ public void update() { ladderItem = ArenaSetupUtil.getNonCompatibleLadderItem(ladder); int slot = gui.get(1).firstEmpty(); + if (slot == -1) { + break; + } gui.get(1).setItem(slot, ladderItem); ladderSlots.put(slot, ladder.getName()); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/LadderTypeGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/LadderTypeGui.java index 9760a48f5..0607093cc 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/LadderTypeGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/arena/arenasettings/normal/LadderTypeGui.java @@ -89,7 +89,7 @@ public void update() { int slot = inventory.firstEmpty(); inventory.setItem(slot, GUIFile.getGuiItem("GUIS.SETUP.ARENA.ARENA-LADDERS-TYPE.ICONS.CUSTOM-KIT-ICONS.ICON") - .replace("%status%", arena.isAllowCustomKitOnMap() ? "&aEnabled" : "&cDisabled") + .replace("%status%", arena.isAllowCustomKitOnMap() ? "Enabled" : "Disabled") .get()); customKitSlot = slot; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/event/EventSetupUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/event/EventSetupUtil.java index 2c2d5b686..c301e6763 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/event/EventSetupUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/event/EventSetupUtil.java @@ -24,7 +24,7 @@ public static ItemStack getDurationItem(EventData eventData) { case TNTTAG -> GUIFile.getGuiItem("GUIS.SETUP.EVENT.EVENT-SETTINGS.ICONS.DURATION.TNTTAG").replace("%explodeTime%", String.valueOf(eventData.getDuration())).get(); case BRACKETS, SUMO -> - GUIFile.getGuiItem("GUIS.SETUP.EVENT.EVENT-SETTINGS.ICONS.DURATION.SUMO&BRACKETS").replace("%roundDuration%", String.valueOf(eventData.getDuration() / 60)).get(); + GUIFile.getGuiItem("GUIS.SETUP.EVENT.EVENT-SETTINGS.ICONS.DURATION.SUMO.RACKETS").replace("%roundDuration%", String.valueOf(eventData.getDuration() / 60)).get(); default -> GUIFile.getGuiItem("GUIS.SETUP.EVENT.EVENT-SETTINGS.ICONS.DURATION.OTHER").replace("%duration%", String.valueOf(eventData.getDuration() / 60)).get(); }; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/event/eventsettings/EventMainGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/event/eventsettings/EventMainGui.java index 1115950d1..320ba9716 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/event/eventsettings/EventMainGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/event/eventsettings/EventMainGui.java @@ -64,8 +64,8 @@ public void update() { inventory.setItem(16, GUIFile.getGuiItem("GUIS.SETUP.EVENT.EVENT-MAIN.ICONS.LOCATION") .replace("%eventName%", eventData.getType().getName()) - .replace("%corner1%", Common.mmToNormal(ArenaUtil.convertLocation(eventData.getCuboidLoc1()))) - .replace("%corner2%", Common.mmToNormal(ArenaUtil.convertLocation(eventData.getCuboidLoc2()))) + .replace("%corner1%", ArenaUtil.convertLocation(eventData.getCuboidLoc1())) + .replace("%corner2%", ArenaUtil.convertLocation(eventData.getCuboidLoc2())) .replace("%spawnPositions%", String.valueOf(eventData.getSpawns().size())) .get()); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/hologram/HologramMainGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/hologram/HologramMainGui.java index 3f87ef740..7f7dc415e 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/hologram/HologramMainGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/hologram/HologramMainGui.java @@ -144,7 +144,7 @@ else if (click.isRightClick() && currentShowStat < 15) private static ItemStack getTypeItem(Hologram hologram) { List typeExtension = new ArrayList<>(); for (LbSecondaryType hologramType : HologramManager.getInstance().getLbSecondaryTypes()) { - typeExtension.add((hologramType.equals(hologram.getLeaderboardType()) ? "&a" : "&c") + " &l► &e" + StringUtil.getNormalizedName(hologramType.name())); + typeExtension.add((hologramType.equals(hologram.getLeaderboardType()) ? "" : "") + " " + StringUtil.getNormalizedName(hologramType.name())); } GUIItem guiItem = GUIFile.getGuiItem("GUIS.SETUP.HOLOGRAM.HOLOGRAM-MAIN.ICONS.EVENT-TYPE"); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/hologram/LadderGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/hologram/LadderGui.java index 2ce41825c..7d8bfe342 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/hologram/LadderGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/hologram/LadderGui.java @@ -80,6 +80,9 @@ public void update() { if (ladderItem != null) { int slot = gui.get(1).firstEmpty(); + if (slot == -1) { + break; + } gui.get(1).setItem(slot, ladderItem); ladderSlots.put(slot, ladder.getName()); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/LadderSummaryGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/LadderSummaryGui.java index ac94af503..c4e79948d 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/LadderSummaryGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/LadderSummaryGui.java @@ -9,57 +9,104 @@ import dev.nandi0813.practice.manager.ladder.abstraction.Ladder; import dev.nandi0813.practice.manager.ladder.abstraction.normal.NormalLadder; import dev.nandi0813.practice.util.InventoryUtil; +import dev.nandi0813.practice.util.PageUtil; import lombok.Getter; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import java.util.HashMap; -import java.util.Map; +import java.util.*; @Getter public class LadderSummaryGui extends GUI { - private final Map ladderSlots = new HashMap<>(); + private final int spaces = 45; + private final Map> ladderSlots = new HashMap<>(); + private final Map backToPage = new HashMap<>(); public LadderSummaryGui() { super(GUIType.Ladder_Summary); - this.gui.put(1, InventoryUtil.createInventory(GUIFile.getString("GUIS.SETUP.LADDER.LADDER-MANAGER.TITLE"), 6)); - build(); } @Override public void build() { - // Frame - for (int i : new int[]{46, 47, 48, 49, 50, 51, 52, 53}) - gui.get(1).setItem(i, GUIManager.getFILLER_ITEM()); - - // Back to Manager Icon - gui.get(1).setItem(45, GUIFile.getGuiItem("GUIS.SETUP.LADDER.LADDER-MANAGER.ICONS.BACK-TO").get()); - update(); } @Override public void update() { - Inventory inventory = gui.get(1); + List ladders = new ArrayList<>(LadderManager.getInstance().getLadders()); + ladders.sort(java.util.Comparator.comparing(Ladder::getName, String::compareToIgnoreCase)); + + Map existingInventories = new HashMap<>(gui); + Map newGui = new HashMap<>(); + Map> newLadderSlots = new HashMap<>(); + + for (int page = 1; PageUtil.isPageValid(ladders.size(), page, spaces) || page == 1; page++) { + Inventory inventory = existingInventories.get(page); + String title = GUIFile.getString("GUIS.SETUP.LADDER.LADDER-MANAGER.TITLE").replace("%page%", String.valueOf(page)); + if (inventory == null || inventory.getSize() != 6 * 9) { + inventory = InventoryUtil.createInventory(title, 6); + } else { + inventory.clear(); + } + newGui.put(page, inventory); - ladderSlots.clear(); - for (int i = 0; i < 45; i++) - inventory.setItem(i, null); + for (int i = 45; i < 54; i++) { + inventory.setItem(i, GUIManager.getFILLER_ITEM()); + } + for (int i = 0; i < 45; i++) { + inventory.setItem(i, null); + } - // Sort ladders alphanumerically by internal name for consistent ordering - LadderManager.getInstance().getLadders() - .stream() - .sorted(java.util.Comparator.comparing(Ladder::getName, String::compareToIgnoreCase)) - .forEach(ladder -> { - int slot = inventory.firstEmpty(); + Map pageSlots = new HashMap<>(); + int startIndex = (page - 1) * spaces; + int endIndex = Math.min(startIndex + spaces, ladders.size()); + for (int i = startIndex; i < endIndex; i++) { + int slot = inventory.firstEmpty(); + if (slot == -1 || slot >= 45) { + break; + } + + NormalLadder ladder = ladders.get(i); + inventory.setItem(slot, getLadderItem(ladder)); + pageSlots.put(slot, ladder); + } + newLadderSlots.put(page, pageSlots); + + ItemStack left = page == 1 + ? GUIFile.getGuiItem("GUIS.SETUP.LADDER.LADDER-MANAGER.ICONS.BACK-TO").get() + : GUIFile.getGuiItem("GUIS.SETUP.LADDER.LADDER-MANAGER.ICONS.PAGE-LEFT") + .replace("%page%", String.valueOf(page - 1)) + .get(); + inventory.setItem(45, left); + + ItemStack right = PageUtil.isPageValid(ladders.size(), page + 1, spaces) + ? GUIFile.getGuiItem("GUIS.SETUP.LADDER.LADDER-MANAGER.ICONS.PAGE-RIGHT") + .replace("%page%", String.valueOf(page + 1)) + .get() + : GUIManager.getFILLER_ITEM(); + inventory.setItem(53, right); + } - inventory.setItem(slot, getLadderItem(ladder)); - ladderSlots.put(slot, ladder); - }); + for (Map.Entry entry : new LinkedHashMap<>(gui).entrySet()) { + if (newGui.containsKey(entry.getKey())) { + continue; + } + + gui.remove(entry.getKey()); + for (Player player : inGuiPlayers.keySet()) { + if (inGuiPlayers.get(player) == entry.getKey()) { + open(player, entry.getKey() - 1); + } + } + } + + gui.putAll(newGui); + ladderSlots.clear(); + ladderSlots.putAll(newLadderSlots); updatePlayers(); } @@ -78,15 +125,25 @@ public void handleClickEvent(InventoryClickEvent e) { if (currentItem == null) return; if (currentItem.equals(GUIManager.getFILLER_ITEM())) return; + int page = inGuiPlayers.getOrDefault(player, 1); if (slot == 45) { - GUIManager.getInstance().searchGUI(GUIType.Setup_Hub).open(player); - } else if (ladderSlots.containsKey(slot)) { - Ladder ladder = ladderSlots.get(slot); + if (page == 1) { + GUIManager.getInstance().searchGUI(GUIType.Setup_Hub).open(player); + } else { + open(player, page - 1); + } + } else if (slot == 53) { + if (gui.containsKey(page + 1)) { + open(player, page + 1); + } + } else if (ladderSlots.containsKey(page) && ladderSlots.get(page).containsKey(slot)) { + Ladder ladder = ladderSlots.get(page).get(slot); if (ladder == null) { this.update(); return; } + backToPage.put(player, page); LadderSetupManager.getInstance().getLadderSetupGUIs().get(ladder).get(GUIType.Ladder_Main).open(player); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/LadderMainGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/LadderMainGui.java index 0cc9787e5..61072eebb 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/LadderMainGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/LadderMainGui.java @@ -8,6 +8,7 @@ import dev.nandi0813.practice.manager.gui.GUIType; import dev.nandi0813.practice.manager.gui.confirmgui.ConfirmGuiType; import dev.nandi0813.practice.manager.gui.setup.ladder.LadderSetupManager; +import dev.nandi0813.practice.manager.gui.setup.ladder.LadderSummaryGui; import dev.nandi0813.practice.manager.ladder.abstraction.Ladder; import dev.nandi0813.practice.manager.ladder.abstraction.normal.NormalLadder; import dev.nandi0813.practice.manager.ladder.util.LadderUtil; @@ -85,7 +86,13 @@ public void handleClickEvent(InventoryClickEvent e) { switch (slot) { case 27: - GUIManager.getInstance().searchGUI(GUIType.Ladder_Summary).open(player); + GUI summaryGui = GUIManager.getInstance().searchGUI(GUIType.Ladder_Summary); + if (summaryGui instanceof LadderSummaryGui ladderSummaryGui) { + ladderSummaryGui.open(player, ladderSummaryGui.getBackToPage().getOrDefault(player, 1)); + ladderSummaryGui.getBackToPage().remove(player); + } else { + summaryGui.open(player); + } break; case 11: if (ladder.isEnabled()) { @@ -155,7 +162,13 @@ public void handleConfirm(Player player, ConfirmGuiType confirmGuiType) { break; case LADDER_DELETE: player.performCommand("ladder delete " + ladder.getName()); - GUIManager.getInstance().searchGUI(GUIType.Ladder_Summary).open(player); + GUI summaryGui = GUIManager.getInstance().searchGUI(GUIType.Ladder_Summary); + if (summaryGui instanceof LadderSummaryGui ladderSummaryGui) { + ladderSummaryGui.open(player, ladderSummaryGui.getBackToPage().getOrDefault(player, 1)); + ladderSummaryGui.getBackToPage().remove(player); + } else { + summaryGui.open(player); + } break; } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/HeartsItem.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/HeartsItem.java new file mode 100644 index 000000000..f358e4d51 --- /dev/null +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/HeartsItem.java @@ -0,0 +1,33 @@ +package dev.nandi0813.practice.manager.gui.setup.ladder.laddersettings.Settings.Items; + +import dev.nandi0813.practice.manager.backend.GUIFile; +import dev.nandi0813.practice.manager.gui.setup.ladder.laddersettings.Settings.SettingItem; +import dev.nandi0813.practice.manager.gui.setup.ladder.laddersettings.Settings.SettingType; +import dev.nandi0813.practice.manager.gui.setup.ladder.laddersettings.Settings.SettingsGui; +import dev.nandi0813.practice.manager.ladder.abstraction.normal.NormalLadder; +import org.bukkit.event.inventory.InventoryClickEvent; + +public class HeartsItem extends SettingItem { + + public HeartsItem(SettingsGui settingsGui, NormalLadder ladder) { + super(settingsGui, SettingType.HEARTS, ladder); + } + + @Override + public void updateItemStack() { + guiItem = GUIFile.getGuiItem("GUIS.SETUP.LADDER.SETTINGS.ICONS.HEARTS") + .replace("%hearts%", String.valueOf(ladder.getHearts())); + } + + @Override + public void clickEvent(InventoryClickEvent e) { + int hearts = ladder.getHearts(); + + if (e.getClick().isLeftClick() && hearts > 1) + ladder.setHearts(hearts - 1); + else if (e.getClick().isRightClick() && hearts < 20) + ladder.setHearts(hearts + 1); + + settingsGui.build(); + } +} diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/KnockbackItem.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/KnockbackItem.java index 24a99caf4..728778a78 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/KnockbackItem.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/KnockbackItem.java @@ -28,8 +28,8 @@ public void updateItemStack() { for (KnockbackType kt : KnockbackType.values()) { String ktName = StringUtils.capitalize(kt.name().toLowerCase()); - if (ladder.getLadderKnockback().getKnockbackType().equals(kt)) extension.add(" &a» " + ktName); - else extension.add(" &7» " + ktName); + if (ladder.getLadderKnockback().getKnockbackType().equals(kt)) extension.add(" » " + ktName); + else extension.add(" » " + ktName); } GUIItem guiItem = GUIFile.getGuiItem("GUIS.SETUP.LADDER.SETTINGS.ICONS.KNOCKBACK"); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/RankedItem.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/RankedItem.java index df8b614f1..7e3ff1546 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/RankedItem.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/Items/RankedItem.java @@ -29,8 +29,8 @@ public void updateItemStack() { for (WeightClassType weightClassType : WeightClassType.values()) { String ktName = StringUtils.capitalize(weightClassType.getName()); - if (ladder.getWeightClass().equals(weightClassType)) extension.add(" &a» " + ktName); - else extension.add(" &7» " + ktName); + if (ladder.getWeightClass().equals(weightClassType)) extension.add(" » " + ktName); + else extension.add(" » " + ktName); } GUIItem guiItem = GUIFile.getGuiItem("GUIS.SETUP.LADDER.SETTINGS.ICONS.WEIGHT-CLASS"); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/SettingType.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/SettingType.java index 35fc3f3c3..46be9911c 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/SettingType.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/SettingType.java @@ -15,6 +15,7 @@ public enum SettingType { DROP_INVENTORY, WEIGHT_CLASS, ROUNDS, + HEARTS, RESPAWN_TIME, BOXING_HITS, FIREBALL_COOLDOWN, diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/SettingsGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/SettingsGui.java index 7b3a95bec..1e6ebda5d 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/SettingsGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/ladder/laddersettings/Settings/SettingsGui.java @@ -46,8 +46,10 @@ public SettingsGui(@NotNull NormalLadder ladder) { guiSlot = GuiSlot.SIZE_1; else if (ladderType.getSettingTypes().size() <= 14) guiSlot = GuiSlot.SIZE_2; - else + else if (ladderType.getSettingTypes().size() <= 22) guiSlot = GuiSlot.SIZE_3; + else + guiSlot = GuiSlot.SIZE_4; gui.put(1, InventoryUtil.createInventory(GUIFile.getString("GUIS.SETUP.LADDER.SETTINGS.TITLE").replace("%ladder%", ladder.getName()), (guiSlot.getRows() + 1))); @@ -67,6 +69,10 @@ public void build() { // Set the setting items int currentItemSlot = 0; for (SettingItem settingItem : settingItems) { + if (currentItemSlot >= guiSlot.getSlots().size()) { + Common.sendConsoleMMMessage("[Ladder Settings GUI] Too many settings for layout: " + ladder.getName()); + break; + } int slot = guiSlot.getSlots().get(currentItemSlot); currentItemSlot++; settingItem.setSlot(slot); @@ -127,7 +133,8 @@ public void handleClickEvent(@NotNull InventoryClickEvent e) { public enum GuiSlot { SIZE_1(2, new ArrayList<>(Arrays.asList(10, 11, 12, 13, 14, 15, 16))), SIZE_2(3, new ArrayList<>(Arrays.asList(10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25))), - SIZE_3(4, new ArrayList<>(Arrays.asList(10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 35, 36))); + SIZE_3(4, new ArrayList<>(Arrays.asList(10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 35))), + SIZE_4(5, new ArrayList<>(Arrays.asList(10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 42, 43))); private final int rows; private final int backSlot; @@ -182,6 +189,9 @@ private void addItems() { if (settingTypes.contains(SettingType.ROUNDS)) settingItems.add(new RoundsItem(this, ladder)); + if (settingTypes.contains(SettingType.HEARTS)) + settingItems.add(new HeartsItem(this, ladder)); + if (settingTypes.contains(SettingType.RESPAWN_TIME)) settingItems.add(new TempRespawnTimeItem(this, ladder)); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/server/ServerHubGui.java b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/server/ServerHubGui.java index 0c742a2d1..0013b9363 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/server/ServerHubGui.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/gui/setup/server/ServerHubGui.java @@ -125,7 +125,7 @@ private ItemStack getInformationItem() { return GUIFile.getGuiItem("GUIS.SETUP.SERVER.SERVER-MANAGER.ICONS.INFORMATIONS") .replace("%onlinePlayers%", String.valueOf(Bukkit.getOnlinePlayers().size())) .replace("%onlineStaffs%", String.valueOf(PlayerUtil.getOnlineStaff().size())) - .replace("%requiredDivision%", DivisionManager.getInstance().getMinimumForRanked() != null ? DivisionManager.getInstance().getMinimumForRanked().getFullName() : "&cN/A") + .replace("%requiredDivision%", DivisionManager.getInstance().getMinimumForRanked() != null ? DivisionManager.getInstance().getMinimumForRanked().getFullName() : "N/A") .replace("%lobbyStatus%", ServerManager.getLobby() != null ? GUIFile.getString("GUIS.SETUP.SERVER.SERVER-MANAGER.ICONS.INFORMATIONS.STATUS-NAMES.SET") : GUIFile.getString("GUIS.SETUP.SERVER.SERVER-MANAGER.ICONS.INFORMATIONS.STATUS-NAMES.UNSET")) .replace("%enabledArena%", String.valueOf( ArenaManager.getInstance().getEnabledArenas().size() + diff --git a/core/src/main/java/dev/nandi0813/practice/manager/inventory/InventoryListener.java b/core/src/main/java/dev/nandi0813/practice/manager/inventory/InventoryListener.java index 254debb03..6f12ebf57 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/inventory/InventoryListener.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/inventory/InventoryListener.java @@ -97,7 +97,7 @@ public void onPlayerInteractWithInvItem(PlayerInteractEvent e) { InvItem invItem; String itemDisplayName = Common.getItemDisplayName(item); - if (ServerManager.getInstance().getInWorld().get(player).equals(WorldEnum.LOBBY) && !player.hasPermission("zpp.admin")) { + if (isInLobbyWorld(player) && !player.hasPermission("zpp.admin")) { invItem = inventory.getHoldItem(itemDisplayName, item.getType(), e.getPlayer().getInventory().getHeldItemSlot()); } else { int slot = -1; @@ -118,26 +118,31 @@ public void onPlayerInteractWithInvItem(PlayerInteractEvent e) { @EventHandler public void onLobbyInteractProtection(PlayerInteractEvent e) { Player player = e.getPlayer(); - if (!isInLobbyWorld(player) || player.hasPermission("zpp.admin")) { - return; - } + Profile profile = ProfileManager.getInstance().getProfile(player); + ProfileStatus profileStatus = profile.getStatus(); - Block clickedBlock = e.getClickedBlock(); - if (clickedBlock == null) { - return; - } + if (isLobbyStatus(profileStatus)) { + if (!isLobbyProtectionAllowed("allow-lobby-interact") + && !player.hasPermission("zpp.admin")) { - Action action = e.getAction(); - Material type = clickedBlock.getType(); + Block clickedBlock = e.getClickedBlock(); + if (clickedBlock == null) return; - if (action == Action.PHYSICAL && Tag.PRESSURE_PLATES.isTagged(type)) { - e.setCancelled(true); - return; - } + Action action = e.getAction(); + Material type = clickedBlock.getType(); - if ((action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) - && (Tag.TRAPDOORS.isTagged(type) || isProtectedWorkstation(type))) { - e.setCancelled(true); + if (action == Action.PHYSICAL && Tag.PRESSURE_PLATES.isTagged(type)) { + e.setCancelled(true); + return; + } + + if ((action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) + && (Tag.TRAPDOORS.isTagged(type) || isProtectedWorkstation(type))) { + e.setCancelled(true); + } + } + + return; } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/inventory/InventoryUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/inventory/InventoryUtil.java index 2302db1f0..b7b852ce2 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/inventory/InventoryUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/inventory/InventoryUtil.java @@ -36,9 +36,7 @@ public static void setLobbyNametag(Player player, Profile profile) { // Tab-list Component listName = prefix.append(name).append(suffix); TabIntegration tabIntegration = TeamPacketBlocker.getInstance().getTabIntegration(); - if (tabIntegration != null && tabIntegration.isAvailable()) { - tabIntegration.setTabListName(player, listName); - } else { + if (tabIntegration == null || !tabIntegration.setTabListName(player, prefix, name, suffix)) { PlayerUtil.setPlayerListName(player, listName); } @@ -101,4 +99,4 @@ public LobbyNametag(Component prefix, Component name, NamedTextColor scoreboardN public Component getSuffix() { return suffix; } public int getSortPriority() { return sortPriority; } } -} \ No newline at end of file +} diff --git a/core/src/main/java/dev/nandi0813/practice/manager/inventory/inventoryitem/ExtraInvItem.java b/core/src/main/java/dev/nandi0813/practice/manager/inventory/inventoryitem/ExtraInvItem.java index f749f5230..cb843ca4b 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/inventory/inventoryitem/ExtraInvItem.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/inventory/inventoryitem/ExtraInvItem.java @@ -1,7 +1,6 @@ package dev.nandi0813.practice.manager.inventory.inventoryitem; import dev.nandi0813.practice.manager.inventory.InventoryManager; -import dev.nandi0813.practice.manager.server.ServerManager; import org.bukkit.entity.Player; public class ExtraInvItem extends InvItem { @@ -26,7 +25,7 @@ public void handleClickEvent(Player player) { command = command.substring(1); } - ServerManager.runConsoleCommand(command.replace("%player%", player.getName())); + player.performCommand(command.replace("%player%", player.getName())); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/inventory/service/InventoryCosmeticService.java b/core/src/main/java/dev/nandi0813/practice/manager/inventory/service/InventoryCosmeticService.java index b7437c857..be5c61df6 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/inventory/service/InventoryCosmeticService.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/inventory/service/InventoryCosmeticService.java @@ -166,7 +166,7 @@ private ItemStack createLobbyElytra() { ItemStack elytra = new ItemStack(Material.ELYTRA); ItemMeta meta = elytra.getItemMeta(); if (meta != null) { - meta.displayName(Common.legacyToComponent("&bLobby Elytra")); + meta.displayName(Common.legacyToComponent("Lobby Elytra")); meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE, ItemFlag.HIDE_ENCHANTS); meta.setUnbreakable(true); tagAsLobbyCosmetic(meta, CosmeticsData.LobbyItemType.NONE); @@ -191,9 +191,9 @@ private ItemStack createLobbyMovementItem(CosmeticsData.LobbyItemType type) { ItemMeta meta = itemStack.getItemMeta(); if (meta != null) { String displayName = switch (type) { - case WIND_CHARGE -> "&bWind Charge"; - case TRIDENT -> "&3Riptide Trident"; - case SPEAR -> "&5Lunge Spear"; + case WIND_CHARGE -> "Wind Charge"; + case TRIDENT -> "Riptide Trident"; + case SPEAR -> "Lunge Spear"; default -> throw new IllegalStateException("Unexpected value: " + type); }; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/abstraction/Ladder.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/abstraction/Ladder.java index c6d0ed2c8..26c252719 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/abstraction/Ladder.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/abstraction/Ladder.java @@ -7,7 +7,6 @@ import dev.nandi0813.practice.manager.ladder.util.LadderKnockback; import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.KitData; -import dev.nandi0813.practice.util.StringUtil; import lombok.Getter; import lombok.Setter; import org.bukkit.Material; @@ -42,6 +41,7 @@ public abstract class Ladder { protected double attackCooldownModifier = 1.0; @Setter protected int rounds = 1; + protected int hearts = 10; // Cooldowns @Setter @@ -104,6 +104,7 @@ protected Ladder(Ladder ladder) { this.build = ladder.isBuild(); this.attackCooldownModifier = ladder.getAttackCooldownModifier(); this.rounds = ladder.getRounds(); + this.hearts = ladder.getHearts(); this.enderPearlCooldown = ladder.getEnderPearlCooldown(); this.goldenAppleCooldown = ladder.getGoldenAppleCooldown(); this.fireworkRocketCooldown = ladder.getFireworkRocketCooldown(); @@ -125,6 +126,10 @@ protected Ladder(Ladder ladder) { public abstract List getArenas(); + public void setHearts(int hearts) { + this.hearts = Math.clamp(hearts, 1, 20); + } + public List getAvailableArenas() { List arenas = new ArrayList<>(); for (Arena arena : getArenas()) @@ -140,11 +145,12 @@ public void setIcon(final ItemStack icon) { this.icon = icon.clone(); - String iconDisplayName = Common.getItemDisplayName(icon); - if (!iconDisplayName.isBlank()) - this.displayName = StringUtil.CC(iconDisplayName); - else + String iconDisplayName = Common.getItemDisplayNameMiniMessage(icon); + if (!iconDisplayName.isBlank()) { + this.displayName = iconDisplayName; + } else { this.displayName = name; + } } public ItemStack getIcon() { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/abstraction/normal/LadderFile.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/abstraction/normal/LadderFile.java index b94503e13..77912b253 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/abstraction/normal/LadderFile.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/abstraction/normal/LadderFile.java @@ -41,6 +41,7 @@ public void setData() { config.set("settings.multiRoundStartCountdown", ladder.isMultiRoundStartCountdown()); config.set("settings.hitdelay", ladder.getAttackCooldownModifier()); config.set("settings.rounds", ladder.getRounds()); + config.set("settings.hearts", ladder.getHearts()); config.set("settings.maxduration", ladder.getMaxDuration()); config.set("settings.epcooldown", ladder.getEnderPearlCooldown()); config.set("settings.gacooldown", ladder.getGoldenAppleCooldown()); @@ -195,6 +196,12 @@ public void getData() { } else ladder.setRounds(1); + if (config.isInt("settings.hearts")) { + ladder.setHearts(config.getInt("settings.hearts")); + } else { + ladder.setHearts(10); + } + if (config.isInt("settings.maxduration")) { ladder.setMaxDuration(config.getInt("settings.maxduration")); } else diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/KnockbackType.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/KnockbackType.java index dddd50b0c..aa4b8cdf2 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/KnockbackType.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/KnockbackType.java @@ -10,21 +10,33 @@ public enum KnockbackType { 0, 0, 0, - 0 + 0, + -1, + -1, + -1, + -1 ), NORMAL ( ConfigManager.getDouble("KNOCKBACK.NORMAL.AIR-HORIZONTAL"), ConfigManager.getDouble("KNOCKBACK.NORMAL.AIR-VERTICAL"), ConfigManager.getDouble("KNOCKBACK.NORMAL.HORIZONTAL"), - ConfigManager.getDouble("KNOCKBACK.NORMAL.VERTICAL") + ConfigManager.getDouble("KNOCKBACK.NORMAL.VERTICAL"), + readMax("KNOCKBACK.NORMAL.MAX-AIR-HORIZONTAL", -1.0D), + readMax("KNOCKBACK.NORMAL.MAX-AIR-VERTICAL", -1.0D), + readMax("KNOCKBACK.NORMAL.MAX-HORIZONTAL", -1.0D), + readMax("KNOCKBACK.NORMAL.MAX-VERTICAL", -1.0D) ), COMBO ( ConfigManager.getDouble("KNOCKBACK.COMBO.AIR-HORIZONTAL"), ConfigManager.getDouble("KNOCKBACK.COMBO.AIR-VERTICAL"), ConfigManager.getDouble("KNOCKBACK.COMBO.HORIZONTAL"), - ConfigManager.getDouble("KNOCKBACK.COMBO.VERTICAL") + ConfigManager.getDouble("KNOCKBACK.COMBO.VERTICAL"), + readMax("KNOCKBACK.COMBO.MAX-AIR-HORIZONTAL", 1.35D), + readMax("KNOCKBACK.COMBO.MAX-AIR-VERTICAL", 0.62D), + readMax("KNOCKBACK.COMBO.MAX-HORIZONTAL", 1.15D), + readMax("KNOCKBACK.COMBO.MAX-VERTICAL", 0.52D) ); @Getter @@ -35,12 +47,30 @@ public enum KnockbackType { private final double horizontal; @Getter private final double vertical; + @Getter + private final double maxAirhorizontal; + @Getter + private final double maxAirvertical; + @Getter + private final double maxHorizontal; + @Getter + private final double maxVertical; - KnockbackType(double airhorizontal, double airvertical, double horizontal, double vertical) { + KnockbackType(double airhorizontal, double airvertical, double horizontal, double vertical, + double maxAirhorizontal, double maxAirvertical, double maxHorizontal, double maxVertical) { this.airhorizontal = airhorizontal; this.airvertical = airvertical; this.horizontal = horizontal; this.vertical = vertical; + this.maxAirhorizontal = maxAirhorizontal; + this.maxAirvertical = maxAirvertical; + this.maxHorizontal = maxHorizontal; + this.maxVertical = maxVertical; + } + + private static double readMax(String path, double defaultValue) { + double configured = ConfigManager.getConfig().getDouble(path, defaultValue); + return configured > 0.0D ? configured : -1.0D; } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/LadderType.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/LadderType.java index 84bf8e7ab..98081e632 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/LadderType.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/LadderType.java @@ -89,6 +89,7 @@ public enum LadderType { .withBuild() .withMovementSettings() .withCommonSettings() + .withPearlSettings() .withSettings( SettingType.GOLDEN_APPLE_COOLDOWN, SettingType.TEMP_BUILD_RETURN_DELAY, @@ -113,6 +114,7 @@ public enum LadderType { SettingType.KNOCKBACK, SettingType.WEIGHT_CLASS, SettingType.ROUNDS, + SettingType.HEARTS, SettingType.MAX_DURATION, SettingType.START_COUNTDOWN, SettingType.SPLEEF_SNOWBALL_MODE, diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/LadderTypeConfig.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/LadderTypeConfig.java index a33ce251b..794c7b2a4 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/LadderTypeConfig.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/enums/LadderTypeConfig.java @@ -115,6 +115,7 @@ public LadderTypeConfig withCommonSettings() { SettingType.KNOCKBACK, SettingType.WEIGHT_CLASS, SettingType.ROUNDS, + SettingType.HEARTS, SettingType.MAX_DURATION, SettingType.START_COUNTDOWN, SettingType.DROP_INVENTORY, diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/BattleRush.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/BattleRush.java index 18baf7398..488052732 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/BattleRush.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/BattleRush.java @@ -76,7 +76,7 @@ private static void onPlayerDamage(final @NotNull EntityDamageEvent e, final @No if (match.getCurrentRound().getRoundStatus().equals(RoundStatus.LIVE)) { e.setDamage(0); - player.setHealth(20); + dev.nandi0813.practice.util.playerutil.PlayerUtil.healToMaxHealth(player); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/Boxing.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/Boxing.java index d1824e2ec..c2fb35f47 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/Boxing.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/Boxing.java @@ -133,7 +133,7 @@ private static void onPlayerDamage(final @NotNull EntityDamageEvent e, final @No if (match.getCurrentRound().getRoundStatus().equals(RoundStatus.LIVE)) { e.setDamage(0); - player.setHealth(20); + dev.nandi0813.practice.util.playerutil.PlayerUtil.healToMaxHealth(player); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/PearlFight.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/PearlFight.java index 9b306794c..434e7666b 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/PearlFight.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/PearlFight.java @@ -53,7 +53,7 @@ private static void onPlayerDamage(final @NotNull EntityDamageEvent e, final @No if (match.getCurrentRound().getRoundStatus().equals(RoundStatus.LIVE)) { e.setDamage(0); - player.setHealth(20); + dev.nandi0813.practice.util.playerutil.PlayerUtil.healToMaxHealth(player); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/Sumo.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/Sumo.java index cbb7ff5b1..83b4c7b4f 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/Sumo.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/Sumo.java @@ -67,7 +67,7 @@ private static void onPlayerDamage(final @NotNull EntityDamageEvent e, final @No // For all other damage types, nullify damage and keep player at full health e.setDamage(0); - player.setHealth(20); + dev.nandi0813.practice.util.playerutil.PlayerUtil.healToMaxHealth(player); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/TntSumo.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/TntSumo.java index 59100dc9e..6412ce5eb 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/TntSumo.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/type/TntSumo.java @@ -352,7 +352,7 @@ private static void onPlayerDamage(@NotNull EntityDamageEvent e, @NotNull Match } e.setDamage(0); - player.setHealth(20); + dev.nandi0813.practice.util.playerutil.PlayerUtil.healToMaxHealth(player); } private static void onPlayerMove(@NotNull PlayerMoveEvent e, @NotNull Match match) { @@ -706,4 +706,3 @@ private AirborneStackState(int hits, long lastHitMillis) { } } - diff --git a/core/src/main/java/dev/nandi0813/practice/manager/ladder/util/LadderUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/ladder/util/LadderUtil.java index 34c95f9bb..f95367139 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/ladder/util/LadderUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/ladder/util/LadderUtil.java @@ -4,6 +4,7 @@ import dev.nandi0813.practice.manager.arena.ArenaManager; import dev.nandi0813.practice.manager.arena.arenas.Arena; import dev.nandi0813.practice.manager.arena.arenas.FFAArena; +import dev.nandi0813.practice.manager.backend.ConfigManager; import dev.nandi0813.practice.manager.backend.LanguageManager; import dev.nandi0813.practice.manager.backend.MysqlManager; import dev.nandi0813.practice.manager.fight.match.Match; @@ -95,14 +96,16 @@ public static void disableLadder(NormalLadder ladder) { GUIManager.getInstance().searchGUI(GUIType.Queue_Ranked).update(true); GUIManager.getInstance().searchGUI(GUIType.CustomLadder_Selector).update(); - Bukkit.getScheduler().runTaskAsynchronously(ZonePractice.getInstance(), () -> - { - for (Profile profile : ProfileManager.getInstance().getProfiles().values()) { - profile.getFile().deleteCustomKit(ladder); - profile.getUnrankedCustomKits().remove(ladder); - profile.getRankedCustomKits().remove(ladder); - } - }); + if (!ConfigManager.getBoolean("SETUP.PRESERVE-CUSTOM-KITS-ON-LADDER-DISABLE")) { + Bukkit.getScheduler().runTaskAsynchronously(ZonePractice.getInstance(), () -> + { + for (Profile profile : ProfileManager.getInstance().getProfiles().values()) { + profile.getFile().deleteCustomKit(ladder); + profile.getUnrankedCustomKits().remove(ladder); + profile.getRankedCustomKits().remove(ladder); + } + }); + } /* * Delete the ladder statistics from the mysql table. diff --git a/core/src/main/java/dev/nandi0813/practice/manager/leaderboard/hologram/Hologram.java b/core/src/main/java/dev/nandi0813/practice/manager/leaderboard/hologram/Hologram.java index eb13e9b51..aecf478fa 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/leaderboard/hologram/Hologram.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/leaderboard/hologram/Hologram.java @@ -67,7 +67,6 @@ public abstract class Hologram { private final AtomicBoolean isUpdating = new AtomicBoolean(false); private HologramState currentState = HologramState.UNINITIALIZED; - // ==================== CONSTRUCTORS ==================== protected Hologram(String name, Location baseLocation, HologramType hologramType) { this.name = name; @@ -90,14 +89,14 @@ protected Hologram(String name, HologramType hologramType) { } } - // ==================== ABSTRACT METHODS ==================== + // ABSTRACT METHODS public abstract void getAbstractData(YamlConfiguration config); public abstract void setAbstractData(YamlConfiguration config); public abstract boolean isReadyToEnable(); public abstract Leaderboard getNextLeaderboard(); - // ==================== DATA PERSISTENCE ==================== + // DATA PERSISTENCE public void getData() { enabled = config.getBoolean("holograms." + name + ".enabled", false); @@ -135,7 +134,16 @@ public void setData() { BackendManager.save(); } - // ==================== CORE MANAGEMENT ==================== + /** + * Moves the hologram to a new player-facing location. + * + *

The internal base location is stored two blocks below the visible hologram. + */ + public void moveTo(@NotNull Location location) { + this.baseLocation = location.clone().subtract(0, 2, 0); + } + + // CORE MANAGEMENT /** * Despawns all hologram lines and clears state. @@ -228,7 +236,7 @@ else if (textLines.size() < lines.size()) { } } - // ==================== UPDATE LOGIC ==================== + // UPDATE LOGIC /** * Main update method - handles leaderboard changes and content updates. @@ -283,7 +291,7 @@ private void handleEmptyLeaderboard() { } } - // ==================== TEXT BUILDING ==================== + // TEXT BUILDING private List buildTextLines(@NotNull Leaderboard leaderboard) { List configLines = getConfigLines(leaderboard); @@ -338,6 +346,7 @@ private List buildSpacings(int lineCount, Leaderboard leaderboard) { private List buildPlacementStrings(Leaderboard leaderboard) { Map playerStats = leaderboard.getList(); List topPlayers = playerStats.keySet().stream() + .filter(p -> p.getName() != null && ProfileManager.getInstance().getProfile(p) != null) .limit(showStat) .collect(Collectors.toList()); @@ -376,7 +385,7 @@ private String formatPlayerEntry(OfflinePlayer player, Map")) { - return ZonePractice.getMiniMessage().deserialize(text); - } - return LegacyComponentSerializer.legacySection().deserialize(text.replace('&', LegacyComponentSerializer.SECTION_CHAR)); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(text)); } /** diff --git a/core/src/main/java/dev/nandi0813/practice/manager/nametag/NametagManager.java b/core/src/main/java/dev/nandi0813/practice/manager/nametag/NametagManager.java index f409e0cfc..1ba068eff 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/nametag/NametagManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/nametag/NametagManager.java @@ -31,6 +31,7 @@ public class NametagManager { private static final boolean LOW_HEALTH_RATIO = dev.nandi0813.practice.manager.backend.ConfigManager.getBoolean("MATCH-SETTINGS.HEALTH-BELOW-NAME.DECIMAL-HEART-INDICATOR.LOW-HEALTH-DECIMAL-RATIO"); private static final double LOW_HEALTH_THRESHOLD = dev.nandi0813.practice.manager.backend.ConfigManager.getDouble("MATCH-SETTINGS.HEALTH-BELOW-NAME.LOW-HEALTH-THRESHOLD") * 2.0; private static final double CONFIG_SCALE = dev.nandi0813.practice.manager.backend.ConfigManager.getDouble("MATCH-SETTINGS.HEALTH-BELOW-NAME.SCALE"); + private static final String HEALTH_SYMBOL = dev.nandi0813.practice.manager.backend.ConfigManager.getString("MATCH-SETTINGS.HEALTH-BELOW-NAME.SYMBOL"); private static final String BELOW_NAME_OBJECTIVE = "ZPP_BELOW"; @@ -58,6 +59,11 @@ public static NametagManager getInstance() { private BukkitTask belowNameRefreshTask; public void initialize() { + if (!PermanentConfig.NAMETAG_MANAGEMENT_ENABLED) { + startBelowNameRefreshTask(); + return; + } + TeamPacketBlocker.getInstance().register(); for (Player online : Bukkit.getOnlinePlayers()) { @@ -80,6 +86,13 @@ public void initialize() { } public void shutdown() { + if (!PermanentConfig.NAMETAG_MANAGEMENT_ENABLED) { + stopBelowNameRefreshTask(); + belowNameUsers.clear(); + belowNameLines.clear(); + return; + } + for (Player player : Bukkit.getOnlinePlayers()) { onPlayerQuit(player); } @@ -473,11 +486,11 @@ private Component formatHealth(Player player, double health) { if (DECIMAL_ALWAYS_SHOW || (LOW_HEALTH_RATIO && health < LOW_HEALTH_THRESHOLD)) { return Component.text(String.format(java.util.Locale.US, "%.1f", displayHealth), NamedTextColor.WHITE) - .append(Component.text("♥", heartColor)); + .append(Component.text(HEALTH_SYMBOL, heartColor)); } - return Component.text((int) Math.ceil(displayHealth) + " ", NamedTextColor.WHITE) - .append(Component.text("♥", heartColor)); + return Component.text((int) Math.ceil(displayHealth), NamedTextColor.WHITE) + .append(Component.text(HEALTH_SYMBOL, heartColor)); } private boolean isSaturated(Player player) { @@ -597,19 +610,11 @@ private void stopBelowNameRefreshTask() { } } - private void reapplyHideTeamLater(Player player) { - if (player == null) { + private void hideVanillaNametag(Player player) { + if (!PermanentConfig.NAMETAG_MANAGEMENT_ENABLED) { return; } - Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> { - if (player.isOnline()) { - hideVanillaNametag(player); - } - }, 1L); - } - - private void hideVanillaNametag(Player player) { if (player == null) { return; } @@ -626,4 +631,4 @@ private void hideVanillaNametag(Player player) { private record NametagOverride(Component prefix, NamedTextColor nameColor, Component suffix) { } -} \ No newline at end of file +} diff --git a/core/src/main/java/dev/nandi0813/practice/manager/nametag/TabIntegration.java b/core/src/main/java/dev/nandi0813/practice/manager/nametag/TabIntegration.java index 5a595cb3c..830dfb52f 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/nametag/TabIntegration.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/nametag/TabIntegration.java @@ -1,454 +1,149 @@ package dev.nandi0813.practice.manager.nametag; -import dev.nandi0813.practice.manager.fight.util.PlayerUtil; import dev.nandi0813.practice.manager.inventory.InventoryUtil; -import dev.nandi0813.practice.util.PermanentConfig; import lombok.Getter; import me.neznamy.tab.api.TabAPI; import me.neznamy.tab.api.TabPlayer; import me.neznamy.tab.api.event.EventBus; import me.neznamy.tab.api.event.player.PlayerLoadEvent; +import me.neznamy.tab.api.event.plugin.TabLoadEvent; import me.neznamy.tab.api.nametag.NameTagManager; import me.neznamy.tab.api.tablist.TabListFormatManager; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -/** - * Integration with TAB API for nametag and tablist management. - *

- * ARCHITECTURE PRINCIPLE: - * This class EXCLUSIVELY uses TAB's API when TAB is available. - * It does NOT contain any internal nametag logic - that belongs in NametagManager. - *

- * Key principles: - *

    - *
  • If TAB API is available: ALL nametag/tablist operations go through TAB API ONLY
  • - *
  • If TAB API is not available: This class does nothing (NametagManager handles it internally)
  • - *
  • NO mixing of TAB API and internal logic within this class
  • - *
  • NO fallback to internal methods if TAB API calls fail - fail silently
  • - *
- *

- * Usage Pattern: - *

- * NametagManager (orchestrator)
- *   ├─ Detects if TAB is available
- *   ├─ If TAB available: delegates to TabIntegration → uses TAB API exclusively
- *   └─ If TAB not available: uses internal packet-based system
- * 
- */ public class TabIntegration { + private static final LegacyComponentSerializer LEGACY = LegacyComponentSerializer.legacySection(); + private final TabAPI tabAPI; + private NameTagManager nameTagManager; + private TabListFormatManager tabListFormatManager; + @Getter private final boolean available; - @Getter - private final boolean tablistFormattingEnabled; public TabIntegration() { TabAPI api = null; - boolean isAvailable; - boolean tablistEnabled = false; + NameTagManager nametags = null; + TabListFormatManager tabList = null; try { api = TabAPI.getInstance(); - isAvailable = api != null; - - // Check if TAB's tablist-name-formatting feature is enabled using their API - if (isAvailable) { - tablistEnabled = checkTablistFormattingEnabled(api); + if (api != null) { + nametags = api.getNameTagManager(); + tabList = api.getTabListFormatManager(); } - } catch (NoClassDefFoundError | Exception e) { - // TAB API not available - isAvailable = false; + } catch (NoClassDefFoundError | Exception ignored) { } this.tabAPI = api; - this.available = isAvailable; - this.tablistFormattingEnabled = tablistEnabled; + this.nameTagManager = nametags; + this.tabListFormatManager = tabList; + this.available = api != null; - if (this.available) { - registerVanillaNameHider(); - hideNametagsForOnlinePlayers(); + if (available) { + registerPlayerLoadHandler(); + Bukkit.getOnlinePlayers().forEach(this::syncPlayer); } } - private void registerVanillaNameHider() { - try { - EventBus eventBus = tabAPI.getEventBus(); - if (eventBus == null) { - return; - } + public void hideNametag(Player player) { + if (player == null) { + return; + } - eventBus.register(PlayerLoadEvent.class, event -> { - hideNametag(event.getPlayer()); + hideNametag(getTabPlayer(player)); + } - // hideNameTag() wipes any prefix/suffix TAB has for this player. - // Re-apply the lobby nametag immediately so it isn't lost on first join. - try { - Object playerObj = event.getPlayer().getPlayer(); - if (!(playerObj instanceof Player player) || !player.isOnline()) return; - dev.nandi0813.practice.manager.profile.Profile profile = - dev.nandi0813.practice.manager.profile.ProfileManager.getInstance().getProfile(player); - if (profile == null) return; - dev.nandi0813.practice.manager.inventory.InventoryUtil.setLobbyNametag(player, profile); - } catch (Exception ignored) { - } - }); + public void hideNametag(TabPlayer tabPlayer) { + if (nameTagManager == null || tabPlayer == null) { + return; + } + + try { + nameTagManager.hideNameTag(tabPlayer); } catch (Exception ignored) { } } - private void hideNametagsForOnlinePlayers() { - for (Player player : Bukkit.getOnlinePlayers()) { - hideNametag(player); + public boolean setTabListName(Player player, Component prefix, Component name, Component suffix) { + if (tabListFormatManager == null) { + return false; + } + + TabPlayer tabPlayer = getTabPlayer(player); + if (tabPlayer == null) { + return false; } - } - /** - * Checks if TAB's tablist-name-formatting feature is enabled using TAB's Developer API. - * Returns true if TabListFormatManager is available and functional. - */ - private boolean checkTablistFormattingEnabled(TabAPI api) { try { - // Use TAB API to check if TabListFormatManager is available - // If getTabListFormatManager() returns null, the feature is disabled - TabListFormatManager manager = api.getTabListFormatManager(); - return manager != null; - } catch (Exception e) { - // If there's an exception, the feature is not available + tabListFormatManager.setPrefix(tabPlayer, toLegacy(prefix)); + tabListFormatManager.setName(tabPlayer, toLegacy(name)); + tabListFormatManager.setSuffix(tabPlayer, toLegacy(suffix)); + return true; + } catch (Exception ignored) { return false; } } - /** - * Sets a player's nametag using ONLY TAB API. - * This method sets the nametag (above head) through TAB's NameTagManager. - * If tablist formatting is enabled in TAB, it also preserves the lobby tablist name. - * - * @param player The player - * @param prefix The prefix component - * @param nameColor The name color to apply to the player's actual name - * @param suffix The suffix component - * @param sortPriority The sort priority (currently unused in TAB integration) - */ - public void setNametag(Player player, Component prefix, NamedTextColor nameColor, Component suffix, int sortPriority) { - if (!available) return; - + private void registerPlayerLoadHandler() { try { - TabPlayer tabPlayer = tabAPI.getPlayer(player.getUniqueId()); - if (tabPlayer == null) return; - - // Get TAB's NameTagManager for nametag (above head) management - NameTagManager nameTagManager = tabAPI.getNameTagManager(); - if (nameTagManager == null) return; - - // Convert Components to legacy strings for TAB API - String prefixStr = componentToLegacy(prefix); - String suffixStr = componentToLegacy(suffix); - - // Apply name color to the prefix - // In TAB, the "team color" (name color) is set via the prefix's last color code - String colorCode = getColorCode(nameColor); - boolean originalPrefixEmpty = prefixStr.isEmpty(); - - // Handle prefix with color code - if (!originalPrefixEmpty) { - // Has actual prefix text - append color code if not already present - boolean endsWithColor = prefixStr.matches(".*§[0-9a-fA-Fk-oK-OrR]$"); - if (!endsWithColor) { - prefixStr = prefixStr + colorCode; - } - nameTagManager.setPrefix(tabPlayer, prefixStr); - } else { - // No prefix text, but we have a color - set color as prefix - nameTagManager.setPrefix(tabPlayer, colorCode); + EventBus eventBus = tabAPI.getEventBus(); + if (eventBus == null) { + return; } - // Set the suffix - nameTagManager.setSuffix(tabPlayer, suffixStr); - - // Preserve the lobby tablist name to prevent match nametag colors from affecting it. - // Only do this when our NAMETAG-MANAGEMENT toggle is enabled. - if (PermanentConfig.NAMETAG_MANAGEMENT_ENABLED) { - if (tablistFormattingEnabled) { - setLobbyTabListName(player); - } else { - preserveTabListNameInternal(player); + eventBus.register(PlayerLoadEvent.class, event -> { + Object playerObj = event.getPlayer().getPlayer(); + if (playerObj instanceof Player player && player.isOnline()) { + syncPlayer(player); } - } - - } catch (Exception e) { - // Silently fail - TAB integration is best-effort - } - } - - public void hideNametag(Player player) { - if (!available || player == null) return; - - try { - TabPlayer tabPlayer = tabAPI.getPlayer(player.getUniqueId()); - if (tabPlayer == null) return; + }); - hideNametag(tabPlayer); + eventBus.register(TabLoadEvent.class, event -> { + refreshManagers(); + // TAB rebuilds its managers on reload, so re-apply our per-player overrides immediately after. + Bukkit.getOnlinePlayers().forEach(this::syncPlayer); + }); } catch (Exception ignored) { } } - public void hideNametag(TabPlayer tabPlayer) { - if (!available || tabPlayer == null) return; - + private void refreshManagers() { try { - NameTagManager nameTagManager = tabAPI.getNameTagManager(); - if (nameTagManager == null) return; - - nameTagManager.hideNameTag(tabPlayer); + nameTagManager = tabAPI.getNameTagManager(); + tabListFormatManager = tabAPI.getTabListFormatManager(); } catch (Exception ignored) { } } - /** - * Sets the player's tablist name to their lobby formatting using ONLY TAB API. - * This method uses TabListFormatManager to set prefix, name, and suffix. - * Only called when tablistFormattingEnabled is true. - * - * @param player The player whose tablist name should be set to lobby formatting - */ - private void setLobbyTabListName(Player player) { - if (!available || !tablistFormattingEnabled || !PermanentConfig.NAMETAG_MANAGEMENT_ENABLED) return; - - try { - TabPlayer tabPlayer = tabAPI.getPlayer(player.getUniqueId()); - if (tabPlayer == null) return; - - TabListFormatManager tabListFormatManager = tabAPI.getTabListFormatManager(); - if (tabListFormatManager == null) return; - - dev.nandi0813.practice.manager.profile.Profile profile = - dev.nandi0813.practice.manager.profile.ProfileManager.getInstance().getProfile(player); - if (profile == null) return; - - InventoryUtil.LobbyNametag lobbyNametag = InventoryUtil.getLobbyNametag(profile, player.getName(), player); + private void syncPlayer(Player player) { + hideNametag(player); - // Convert components to legacy strings for TAB API - String prefixStr = componentToLegacy(lobbyNametag.getPrefix()); - String suffixStr = componentToLegacy(lobbyNametag.getSuffix()); - String nameStr = componentToLegacy(lobbyNametag.getName()); - - // Use TAB's TabListFormatManager to set the tab list formatting - tabListFormatManager.setPrefix(tabPlayer, prefixStr); - tabListFormatManager.setName(tabPlayer, nameStr); - tabListFormatManager.setSuffix(tabPlayer, suffixStr); - - } catch (Exception e) { - // Silently fail - this is best-effort + dev.nandi0813.practice.manager.profile.Profile profile = + dev.nandi0813.practice.manager.profile.ProfileManager.getInstance().getProfile(player); + if (profile != null) { + // This reuses the normal lobby formatting path so TAB and vanilla fallback stay consistent. + InventoryUtil.setLobbyNametag(player, profile); } } - /** - * Sets a player's tablist name using ONLY TAB API. - * This is used for lobby nametag formatting where we want to show the full formatted name in tablist. - * Only works if TAB's tablist-name-formatting feature is enabled. - * - * @param player The player - * @param listName The full formatted component to display in tablist (prefix + colored name + suffix) - */ - public void setTabListName(Player player, Component listName) { - if (!available || !tablistFormattingEnabled || !PermanentConfig.NAMETAG_MANAGEMENT_ENABLED) return; - - try { - TabPlayer tabPlayer = tabAPI.getPlayer(player.getUniqueId()); - if (tabPlayer == null) return; - - TabListFormatManager tabListFormatManager = tabAPI.getTabListFormatManager(); - if (tabListFormatManager == null) return; - - // Convert Component to legacy string for TAB API - String fullListName = componentToLegacy(listName); - String playerName = player.getName(); - - // Parse the formatted name into prefix, name, and suffix - // The listName contains: prefix + playerName + suffix - int nameIndex = fullListName.indexOf(playerName); - - if (nameIndex >= 0) { - // Found the player name in the formatted string - // Extract prefix (everything before the name, may include color codes) - String prefix = fullListName.substring(0, nameIndex); - - // Extract the name portion with its color code - String nameWithColor = playerName; - int lastColorBeforeName = prefix.lastIndexOf('§'); - if (lastColorBeforeName >= 0 && lastColorBeforeName + 1 < prefix.length()) { - // Extract the color code and apply it to the name - String colorCode = prefix.substring(lastColorBeforeName); - nameWithColor = colorCode + playerName; - // Remove the trailing color code from prefix (it's now part of the name) - prefix = prefix.substring(0, lastColorBeforeName); - } - - // Extract suffix (everything after the name) - String suffix = fullListName.substring(nameIndex + playerName.length()); - - // Set the components through TAB API - tabListFormatManager.setPrefix(tabPlayer, prefix); - tabListFormatManager.setName(tabPlayer, nameWithColor); - tabListFormatManager.setSuffix(tabPlayer, suffix); - } else { - // Fallback: couldn't parse, set the whole thing as name - tabListFormatManager.setPrefix(tabPlayer, ""); - tabListFormatManager.setName(tabPlayer, fullListName); - tabListFormatManager.setSuffix(tabPlayer, ""); - } - - } catch (Exception e) { - // Silently fail - TAB integration is best-effort + private TabPlayer getTabPlayer(Player player) { + if (!available || player == null) { + return null; } - } - - /** - * Resets a player's nametag to TAB's default using ONLY TAB API. - * This resets the nametag (above head) prefix and suffix to TAB's configured values. - * NOTE: This does NOT reset tablist formatting - tablist remains as configured by TAB. - * - * @param player The player - */ - public void resetNametag(Player player) { - if (!available) return; try { - TabPlayer tabPlayer = tabAPI.getPlayer(player.getUniqueId()); - if (tabPlayer == null) return; - - // Get TAB's NameTagManager to reset nametag values - NameTagManager nameTagManager = tabAPI.getNameTagManager(); - if (nameTagManager != null) { - // Reset nametag prefix and suffix to default (null values reset to TAB's config) - nameTagManager.setPrefix(tabPlayer, null); - nameTagManager.setSuffix(tabPlayer, null); - } - - // Also reset tablist formatting to TAB's defaults so stale values don't persist - if (tablistFormattingEnabled) { - TabListFormatManager tabListFormatManager = tabAPI.getTabListFormatManager(); - if (tabListFormatManager != null) { - tabListFormatManager.setPrefix(tabPlayer, null); - tabListFormatManager.setName(tabPlayer, null); - tabListFormatManager.setSuffix(tabPlayer, null); - } - } - - } catch (Exception e) { - // Silently fail - TAB integration is best-effort + return tabAPI.getPlayer(player.getUniqueId()); + } catch (Exception ignored) { + return null; } } - /** - * Converts an Adventure Component to a legacy color-coded string. - */ - private String componentToLegacy(Component component) { - if (component == null) return ""; - return LegacyComponentSerializer.legacySection().serialize(component); - } - - /** - * Converts a NamedTextColor to a legacy color code (§x format). - * This is needed for TAB API's setPlayerNameColor method. - * - * @param color The NamedTextColor to convert - * @return Legacy color code string (e.g., "§a" for green) - */ - private String getColorCode(NamedTextColor color) { - if (color == null) return "§7"; // Default to gray - - // Map NamedTextColor to legacy color codes - if (color == NamedTextColor.BLACK) return "§0"; - if (color == NamedTextColor.DARK_BLUE) return "§1"; - if (color == NamedTextColor.DARK_GREEN) return "§2"; - if (color == NamedTextColor.DARK_AQUA) return "§3"; - if (color == NamedTextColor.DARK_RED) return "§4"; - if (color == NamedTextColor.DARK_PURPLE) return "§5"; - if (color == NamedTextColor.GOLD) return "§6"; - if (color == NamedTextColor.GRAY) return "§7"; - if (color == NamedTextColor.DARK_GRAY) return "§8"; - if (color == NamedTextColor.BLUE) return "§9"; - if (color == NamedTextColor.GREEN) return "§a"; - if (color == NamedTextColor.AQUA) return "§b"; - if (color == NamedTextColor.RED) return "§c"; - if (color == NamedTextColor.LIGHT_PURPLE) return "§d"; - if (color == NamedTextColor.YELLOW) return "§e"; - if (color == NamedTextColor.WHITE) return "§f"; - - return "§7"; // Default to gray if unknown - } - - /** - * Applies division placeholders to a component. - * - * @param component The component to process - * @param division The division to apply - * @return Component with division placeholders replaced - */ - private Component applyDivisionPlaceholder(Component component, dev.nandi0813.practice.manager.division.Division division) { - if (component == null || division == null) return component; - - return component - .replaceText(net.kyori.adventure.text.TextReplacementConfig.builder() - .match("%division%") - .replacement(division.getComponentFullName()) - .build()) - .replaceText(net.kyori.adventure.text.TextReplacementConfig.builder() - .match("%division_short%") - .replacement(division.getComponentShortName()) - .build()); - } - - /** - * Removes division placeholders from a component. - * - * @param component The component to process - * @return Component with division placeholders removed - */ - private Component removeDivisionPlaceholder(Component component) { - if (component == null) return component; - - return component - .replaceText(net.kyori.adventure.text.TextReplacementConfig.builder() - .match("%division%") - .replacement(Component.empty()) - .build()) - .replaceText(net.kyori.adventure.text.TextReplacementConfig.builder() - .match("%division_short%") - .replacement(Component.empty()) - .build()); - } - - /** - * Preserves the player's tablist name using internal Bukkit method. - * This is called when TAB's tablist-name-formatting is disabled. - * Prevents match nametag colors from bleeding into the tablist in 1.21+. - * - * @param player The player whose tablist name should be preserved - */ - private void preserveTabListNameInternal(Player player) { - try { - dev.nandi0813.practice.manager.profile.Profile profile = - dev.nandi0813.practice.manager.profile.ProfileManager.getInstance().getProfile(player); - if (profile == null) return; - - InventoryUtil.LobbyNametag lobbyNametag = InventoryUtil.getLobbyNametag(profile, player.getName(), player); - Component tabListName = lobbyNametag.getPrefix() - .append(lobbyNametag.getName()) - .append(lobbyNametag.getSuffix()); - - // Use internal Bukkit method to set the tablist name (not TAB API) - PlayerUtil.setPlayerListName(player, tabListName); - - } catch (Exception e) { - // Silently fail - this is best-effort - } + private String toLegacy(Component component) { + return component == null ? "" : LEGACY.serialize(component); } - - } +} diff --git a/core/src/main/java/dev/nandi0813/practice/manager/nametag/TeamPacketBlocker.java b/core/src/main/java/dev/nandi0813/practice/manager/nametag/TeamPacketBlocker.java index 59b8f9e7a..13b2d9d0c 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/nametag/TeamPacketBlocker.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/nametag/TeamPacketBlocker.java @@ -2,23 +2,13 @@ import lombok.Getter; import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; public class TeamPacketBlocker { private static TeamPacketBlocker instance; @Getter - private boolean tabPluginPresent = false; - - @Getter - private boolean tabScoreboardTeamsEnabled = false; - - @Getter - private boolean nametagSystemDisabled = false; - - @Getter - private TabIntegration tabIntegration = null; + private TabIntegration tabIntegration; private TeamPacketBlocker() { } @@ -31,41 +21,16 @@ public static TeamPacketBlocker getInstance() { } public void register() { - Plugin tabPlugin = Bukkit.getPluginManager().getPlugin("TAB"); - tabPluginPresent = tabPlugin != null && tabPlugin.isEnabled(); - - if (!tabPluginPresent) { - return; - } - - tabScoreboardTeamsEnabled = false; - nametagSystemDisabled = false; - - try { - tabIntegration = new TabIntegration(); - } catch (Throwable ignored) { - tabIntegration = null; + if (Bukkit.getPluginManager().isPluginEnabled("TAB")) { + try { + tabIntegration = new TabIntegration(); + } catch (Throwable ignored) { + tabIntegration = null; + } } } public void unregister() { tabIntegration = null; - tabPluginPresent = false; - tabScoreboardTeamsEnabled = false; - nametagSystemDisabled = false; - } - - @SuppressWarnings ( "unused" ) - public void registerOurTeam(String teamName) { - } - - @SuppressWarnings ( "unused" ) - public void unregisterOurTeam(String teamName) { - } - - @SuppressWarnings ( "unused" ) - public boolean isOurTeam(String teamName) { - return false; } - } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/PlayerKitManager.java b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/PlayerKitManager.java index 89267a671..bb2c94e9c 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/PlayerKitManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/PlayerKitManager.java @@ -89,7 +89,7 @@ private void loadDynamicCategories() { String itemsPath = "GUI.ITEMS.ITEMS-GUI.CATEGORIES." + id + ".ITEMS"; EditorIcon icon = getEditorItem(iconPath); - String title = config.getString(titlePath, "&8" + id); + String title = config.getString(titlePath, "" + id); List items = config.getStringList(itemsPath); CategoryGUI gui = new CategoryGUI(GUIType.PlayerCustom_DynamicCategory, title, items); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/CustomSettingGUI.java b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/CustomSettingGUI.java index 96d9462e7..0c1139373 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/CustomSettingGUI.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/CustomSettingGUI.java @@ -147,8 +147,8 @@ private static ItemStack getKnockbackItem(CustomLadder ladder) { for (KnockbackType kt : KnockbackType.values()) { String ktName = StringUtils.capitalize(kt.name().toLowerCase()); - if (ladder.getLadderKnockback().getKnockbackType().equals(kt)) extension.add(" &a» " + ktName); - else extension.add(" &7» " + ktName); + if (ladder.getLadderKnockback().getKnockbackType().equals(kt)) extension.add(" » " + ktName); + else extension.add(" » " + ktName); } for (String line : guiItem.getLore()) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/ShulkerBoxEditorGUI.java b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/ShulkerBoxEditorGUI.java index d9fa8e91f..eb26378be 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/ShulkerBoxEditorGUI.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/ShulkerBoxEditorGUI.java @@ -11,7 +11,6 @@ import dev.nandi0813.practice.util.Common; import org.bukkit.enchantments.Enchantment; import dev.nandi0813.practice.util.InventoryUtil; -import dev.nandi0813.practice.util.StringUtil; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.ShulkerBox; @@ -71,7 +70,7 @@ public ShulkerBoxEditorGUI(GUI returnGui, KitItem shulkerKitItem) { // Load existing contents from the shulker's BlockStateMeta loadContents(); - String title = StringUtil.CC("&8Shulker Box Contents"); + String title = "Shulker Box Contents"; this.gui.put(1, InventoryUtil.createInventory(title, ROWS)); build(); } @@ -143,9 +142,9 @@ public void update() { ItemStack clearItem = new ItemStack(Material.BARRIER); var clearMeta = clearItem.getItemMeta(); if (clearMeta != null) { - clearMeta.displayName(net.kyori.adventure.text.Component.text(StringUtil.CC("&cClear All Contents"))); + clearMeta.displayName(Common.deserializeMiniMessage("Clear All Contents")); java.util.List clearLore = new java.util.ArrayList<>(); - clearLore.add(net.kyori.adventure.text.Component.text(StringUtil.CC("&7Removes all items inside."))); + clearLore.add(Common.deserializeMiniMessage("Removes all items inside.")); clearMeta.lore(clearLore); clearItem.setItemMeta(clearMeta); } @@ -155,10 +154,10 @@ public void update() { ItemStack removeItem = new ItemStack(Material.SHULKER_BOX); var removeMeta = removeItem.getItemMeta(); if (removeMeta != null) { - removeMeta.displayName(net.kyori.adventure.text.Component.text(StringUtil.CC("&cRemove Shulker Box"))); + removeMeta.displayName(Common.deserializeMiniMessage("Remove Shulker Box")); java.util.List removeLore = new java.util.ArrayList<>(); - removeLore.add(net.kyori.adventure.text.Component.text(StringUtil.CC("&7Removes this shulker box"))); - removeLore.add(net.kyori.adventure.text.Component.text(StringUtil.CC("&7from the kit slot entirely."))); + removeLore.add(Common.deserializeMiniMessage("Removes this shulker box")); + removeLore.add(Common.deserializeMiniMessage("from the kit slot entirely.")); removeMeta.lore(removeLore); removeItem.setItemMeta(removeMeta); } @@ -297,21 +296,21 @@ private ItemStack buildFilledSlot(ItemStack item) { ? new java.util.ArrayList<>(meta.lore()) : new java.util.ArrayList<>(); - lore.add(net.kyori.adventure.text.Component.text(StringUtil.CC(""))); - lore.add(net.kyori.adventure.text.Component.text(StringUtil.CC("&eLeft-click &7to replace item"))); - lore.add(net.kyori.adventure.text.Component.text(StringUtil.CC("&eShift-click &7to remove"))); + lore.add(net.kyori.adventure.text.Component.empty()); + lore.add(Common.deserializeMiniMessage("Left-click to replace item")); + lore.add(Common.deserializeMiniMessage("Shift-click to remove")); boolean stackable = item.getType().getMaxStackSize() > 1; boolean enchantable = canBeEnchanted(item); if (stackable) { - lore.add(net.kyori.adventure.text.Component.text(StringUtil.CC("&eRight-click &7to change amount"))); + lore.add(Common.deserializeMiniMessage("Right-click to change amount")); } if (enchantable) { if (stackable) { - lore.add(net.kyori.adventure.text.Component.text(StringUtil.CC("&eShift-right-click &7to enchant"))); + lore.add(Common.deserializeMiniMessage("Shift-right-click to enchant")); } else { - lore.add(net.kyori.adventure.text.Component.text(StringUtil.CC("&eRight-click &7to enchant"))); + lore.add(Common.deserializeMiniMessage("Right-click to enchant")); } } @@ -332,7 +331,7 @@ private static ItemStack buildEmptySlot(int index) { ItemStack item = new ItemStack(Material.LIGHT_BLUE_STAINED_GLASS_PANE); var meta = item.getItemMeta(); if (meta != null) { - meta.displayName(net.kyori.adventure.text.Component.text(StringUtil.CC("&7Slot " + (index + 1)))); + meta.displayName(Common.deserializeMiniMessage("Slot " + (index + 1))); item.setItemMeta(meta); } return item; diff --git a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/ShulkerCategoryGUI.java b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/ShulkerCategoryGUI.java index 1714510bb..374bc5d02 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/ShulkerCategoryGUI.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/ShulkerCategoryGUI.java @@ -8,6 +8,7 @@ import dev.nandi0813.practice.manager.playerkit.PlayerKitManager; import dev.nandi0813.practice.manager.playerkit.StaticItems; import dev.nandi0813.practice.manager.playerkit.items.KitItem; +import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.InventoryUtil; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -30,22 +31,22 @@ public class ShulkerCategoryGUI extends GUI { // Ordered map: display name → Material private static final Map SHULKERS = new LinkedHashMap<>(); static { - SHULKERS.put("&fWhite Shulker Box", Material.WHITE_SHULKER_BOX); - SHULKERS.put("&6Orange Shulker Box", Material.ORANGE_SHULKER_BOX); - SHULKERS.put("&dMagenta Shulker Box", Material.MAGENTA_SHULKER_BOX); - SHULKERS.put("&bLight Blue Shulker Box", Material.LIGHT_BLUE_SHULKER_BOX); - SHULKERS.put("&eYellow Shulker Box", Material.YELLOW_SHULKER_BOX); - SHULKERS.put("&aLime Shulker Box", Material.LIME_SHULKER_BOX); - SHULKERS.put("&dPink Shulker Box", Material.PINK_SHULKER_BOX); - SHULKERS.put("&8Gray Shulker Box", Material.GRAY_SHULKER_BOX); - SHULKERS.put("&7Light Gray Shulker Box", Material.LIGHT_GRAY_SHULKER_BOX); - SHULKERS.put("&3Cyan Shulker Box", Material.CYAN_SHULKER_BOX); - SHULKERS.put("&5Purple Shulker Box", Material.PURPLE_SHULKER_BOX); - SHULKERS.put("&9Blue Shulker Box", Material.BLUE_SHULKER_BOX); - SHULKERS.put("&cBrown Shulker Box", Material.BROWN_SHULKER_BOX); - SHULKERS.put("&2Green Shulker Box", Material.GREEN_SHULKER_BOX); - SHULKERS.put("&cRed Shulker Box", Material.RED_SHULKER_BOX); - SHULKERS.put("&0Black Shulker Box", Material.BLACK_SHULKER_BOX); + SHULKERS.put("White Shulker Box", Material.WHITE_SHULKER_BOX); + SHULKERS.put("Orange Shulker Box", Material.ORANGE_SHULKER_BOX); + SHULKERS.put("Magenta Shulker Box", Material.MAGENTA_SHULKER_BOX); + SHULKERS.put("Light Blue Shulker Box", Material.LIGHT_BLUE_SHULKER_BOX); + SHULKERS.put("Yellow Shulker Box", Material.YELLOW_SHULKER_BOX); + SHULKERS.put("Lime Shulker Box", Material.LIME_SHULKER_BOX); + SHULKERS.put("Pink Shulker Box", Material.PINK_SHULKER_BOX); + SHULKERS.put("Gray Shulker Box", Material.GRAY_SHULKER_BOX); + SHULKERS.put("Light Gray Shulker Box", Material.LIGHT_GRAY_SHULKER_BOX); + SHULKERS.put("Cyan Shulker Box", Material.CYAN_SHULKER_BOX); + SHULKERS.put("Purple Shulker Box", Material.PURPLE_SHULKER_BOX); + SHULKERS.put("Blue Shulker Box", Material.BLUE_SHULKER_BOX); + SHULKERS.put("Brown Shulker Box", Material.BROWN_SHULKER_BOX); + SHULKERS.put("Green Shulker Box", Material.GREEN_SHULKER_BOX); + SHULKERS.put("Red Shulker Box", Material.RED_SHULKER_BOX); + SHULKERS.put("Black Shulker Box", Material.BLACK_SHULKER_BOX); } // Slot positions for the 16 shulkers (two rows of 8, centred in a 5-row GUI) @@ -166,13 +167,10 @@ private static ItemStack buildShulkerItem(Material mat, String name) { ItemStack item = new ItemStack(mat); var meta = item.getItemMeta(); if (meta != null) { - meta.displayName(net.kyori.adventure.text.Component.text( - dev.nandi0813.practice.util.StringUtil.CC(name))); + meta.displayName(Common.deserializeMiniMessage(name)); var lore = new java.util.ArrayList(); - lore.add(net.kyori.adventure.text.Component.text( - dev.nandi0813.practice.util.StringUtil.CC("&eLeft-click &7to add to kit"))); - lore.add(net.kyori.adventure.text.Component.text( - dev.nandi0813.practice.util.StringUtil.CC("&eRight-click &7to edit contents"))); + lore.add(Common.deserializeMiniMessage("Left-click to add to kit")); + lore.add(Common.deserializeMiniMessage("Right-click to edit contents")); meta.lore(lore); item.setItemMeta(meta); } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/itemeditors/ItemCategory.java b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/itemeditors/ItemCategory.java index 18adb0d2d..470162d5a 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/itemeditors/ItemCategory.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/playerkit/guis/itemeditors/ItemCategory.java @@ -108,7 +108,7 @@ public void handleClickEvent(InventoryClickEvent e) { KitItem kitItem = editing.getKitItem(); GUI mainGUI = editing.getCustomLadder().getMainGUI(); - // ── Back ────────────────────────────────────────────────────── + // Back if (icon.equals(StaticItems.CATEGORY_GUI_BACK_ICON)) { if (editing.isEditingShulker()) { dev.nandi0813.practice.manager.playerkit.guis.ShulkerBoxEditorGUI editor = editing.getShulkerEditor(); @@ -120,7 +120,7 @@ public void handleClickEvent(InventoryClickEvent e) { return; } - // ── None ───────────────────────────────────────────────────── + // None if (icon.equals(StaticItems.CATEGORY_GUI_NONE_ICON)) { kitItem.reset(); if (editing.isEditingShulker()) { @@ -137,7 +137,7 @@ public void handleClickEvent(InventoryClickEvent e) { return; } - // ── Fixed categories ───────────────────────────────────────── + // Fixed categories if (icon.equals(StaticItems.CATEGORY_GUI_ARMOR_ICON)) { GUIManager.getInstance().searchGUI(GUIType.PlayerCustom_Armor).open(player); return; @@ -159,7 +159,7 @@ public void handleClickEvent(InventoryClickEvent e) { return; } - // ── Dynamic categories ─────────────────────────────────────── + // Dynamic categories for (DynamicCategory cat : PlayerKitManager.getInstance().getDynamicCategories()) { if (icon.equals(cat.getIcon())) { cat.getGui().open(player); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/Profile.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/Profile.java index 6c725fbd6..6bd58f81c 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/Profile.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/Profile.java @@ -32,62 +32,71 @@ @Setter public class Profile { + // Identity private final UUID uuid; private final OfflinePlayer player; private final ProfileFile file; private final ProfileStat stats; private Group group; + // Name display private Component prefix; private String nameTemplate; private NamedTextColor nameColor; private Component suffix; + // Join timestamps private long firstJoin; private long lastJoin; + // Online state private ProfileStatus status; private boolean spectatorMode; private boolean party; private boolean hideSpectators; + // Staff state private boolean staffMode; private boolean staffChat; private boolean hideFromPlayers; private Player followTarget; + // Player settings private boolean duelRequest; private boolean sidebar; private boolean hidePlayers; private boolean partyInvites; private boolean allowSpectate; private boolean privateMessages; - private ProfileWorldTime worldTime; + private ProfileWorldTime worldTime = ProfileWorldTime.DAY; private boolean flying; private ProfilePrefixVisibility prefixVisibility = ProfilePrefixVisibility.PREFIX_AND_SUFFIX; + // Custom kits private int allowedCustomKits; private final Map> unrankedCustomKits = new HashMap<>(); private final Map> rankedCustomKits = new HashMap<>(); - // Unranked & Ranked & Event left daily + // Daily limits private final List ignoredPlayers = new ArrayList<>(); - private int unrankedLeft = 0; - private int rankedLeft = 0; - private int eventStartLeft = 0; - private int partyBroadcastLeft = 0; + private int unrankedLeft; + private int rankedLeft; + private int eventStartLeft; + private int partyBroadcastLeft; + // Misc private RankedBan rankedBan = new RankedBan(); private ProfileSettingsGui settingsGui; - private ActionBar actionBar = new ActionBar(this); + private ActionBar actionBar; - // Cosmetics data for armor trims + // Cosmetics private CosmeticsData cosmeticsData = new CosmeticsData(); // Custom ladder private PlayerCustomKitSelector playerCustomKitSelector; private final List customLadders = new ArrayList<>(); private CustomLadder selectedCustomLadder; + private boolean fullDataLoaded; public Profile(UUID uuid, OfflinePlayer player) { this.uuid = uuid; @@ -116,67 +125,118 @@ public Player getOnlinePlayer() { return Bukkit.getPlayer(uuid); } + // Data persistence + public void saveData() { - this.rankedBan.set(file.getConfig(), "ranked-ban"); + rankedBan.saveToConfig(file.getConfig(), "ranked-ban"); + + saveCustomLadders(); + stats.setData(false); + file.setData(); + } + + private void saveCustomLadders() { for (CustomLadder customLadder : customLadders) { customLadder.setData(); } - if (this.selectedCustomLadder != null) { - this.file.getConfig().set("selected-custom-ladder", customLadders.indexOf(this.selectedCustomLadder)); + if (selectedCustomLadder != null) { + file.getConfig().set("selected-custom-ladder", customLadders.indexOf(selectedCustomLadder)); } - - stats.setData(false); - file.setData(); } public void getData() { + stats.getLadderStats().clear(); file.getData(); stats.getData(); - this.rankedBan.get(file.getConfig(), "ranked-ban"); - - if (this.file.getConfig().isConfigurationSection("player-custom-kit")) { - this.customLadders.clear(); - for (String ladder : Objects.requireNonNull(this.file.getConfig().getConfigurationSection("player-custom-kit")).getKeys(false)) { - try { - int i = Integer.parseInt(ladder); - if (i < 0 || i > 5) { - continue; - } - - this.customLadders.add(new CustomLadder(this, "player-custom-kit." + i, i + 1)); - } catch (NumberFormatException e) { - if (this.file.getConfig().isConfigurationSection("player-custom-kit")) { - CustomLadder oldLadderFormat = new CustomLadder(this, "player-custom-kit", 1); - this.customLadders.add(new CustomLadder(oldLadderFormat, this, "player-custom-kit.0")); - - this.file.getConfig().set("player-custom-kit", null); - this.file.saveFile(); - } - break; - } - } + rankedBan.loadFromConfig(file.getConfig(), "ranked-ban"); + + loadCustomLadders(); + + fullDataLoaded = true; + } + + private void loadCustomLadders() { + if (!file.getConfig().isConfigurationSection("player-custom-kit")) return; + + customLadders.clear(); + for (String key : Objects.requireNonNull( + file.getConfig().getConfigurationSection("player-custom-kit")).getKeys(false)) { + if (!tryLoadCustomLadder(key)) break; + } + + loadSelectedCustomLadder(); + } - if (!this.customLadders.isEmpty()) { - if (this.file.getConfig().isInt("selected-custom-ladder")) { - int index = this.file.getConfig().getInt("selected-custom-ladder"); - if (index < this.customLadders.size() && index >= 0) { - this.selectedCustomLadder = this.customLadders.get(index); - } - } + private boolean tryLoadCustomLadder(String key) { + try { + int i = Integer.parseInt(key); + if (i < 0 || i > 5) return true; + + customLadders.add(new CustomLadder(this, "player-custom-kit." + i, i + 1)); + return true; + } catch (NumberFormatException e) { + if (file.getConfig().isConfigurationSection("player-custom-kit")) { + CustomLadder oldFormat = new CustomLadder(this, "player-custom-kit", 1); + customLadders.add(new CustomLadder(oldFormat, this, "player-custom-kit.0")); + file.getConfig().set("player-custom-kit", null); + file.saveFile(); } + return false; } } + private void loadSelectedCustomLadder() { + if (customLadders.isEmpty()) return; + if (!file.getConfig().isInt("selected-custom-ladder")) return; + + int index = file.getConfig().getInt("selected-custom-ladder"); + if (index >= 0 && index < customLadders.size()) { + selectedCustomLadder = customLadders.get(index); + } + } + + public synchronized void loadStatsOnlyData() { + file.reloadFile(); + stats.getLadderStats().clear(); + + if (file.getConfig().isLong("join.first")) + setFirstJoin(file.getConfig().getLong("join.first")); + + if (file.getConfig().isLong("join.latest")) + setLastJoin(file.getConfig().getLong("join.latest")); + + stats.getData(); + fullDataLoaded = false; + } + + public synchronized void ensureFullDataLoaded() { + if (fullDataLoaded) return; + + getData(); + } + + public synchronized void demoteToStatsOnly() { + settingsGui = null; + playerCustomKitSelector = null; + selectedCustomLadder = null; + customLadders.clear(); + unrankedCustomKits.clear(); + rankedCustomKits.clear(); + ignoredPlayers.clear(); + followTarget = null; + actionBar = null; + fullDataLoaded = false; + } + + // Group management + public void checkGroup() { Player online = getOnlinePlayer(); if (online == null || !online.isOnline()) return; Group newGroup = GroupManager.getInstance().getGroup(online); - - // If newGroup is null (shouldn't happen with our fix, but safety check) - // or if the group has changed, update it if (newGroup == null) { Common.sendConsoleMMMessage("Warning: Could not determine group for " + online.getName() + ". Assigning default (lowest weighted) group to them."); return; @@ -185,7 +245,7 @@ public void checkGroup() { if (group == newGroup) return; try { - this.setGroup(newGroup); + setGroup(newGroup); } catch (Exception e) { Common.sendConsoleMMMessage("Failed to set group for " + online.getName() + "! Error: " + e.getMessage()); } @@ -193,15 +253,9 @@ public void checkGroup() { public int getCustomKitPerm() { Player onlinePlayer = getOnlinePlayer(); + if (onlinePlayer == null) return 0; - if (onlinePlayer == null) { - return 0; - } - - if (this.group != null) { - return this.group.getModifiableKitLimit(); - } - + if (group != null) return group.getModifiableKitLimit(); return -1; } @@ -211,52 +265,62 @@ public void setGroup(Group group) throws IllegalArgumentException { } this.group = group; - this.unrankedLeft = group.getUnrankedLimit(); - this.rankedLeft = group.getRankedLimit(); - this.eventStartLeft = group.getEventStartLimit(); - this.partyBroadcastLeft = group.getPartyBroadcastLimit(); - - Player onlinePlayer = this.getOnlinePlayer(); - if (onlinePlayer != null) { - Party partyObj = PartyManager.getInstance().getParty(onlinePlayer); - if (partyObj != null && onlinePlayer.equals(partyObj.getLeader())) { - partyObj.refreshMaxPlayerLimitForLeader(); - } - } + unrankedLeft = group.getUnrankedLimit(); + rankedLeft = group.getRankedLimit(); + eventStartLeft = group.getEventStartLimit(); + partyBroadcastLeft = group.getPartyBroadcastLimit(); - while (this.customLadders.size() < this.group.getCustomKitLimit()) { - this.customLadders.add(new CustomLadder(this, "player-custom-kit." + customLadders.size(), this.customLadders.size() + 1)); - } + refreshPartyLimit(); + syncCustomLadderCount(); - while (this.customLadders.size() > this.group.getCustomKitLimit()) { - this.customLadders.removeLast(); + // Invalidate the selector so it gets recreated on next access (lazy-loading) + playerCustomKitSelector = null; + } + + private void refreshPartyLimit() { + Player onlinePlayer = getOnlinePlayer(); + if (onlinePlayer == null) return; + + Party partyObj = PartyManager.getInstance().getParty(onlinePlayer); + if (partyObj != null && onlinePlayer.equals(partyObj.getLeader())) { + partyObj.refreshMaxPlayerLimitForLeader(); } + } - // Invalidate the selector so it gets recreated on next access (lazy-loading) - this.playerCustomKitSelector = null; + private void syncCustomLadderCount() { + while (customLadders.size() < group.getCustomKitLimit()) { + customLadders.add(new CustomLadder(this, "player-custom-kit." + customLadders.size(), customLadders.size() + 1)); + } + while (customLadders.size() > group.getCustomKitLimit()) { + customLadders.removeLast(); + } } - /** - * Lazily loads and returns the PlayerCustomKitSelector. - * Creates it only when first accessed to save RAM for offline players. - */ + // Lazy-loaded accessors + public PlayerCustomKitSelector getPlayerCustomKitSelector() { - if (this.playerCustomKitSelector == null) { - this.playerCustomKitSelector = new PlayerCustomKitSelector(this); + if (playerCustomKitSelector == null) { + playerCustomKitSelector = new PlayerCustomKitSelector(this); } - return this.playerCustomKitSelector; + return playerCustomKitSelector; } - public void setSelectedCustomLadder(CustomLadder customLadder) { - if (customLadder == null) { - throw new IllegalArgumentException("Custom ladder cannot be null."); + public ActionBar getActionBar() { + if (actionBar == null) { + actionBar = new ActionBar(this); } + return actionBar; + } - if (!customLadders.contains(customLadder)) { + // Setters with side effects + + public void setSelectedCustomLadder(CustomLadder customLadder) { + if (customLadder == null) + throw new IllegalArgumentException("Custom ladder cannot be null."); + if (!customLadders.contains(customLadder)) throw new IllegalArgumentException("Custom ladder not found in profile."); - } - this.selectedCustomLadder = customLadder; + selectedCustomLadder = customLadder; } public void setStatus(ProfileStatus status) { @@ -265,15 +329,18 @@ public void setStatus(ProfileStatus status) { Bukkit.getPluginManager().callEvent(new ProfileStatusChangeEvent(this, previous, status)); - // Leaving lobby/spectate for a new activity invalidates pending rematches. - if ((previous == ProfileStatus.LOBBY || previous == ProfileStatus.SPECTATE) - && status != ProfileStatus.LOBBY - && status != ProfileStatus.SPECTATE - && status != ProfileStatus.OFFLINE) { - Player online = getOnlinePlayer(); - if (online != null && online.isOnline()) { - MatchManager.getInstance().invalidateRematchByPlayer(online); - } + invalidateRematchIfLeftLobby(previous, status); + } + + private void invalidateRematchIfLeftLobby(ProfileStatus previous, ProfileStatus status) { + boolean wasIdle = previous == ProfileStatus.LOBBY || previous == ProfileStatus.SPECTATE; + boolean isActive = status != ProfileStatus.LOBBY && status != ProfileStatus.SPECTATE && status != ProfileStatus.OFFLINE; + + if (!wasIdle || !isActive) return; + + Player online = getOnlinePlayer(); + if (online != null && online.isOnline()) { + MatchManager.getInstance().invalidateRematchByPlayer(online); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/ProfileFile.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/ProfileFile.java index 8d24d6f93..4e0e7279b 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/ProfileFile.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/ProfileFile.java @@ -42,32 +42,56 @@ public ProfileFile(Profile profile) { @Override public void setData() { + setJoinTimestamps(); + setGroup(); + setPrefix(); + setSuffix(); + setNameTemplate(); + setCustomKitPerm(); + setSettings(); + saveCosmetics(); + saveCustomKits(); + saveFile(); + } + + private void setJoinTimestamps() { config.set("join.latest", profile.getLastJoin()); + } + private void setGroup() { if (profile.getGroup() != null) config.set("group", profile.getGroup().getName()); else config.set("group", null); + } + private void setPrefix() { if (profile.getPrefix() != null) config.set("prefix", dev.nandi0813.practice.ZonePractice.getMiniMessage().serialize(profile.getPrefix())); else config.set("prefix", null); + } + private void setSuffix() { if (profile.getSuffix() != null) config.set("suffix", dev.nandi0813.practice.ZonePractice.getMiniMessage().serialize(profile.getSuffix())); else config.set("suffix", null); + } + private void setNameTemplate() { if (profile.getNameTemplate() != null && !profile.getNameTemplate().isEmpty()) config.set("name-template", profile.getNameTemplate()); else config.set("name-template", null); + } + private void setCustomKitPerm() { int customKitPerm = profile.getCustomKitPerm(); if (customKitPerm > 0) config.set("allowed-custom-kits", customKitPerm); + } - // Basic settings + private void setSettings() { config.set("settings.duelrequest", profile.isDuelRequest()); config.set("settings.sidebar", profile.isSidebar()); config.set("settings.hideplayers", profile.isHidePlayers()); @@ -77,74 +101,67 @@ public void setData() { config.set("settings.messages", profile.isPrivateMessages()); config.set("settings.worldtime", profile.getWorldTime().toString()); config.set("settings.prefix-visibility", profile.getPrefixVisibility().toString()); + } - // Cosmetics data for armor trims - if (profile.getCosmeticsData() != null) { - config.set("cosmetics.active-tier", profile.getCosmeticsData().getActiveTier().getId()); - config.set("cosmetics.death-effect", profile.getCosmeticsData().getDeathEffect().getId()); - config.set("cosmetics.lobby-item", profile.getCosmeticsData().getLobbyItemType().name()); - config.set("cosmetics.shield.active-layout-index", profile.getCosmeticsData().getActiveShieldLayoutIndex()); + private void saveCosmetics() { + if (profile.getCosmeticsData() == null) return; - List serializedShieldLayouts = profile.getCosmeticsData().getShieldLayouts().stream() - .map(ShieldLayout::serialise) - .toList(); - config.set("cosmetics.shield.layouts", serializedShieldLayouts); + config.set("cosmetics.active-tier", profile.getCosmeticsData().getActiveTier().getId()); + config.set("cosmetics.death-effect", profile.getCosmeticsData().getDeathEffect().getId()); + config.set("cosmetics.lobby-item", profile.getCosmeticsData().getLobbyItemType().name()); + config.set("cosmetics.shield.active-layout-index", profile.getCosmeticsData().getActiveShieldLayoutIndex()); - for (ArmorTrimTier tier : ArmorTrimTier.values()) { - for (ArmorSlot slot : ArmorSlot.values()) { - String basePath = "cosmetics.tiers." + tier.getId() + "." + slot.getId(); + List serializedShieldLayouts = profile.getCosmeticsData().getShieldLayouts().stream() + .map(ShieldLayout::serialise) + .toList(); + config.set("cosmetics.shield.layouts", serializedShieldLayouts); - TrimPattern pattern = profile.getCosmeticsData().getPattern(tier, slot); - if (pattern != null) { - config.set(basePath + ".pattern", "minecraft:" + CosmeticsPermissionManager.getTrimId(pattern)); - } else { - config.set(basePath + ".pattern", null); - } + for (ArmorTrimTier tier : ArmorTrimTier.values()) { + for (ArmorSlot slot : ArmorSlot.values()) { + String basePath = "cosmetics.tiers." + tier.getId() + "." + slot.getId(); - TrimMaterial material = profile.getCosmeticsData().getMaterial(tier, slot); - if (material != null) { - config.set(basePath + ".material", "minecraft:" + CosmeticsPermissionManager.getTrimId(material)); - } else { - config.set(basePath + ".material", null); - } + TrimPattern pattern = profile.getCosmeticsData().getPattern(tier, slot); + if (pattern != null) { + config.set(basePath + ".pattern", "minecraft:" + CosmeticsPermissionManager.getTrimId(pattern)); + } else { + config.set(basePath + ".pattern", null); + } + + TrimMaterial material = profile.getCosmeticsData().getMaterial(tier, slot); + if (material != null) { + config.set(basePath + ".material", "minecraft:" + CosmeticsPermissionManager.getTrimId(material)); + } else { + config.set(basePath + ".material", null); } } } + } - // Ladder win/lose stats + private void saveCustomKits() { for (NormalLadder ladder : LadderManager.getInstance().getLadders()) { String name = ladder.getName().toLowerCase(); - for (int i = 1; i <= 4; i++) { - if (!profile.getUnrankedCustomKits().isEmpty()) { - if (profile.getUnrankedCustomKits().containsKey(ladder) && profile.getUnrankedCustomKits().get(ladder).containsKey(i)) { - CustomKit customKit = profile.getUnrankedCustomKits().get(ladder).get(i); - if (customKit != null) { - config.set("customkit." + name + ".kit" + i + ".unranked.inventory", ItemSerializationUtil.itemStackArrayToBase64(customKit.getInventory())); - config.set("customkit." + name + ".kit" + i + ".unranked.armor", ItemSerializationUtil.itemStackArrayToBase64(customKit.getArmor())); - config.set("customkit." + name + ".kit" + i + ".unranked.extra", ItemSerializationUtil.itemStackArrayToBase64(customKit.getExtra())); - } - } - } - } - - if (ladder.isRanked()) { - for (int i = 1; i <= 4; i++) { - if (!profile.getRankedCustomKits().isEmpty()) { - if (profile.getRankedCustomKits().containsKey(ladder) && profile.getRankedCustomKits().get(ladder).containsKey(i)) { - CustomKit customKit = profile.getRankedCustomKits().get(ladder).get(i); - if (customKit != null) { - config.set("customkit." + name + ".kit" + i + ".ranked.inventory", ItemSerializationUtil.itemStackArrayToBase64(customKit.getInventory())); - config.set("customkit." + name + ".kit" + i + ".ranked.armor", ItemSerializationUtil.itemStackArrayToBase64(customKit.getArmor())); - config.set("customkit." + name + ".kit" + i + ".ranked.extra", ItemSerializationUtil.itemStackArrayToBase64(customKit.getExtra())); - } - } - } - } - } + saveCustomKitSet(profile.getUnrankedCustomKits(), ladder, name, "unranked"); + if (ladder.isRanked()) + saveCustomKitSet(profile.getRankedCustomKits(), ladder, name, "ranked"); } + } - saveFile(); + private void saveCustomKitSet(Map> kits, NormalLadder ladder, String name, String type) { + if (kits.isEmpty()) return; + + Map ladderKits = kits.get(ladder); + if (ladderKits == null) return; + + for (int i = 1; i <= 4; i++) { + CustomKit customKit = ladderKits.get(i); + if (customKit == null) continue; + + String base = "customkit." + name + ".kit" + i + "." + type; + config.set(base + ".inventory", ItemSerializationUtil.itemStackArrayToBase64(customKit.getInventory())); + config.set(base + ".armor", ItemSerializationUtil.itemStackArrayToBase64(customKit.getArmor())); + config.set(base + ".extra", ItemSerializationUtil.itemStackArrayToBase64(customKit.getExtra())); + } } public void setDefaultData() { @@ -161,7 +178,12 @@ public void setDefaultData() { config.set("settings.allowspectate", ConfigManager.getBoolean("PLAYER.DEFAULT-SETTINGS.ALLOWSPECTATE")); config.set("settings.flying", ConfigManager.getBoolean("PLAYER.DEFAULT-SETTINGS.FLYING")); config.set("settings.messages", ConfigManager.getBoolean("PLAYER.DEFAULT-SETTINGS.PRIVATEMESSAGE")); - config.set("settings.worldtime", ProfileWorldTime.valueOf(ConfigManager.getString("PLAYER.DEFAULT-SETTINGS.WORLD-TIME")).toString()); + String defaultWorldTime = ConfigManager.getString("PLAYER.DEFAULT-SETTINGS.WORLD-TIME"); + try { + config.set("settings.worldtime", ProfileWorldTime.valueOf(defaultWorldTime.toUpperCase(Locale.ROOT)).toString()); + } catch (Exception ignored) { + config.set("settings.worldtime", ProfileWorldTime.DAY.toString()); + } String defaultPrefixVisibility = ConfigManager.getString("PLAYER.DEFAULT-SETTINGS.PREFIX-VISIBILITY"); try { @@ -175,38 +197,62 @@ public void setDefaultData() { @Override public void getData() { + loadJoinTimestamps(); + loadGroup(); + loadPrefix(); + loadSuffix(); + loadNameTemplate(); + loadCustomKitPerm(); + loadSettings(); + loadCosmetics(); + loadCustomKits(); + } + + private void loadJoinTimestamps() { if (config.isLong("join.first")) profile.setFirstJoin(config.getLong("join.first")); if (config.isLong("join.latest")) profile.setLastJoin(config.getLong("join.latest")); + } - if (config.isSet("group")) { - Group group = GroupManager.getInstance().getGroup(config.getString("group")); - if (group != null) { - try { - profile.setGroup(group); - } catch (Exception e) { - Common.sendConsoleMMMessage("Failed to set group for " + profile.getPlayer().getName() + "! Error: " + e.getMessage()); - } - profile.setUnrankedLeft(group.getUnrankedLimit()); - profile.setRankedLeft(group.getRankedLimit()); - profile.setEventStartLeft(group.getEventStartLimit()); + private void loadGroup() { + if (!config.isSet("group")) return; + + Group group = GroupManager.getInstance().getGroup(config.getString("group")); + if (group != null) { + try { + profile.setGroup(group); + } catch (Exception e) { + Common.sendConsoleMMMessage("Failed to set group for " + profile.getPlayer().getName() + "! Error: " + e.getMessage()); } + profile.setUnrankedLeft(group.getUnrankedLimit()); + profile.setRankedLeft(group.getRankedLimit()); + profile.setEventStartLeft(group.getEventStartLimit()); } + } + private void loadPrefix() { if (config.isString("prefix")) profile.setPrefix(NameFormatUtil.parseConfiguredComponent(Objects.requireNonNull(config.getString("prefix")))); + } + private void loadSuffix() { if (config.isString("suffix")) profile.setSuffix(NameFormatUtil.parseConfiguredComponent(Objects.requireNonNull(config.getString("suffix")))); + } + private void loadNameTemplate() { if (config.isString("name-template")) profile.setNameTemplate(config.getString("name-template")); + } + private void loadCustomKitPerm() { if (config.isInt("allowed-custom-kits")) profile.setAllowedCustomKits(config.getInt("allowed-custom-kits")); + } + private void loadSettings() { profile.setDuelRequest(config.getBoolean("settings.duelrequest")); profile.setSidebar(config.getBoolean("settings.sidebar")); profile.setHidePlayers(config.getBoolean("settings.hideplayers")); @@ -214,7 +260,13 @@ public void getData() { profile.setAllowSpectate(config.getBoolean("settings.allowspectate")); profile.setFlying(config.getBoolean("settings.flying")); profile.setPrivateMessages(config.getBoolean("settings.messages")); - profile.setWorldTime(ProfileWorldTime.valueOf(config.getString("settings.worldtime"))); + + String rawWorldTime = config.getString("settings.worldtime", ProfileWorldTime.DAY.toString()); + try { + profile.setWorldTime(ProfileWorldTime.valueOf(rawWorldTime.toUpperCase(Locale.ROOT))); + } catch (IllegalArgumentException ignored) { + profile.setWorldTime(ProfileWorldTime.DAY); + } String rawPrefixVisibility = config.getString("settings.prefix-visibility", ProfilePrefixVisibility.PREFIX_AND_SUFFIX.toString()); try { @@ -222,8 +274,9 @@ public void getData() { } catch (IllegalArgumentException ignored) { profile.setPrefixVisibility(ProfilePrefixVisibility.PREFIX_AND_SUFFIX); } + } - // Load cosmetics data for armor trims + private void loadCosmetics() { try { ArmorTrimTier activeTier = ArmorTrimTier.fromId(config.getString("cosmetics.active-tier", "leather")); profile.getCosmeticsData().setActiveTier(activeTier); @@ -290,76 +343,35 @@ public void getData() { } catch (Exception e) { // Handle invalid cosmetics data - silently ignore for graceful handling of removed/renamed cosmetics } + } + private void loadCustomKits() { for (NormalLadder ladder : LadderManager.getInstance().getLadders()) { String name = ladder.getName().toLowerCase(); - // Unranked custom kit - Map unrankedInventory = new HashMap<>(); - for (int i = 1; i <= 4; i++) { - ItemStack[] inventory; - ItemStack[] armor; - ItemStack[] extra; - - if (config.isString("customkit." + name.toLowerCase() + ".kit" + i + ".unranked.inventory")) { - inventory = ItemSerializationUtil.itemStackArrayFromBase64(config.getString("customkit." + name.toLowerCase() + ".kit" + i + ".unranked.inventory")); - armor = config.isString("customkit." + name.toLowerCase() + ".kit" + i + ".unranked.armor") - ? ItemSerializationUtil.itemStackArrayFromBase64(config.getString("customkit." + name.toLowerCase() + ".kit" + i + ".unranked.armor")) - : null; - extra = ItemSerializationUtil.itemStackArrayFromBase64(config.getString("customkit." + name.toLowerCase() + ".kit" + i + ".unranked.extra")); - - // Legacy migration: old format stored armor in inventory[36..39] - if (armor == null && inventory != null && inventory.length > 36) { - ItemStack[] splitInventory = new ItemStack[36]; - System.arraycopy(inventory, 0, splitInventory, 0, 36); - armor = new ItemStack[]{ - inventory.length > 36 ? inventory[36] : null, - inventory.length > 37 ? inventory[37] : null, - inventory.length > 38 ? inventory[38] : null, - inventory.length > 39 ? inventory[39] : null - }; - inventory = splitInventory; - } + profile.getUnrankedCustomKits().put(ladder, loadCustomKitSet(ladder, name, "unranked")); + if (ladder.isRanked()) + profile.getRankedCustomKits().put(ladder, loadCustomKitSet(ladder, name, "ranked")); + } + } - unrankedInventory.put(i, new CustomKit(null, inventory, armor, extra)); - } - } - profile.getUnrankedCustomKits().put(ladder, unrankedInventory); - - if (ladder.isRanked()) { - // Ranked custom kit - Map rankedInventory = new HashMap<>(); - for (int i = 1; i <= 4; i++) { - ItemStack[] inventory; - ItemStack[] armor; - ItemStack[] extra; - - if (config.isString("customkit." + name.toLowerCase() + ".kit" + i + ".ranked.inventory")) { - inventory = ItemSerializationUtil.itemStackArrayFromBase64(config.getString("customkit." + name.toLowerCase() + ".kit" + i + ".ranked.inventory")); - armor = config.isString("customkit." + name.toLowerCase() + ".kit" + i + ".ranked.armor") - ? ItemSerializationUtil.itemStackArrayFromBase64(config.getString("customkit." + name.toLowerCase() + ".kit" + i + ".ranked.armor")) - : null; - extra = ItemSerializationUtil.itemStackArrayFromBase64(config.getString("customkit." + name.toLowerCase() + ".kit" + i + ".ranked.extra")); - - // Legacy migration: old format stored armor in inventory[36..39] - if (armor == null && inventory != null && inventory.length > 36) { - ItemStack[] splitInventory = new ItemStack[36]; - System.arraycopy(inventory, 0, splitInventory, 0, 36); - armor = new ItemStack[]{ - inventory.length > 36 ? inventory[36] : null, - inventory.length > 37 ? inventory[37] : null, - inventory.length > 38 ? inventory[38] : null, - inventory.length > 39 ? inventory[39] : null - }; - inventory = splitInventory; - } + private Map loadCustomKitSet(NormalLadder ladder, String name, String type) { + Map result = new HashMap<>(); - rankedInventory.put(i, new CustomKit(null, inventory, armor, extra)); - } - } - profile.getRankedCustomKits().put(ladder, rankedInventory); - } + for (int i = 1; i <= 4; i++) { + String base = "customkit." + name + ".kit" + i + "." + type; + if (!config.isString(base + ".inventory")) continue; + + ItemStack[] inventory = ItemSerializationUtil.itemStackArrayFromBase64(config.getString(base + ".inventory")); + ItemStack[] armor = config.isString(base + ".armor") + ? ItemSerializationUtil.itemStackArrayFromBase64(config.getString(base + ".armor")) + : null; + ItemStack[] extra = ItemSerializationUtil.itemStackArrayFromBase64(config.getString(base + ".extra")); + + result.put(i, new CustomKit(null, inventory, armor, extra)); } + + return result; } public void deleteCustomKit(Ladder ladder, int kit) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/ProfileManager.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/ProfileManager.java index 29612e337..5b67792d0 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/ProfileManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/ProfileManager.java @@ -17,6 +17,7 @@ import java.io.File; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; public class ProfileManager { @@ -32,33 +33,54 @@ private ProfileManager() { } @Getter - private final Map uuids = new HashMap<>(); + private final Map uuids = new ConcurrentHashMap<>(); @Getter - private final Map profiles = new HashMap<>(); + private final Map profiles = new ConcurrentHashMap<>(); private final File folder = new File(ZonePractice.getInstance().getDataFolder() + "/profiles"); public Profile getProfile(UUID uuid) { - return profiles.getOrDefault(uuid, null); + if (uuid == null) { + return null; + } + + Profile cached = profiles.get(uuid); + if (cached != null) { + return cached; + } + + return loadProfileIfExists(uuid, Bukkit.getOfflinePlayer(uuid), false); } public Profile getProfile(Player player) { - if (player == null) return null; - if (uuids.containsKey(player)) - return getProfile(uuids.get(player)); - - uuids.put(player, player.getUniqueId()); - return getProfile(player); + if (player == null) { + return null; + } + UUID uuid = player.getUniqueId(); + uuids.put(player, uuid); + Profile profile = profiles.get(uuid); + if (profile == null) { + return loadProfileIfExists(uuid, player, true); + } + if (!profile.isFullDataLoaded()) { + profile.ensureFullDataLoaded(); + loadProfileInfo(profile); + } + return profile; } public Profile getProfile(OfflinePlayer player) { if (player == null) return null; - if (uuids.containsKey(player)) - return getProfile(uuids.get(player)); - uuids.put(player, player.getUniqueId()); - return getProfile(player); + UUID uuid = player.getUniqueId(); + Profile profile = profiles.get(uuid); + if (profile != null) { + return profile; + } + + boolean loadFull = player.isOnline(); + return loadProfileIfExists(uuid, player, loadFull); } public Profile getProfile(Entity entity) { @@ -69,14 +91,14 @@ public Profile getProfile(Entity entity) { } public Profile newProfile(Player player, UUID uuid) { - final Profile profile = new Profile(uuid); + Profile profile = new Profile(uuid); profile.getFile().setDefaultData(); profile.getData(); profile.getStats().setDivision(DivisionManager.getInstance().getDivision(profile)); - ProfileManager.getInstance().getProfiles().put(uuid, profile); - ProfileManager.getInstance().loadProfileInfo(profile); + profiles.put(uuid, profile); + loadProfileInfo(profile); Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> Bukkit.getPluginManager().callEvent(new NewPlayerJoin(player)), 20L * 2); @@ -87,32 +109,10 @@ public Profile newProfile(Player player, UUID uuid) { public void loadProfiles(final StartUpCallback startUpCallback) { Bukkit.getScheduler().runTaskAsynchronously(ZonePractice.getInstance(), () -> { - if (folder.isDirectory() && folder.listFiles() != null) { - for (File profileFile : Objects.requireNonNull(folder.listFiles())) { - if (profileFile.isFile() && profileFile.getName().endsWith(".yml")) { - YamlConfiguration config = YamlConfiguration.loadConfiguration(profileFile); - String uuidString = config.getString("uuid"); - UUID uuid = parseUuid(uuidString); - - if (uuid == null) { - Common.sendConsoleMMMessage("Warning: Skipping corrupted profile file " + profileFile.getName() + " (invalid or missing uuid: " + uuidString + ")"); - continue; - } - - OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); - - if (offlinePlayer.getName() != null) { - Profile profile = new Profile(uuid, offlinePlayer); - profile.getData(); - profiles.put(uuid, profile); - } - } - } - } + loadProfilesFromDisk(); - Collection loadedProfiles = ProfileManager.getInstance().getProfiles().values(); - CompletableFuture loadFuture = MysqlManager.loadProfilesAsync(loadedProfiles); - loadFuture.whenComplete((ignored, throwable) -> { + Collection loadedProfiles = profiles.values(); + MysqlManager.loadProfilesAsync(loadedProfiles).whenComplete((ignored, throwable) -> { if (throwable != null) { Common.sendConsoleMMMessage("Error: " + throwable.getMessage()); } @@ -121,6 +121,36 @@ public void loadProfiles(final StartUpCallback startUpCallback) { }); } + private void loadProfilesFromDisk() { + if (!folder.exists() && !folder.mkdirs()) { + Common.sendConsoleMMMessage("Error: Could not create profiles folder."); + } + + if (!folder.isDirectory()) return; + + File[] files = folder.listFiles(); + if (files == null) return; + + for (File profileFile : files) { + if (!profileFile.isFile() || !profileFile.getName().endsWith(".yml")) continue; + + YamlConfiguration config = YamlConfiguration.loadConfiguration(profileFile); + String uuidString = config.getString("uuid"); + UUID uuid = parseUuid(uuidString); + + if (uuid == null) { + Common.sendConsoleMMMessage("Warning: Skipping corrupted profile file " + profileFile.getName() + " (invalid or missing uuid: " + uuidString + ")"); + continue; + } + + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + Profile profile = new Profile(uuid, offlinePlayer); + profile.loadStatsOnlyData(); + profile.getStats().setDivision(DivisionManager.getInstance().getDivision(profile)); + profiles.put(uuid, profile); + } + } + private UUID parseUuid(String uuidString) { if (uuidString == null || uuidString.isBlank()) return null; @@ -132,20 +162,84 @@ private UUID parseUuid(String uuidString) { } public void loadAllProfileInformations() { - Bukkit.getScheduler().runTaskAsynchronously(ZonePractice.getInstance(), () -> - { - for (Profile profile : ProfileManager.getInstance().getProfiles().values()) - loadProfileInfo(profile); + Bukkit.getScheduler().runTask(ZonePractice.getInstance(), () -> { + for (Player online : Bukkit.getOnlinePlayers()) { + Profile profile = getProfile(online); + if (profile != null) { + loadProfileInfo(profile); + } + } }); } public void loadProfileInfo(Profile profile) { + if (profile == null) { + return; + } + profile.getStats().setDivision(DivisionManager.getInstance().getDivision(profile)); - profile.setSettingsGui(new ProfileSettingsGui(profile)); + + Player online = profile.getOnlinePlayer(); + if (online != null && online.isOnline() && profile.getSettingsGui() == null) { + profile.setSettingsGui(new ProfileSettingsGui(profile)); + } } public void saveProfiles() { - for (Profile profile : profiles.values()) profile.saveData(); + // Iterate over a stable snapshot to avoid ConcurrentModificationException + // when autosave overlaps joins/quits/profile updates. + for (Profile profile : new ArrayList<>(profiles.values())) { + if (profile != null) { + profile.saveData(); + } + } + } + + public void demoteOfflineProfile(UUID uuid) { + if (uuid == null) { + return; + } + + Player online = Bukkit.getPlayer(uuid); + if (online != null && online.isOnline()) { + return; + } + + Profile profile = profiles.get(uuid); + if (profile == null) { + return; + } + + profile.saveData(); + MysqlManager.saveProfileAsync(profile); + profile.loadStatsOnlyData(); + profile.demoteToStatsOnly(); + } + + public void clearPlayerReference(Player player) { + if (player == null) { + return; + } + + uuids.remove(player); + } + + private Profile loadProfileIfExists(UUID uuid, OfflinePlayer offlinePlayer, boolean loadFull) { + File profileFile = new File(folder, uuid.toString().toLowerCase() + ".yml"); + if (!profileFile.exists()) { + return null; + } + + Profile loaded = profiles.computeIfAbsent(uuid, id -> new Profile(id, offlinePlayer)); + if (loadFull) { + loaded.ensureFullDataLoaded(); + loadProfileInfo(loaded); + } else if (!loaded.isFullDataLoaded() && loaded.getStats().getLadderStats().isEmpty()) { + loaded.loadStatsOnlyData(); + loaded.getStats().setDivision(DivisionManager.getInstance().getDivision(loaded)); + } + + return loaded; } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/RankedBan.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/RankedBan.java index 593fcb169..a3ffecae2 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/RankedBan.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/RankedBan.java @@ -13,59 +13,60 @@ @Setter public class RankedBan { - private Profile banner = null; - private boolean banned = false; - private String reason = null; - private long time = 0L; + private Profile banner; + private boolean banned; + private String reason; + private long time; public boolean ban(Profile banner, String reason) { - if (!this.banned) { - this.banned = true; - this.banner = banner; - this.reason = reason; - this.time = System.currentTimeMillis(); - return true; - } - return false; + if (banned) return false; + + this.banned = true; + this.banner = banner; + this.reason = reason; + this.time = System.currentTimeMillis(); + return true; } public boolean unban() { - if (this.banned) { - this.banned = false; - this.reason = null; - return true; - } - return false; + if (!banned) return false; + + this.banned = false; + this.reason = null; + return true; } - public void set(final @NotNull YamlConfiguration config, final String path) { - if (this.isBanned()) { - if (banner != null) - config.set(path + ".banner", this.getBanner().getUuid().toString()); - config.set(path + ".banned", true); - config.set(path + ".reason", this.getReason()); - config.set(path + ".bannedAt", this.getTime()); - } else + public void saveToConfig(final @NotNull YamlConfiguration config, final String path) { + if (!isBanned()) { config.set(path, null); + return; + } + + if (banner != null) + config.set(path + ".banner", banner.getUuid().toString()); + + config.set(path + ".banned", true); + config.set(path + ".reason", reason); + config.set(path + ".bannedAt", time); } - public void get(final @NotNull YamlConfiguration config, final String path) { - if (config.isBoolean(path + ".banned")) - this.banned = config.getBoolean(path + ".banned"); + public void loadFromConfig(final @NotNull YamlConfiguration config, final String path) { + if (!config.isBoolean(path + ".banned")) return; - if (this.isBanned()) { - Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> - { - if (config.isString(path + ".banner")) - banner = ProfileManager.getInstance().getProfile(UUID.fromString(config.getString(path + ".banner"))); - }, 20L * 3); + banned = config.getBoolean(path + ".banned"); - if (config.isString(path + ".reason")) - this.reason = config.getString(path + ".reason"); + if (!isBanned()) return; - if (config.isLong(path + ".bannedAt")) - this.time = config.getLong(path + ".bannedAt"); - } + Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> { + if (config.isString(path + ".banner")) + banner = ProfileManager.getInstance().getProfile(UUID.fromString(config.getString(path + ".banner"))); + }, 20L * 3); + + if (config.isString(path + ".reason")) + reason = config.getString(path + ".reason"); + + if (config.isLong(path + ".bannedAt")) + time = config.getLong(path + ".bannedAt"); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/CosmeticsData.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/CosmeticsData.java index 2cf6a77ec..f39e23e09 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/CosmeticsData.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/CosmeticsData.java @@ -41,18 +41,14 @@ public String getPermissionNode() { public CosmeticsData() { for (ArmorTrimTier tier : ArmorTrimTier.values()) { Map bySlot = new EnumMap<>(ArmorSlot.class); - for (ArmorSlot armorSlot : ArmorSlot.values()) { + for (ArmorSlot armorSlot : ArmorSlot.values()) bySlot.put(armorSlot, new SlotData()); - } tierData.put(tier, bySlot); } } public TrimPattern getPattern(ArmorTrimTier tier, ArmorSlot slot) { - if (slot == null) { - return null; - } - + if (slot == null) return null; return getSlotData(tier, slot).pattern; } @@ -61,18 +57,12 @@ public TrimMaterial getMaterial(ArmorSlot slot) { } public TrimMaterial getMaterial(ArmorTrimTier tier, ArmorSlot slot) { - if (slot == null) { - return null; - } - + if (slot == null) return null; return getSlotData(tier, slot).material; } public void setPattern(ArmorTrimTier tier, ArmorSlot slot, TrimPattern pattern) { - if (slot == null) { - return; - } - + if (slot == null) return; getSlotData(tier, slot).pattern = pattern; } @@ -81,10 +71,7 @@ public void setMaterial(ArmorSlot slot, TrimMaterial material) { } public void setMaterial(ArmorTrimTier tier, ArmorSlot slot, TrimMaterial material) { - if (slot == null) { - return; - } - + if (slot == null) return; getSlotData(tier, slot).material = material; } @@ -96,7 +83,7 @@ private SlotData getSlotData(ArmorTrimTier tier, ArmorSlot slot) { tierData.put(resolvedTier, bySlot); } - return bySlot.computeIfAbsent(slot, k -> new SlotData()); + return bySlot.computeIfAbsent(slot, _ -> new SlotData()); } public ShieldLayout getActiveShieldLayout() { @@ -113,14 +100,14 @@ public void setLobbyItemType(LobbyItemType lobbyItemType) { } public void setShieldLayouts(List layouts) { - this.shieldLayouts.clear(); - if (layouts != null) { - this.shieldLayouts.addAll(layouts); - } + shieldLayouts.clear(); + if (layouts != null) + shieldLayouts.addAll(layouts); } private static final class SlotData { private TrimPattern pattern; private TrimMaterial material; } + } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/armortrim/CosmeticsPermissionSanitizer.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/armortrim/CosmeticsPermissionSanitizer.java index 818cb940a..b200f41c8 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/armortrim/CosmeticsPermissionSanitizer.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/armortrim/CosmeticsPermissionSanitizer.java @@ -13,9 +13,9 @@ public enum CosmeticsPermissionSanitizer { ; - public static boolean sanitize(Player player, Profile profile) { + public static void sanitize(Player player, Profile profile) { if (player == null || profile == null || profile.getCosmeticsData() == null) { - return false; + return; } boolean changed = false; @@ -95,7 +95,7 @@ public static boolean sanitize(Player player, Profile profile) { int maxShieldLayouts = CosmeticsPermissionManager.getMaxShieldLayouts(player); var shieldLayouts = profile.getCosmeticsData().getShieldLayouts(); while (shieldLayouts.size() > maxShieldLayouts) { - shieldLayouts.remove(shieldLayouts.size() - 1); + shieldLayouts.removeLast(); changed = true; } @@ -113,7 +113,6 @@ public static boolean sanitize(Player player, Profile profile) { profile.saveData(); } - return changed; } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/shield/ShieldLayout.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/shield/ShieldLayout.java index 79f082fea..a30fe6865 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/shield/ShieldLayout.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/cosmetics/shield/ShieldLayout.java @@ -52,8 +52,7 @@ public boolean removeTopLayer() { return true; } - // ── Serialisation helpers ──────────────────────────────────────── - + // Serialisation helpers /** Serialise to a single string for YAML storage: "name|BASE_COLOR|COLOR:PATTERN,COLOR:PATTERN,..." */ public String serialise() { var bannerPatternRegistry = RegistryAccess.registryAccess().getRegistry(RegistryKey.BANNER_PATTERN); @@ -112,8 +111,7 @@ private static PatternType parsePatternType(String raw) { private static String escapePipe(String s) { return s.replace("|", "\\|"); } private static String unescapePipe(String s) { return s.replace("\\|", "|"); } - // ── PatternLayer record ────────────────────────────────────────── - + // PatternLayer record public record PatternLayer(DyeColor color, PatternType pattern) { @Override public boolean equals(Object obj) { diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/enums/ProfilePrefixVisibility.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/enums/ProfilePrefixVisibility.java index bd90d2132..e37523844 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/enums/ProfilePrefixVisibility.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/enums/ProfilePrefixVisibility.java @@ -33,12 +33,12 @@ public static ProfilePrefixVisibility getNext(ProfilePrefixVisibility current) { if (current != null) { int index = list.indexOf(current); if (index == list.size() - 1) { - return list.get(0); + return list.getFirst(); } return list.get(index + 1); } - return list.get(0); + return list.getFirst(); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/enums/ProfileWorldTime.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/enums/ProfileWorldTime.java index 65f9d134b..2da0eb1de 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/enums/ProfileWorldTime.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/enums/ProfileWorldTime.java @@ -31,11 +31,11 @@ public static ProfileWorldTime getNextWorldTime(ProfileWorldTime profileWorldTim int c = list.indexOf(profileWorldTime); if (list.size() - 1 == c) - return list.get(0); + return list.getFirst(); else return list.get(c + 1); } else - return list.get(0); + return list.getFirst(); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/group/GroupManager.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/group/GroupManager.java index 1369de742..5fdb56c7f 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/group/GroupManager.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/group/GroupManager.java @@ -2,6 +2,7 @@ import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.backend.ConfigFile; +import dev.nandi0813.practice.util.StringUtil; import dev.nandi0813.practice.manager.backend.ConfigManager; import dev.nandi0813.practice.manager.profile.Profile; import dev.nandi0813.practice.manager.profile.ProfileManager; @@ -48,7 +49,7 @@ public void loadGroups() { List sidebarExtensionRaw = new ArrayList<>(); if (SidebarManager.getInstance().isList("GROUP-EXTENSIONS." + groupName)) { for (String line : SidebarManager.getInstance().getList("GROUP-EXTENSIONS." + groupName)) { - sidebarExtension.add(ZonePractice.getMiniMessage().deserialize(line)); + sidebarExtension.add(ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(line))); sidebarExtensionRaw.add(line); } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/statistics/LadderStats.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/statistics/LadderStats.java index 50469fe21..468b9a6c1 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/statistics/LadderStats.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/statistics/LadderStats.java @@ -11,77 +11,71 @@ public class LadderStats { private final YamlConfiguration config; - private int unRankedWins = 0; - private int unRankedLosses = 0; - private int unRankedWinStreak = 0; - private int unRankedBestWinStreak = 0; - private int unRankedLoseStreak = 0; - private int unRankedBestLoseStreak = 0; - - private int rankedWins = 0; - private int rankedLosses = 0; - private int rankedWinStreak = 0; - private int rankedBestWinStreak = 0; - private int rankedLoseStreak = 0; - private int rankedBestLoseStreak = 0; + private int unRankedWins; + private int unRankedLosses; + private int unRankedWinStreak; + private int unRankedBestWinStreak; + private int unRankedLoseStreak; + private int unRankedBestLoseStreak; + + private int rankedWins; + private int rankedLosses; + private int rankedWinStreak; + private int rankedBestWinStreak; + private int rankedLoseStreak; + private int rankedBestLoseStreak; private int elo = LadderManager.getDEFAULT_ELO(); - private int kills = 0; - private int deaths = 0; + private int kills; + private int deaths; public LadderStats(YamlConfiguration config) { this.config = config; } public void increaseWins(boolean ranked) { - if (ranked) { - this.rankedWins++; - } else { - this.unRankedWins++; - } + if (ranked) + rankedWins++; + else + unRankedWins++; } public void increaseLosses(boolean ranked) { - if (ranked) { - this.rankedLosses++; - } else { - this.unRankedLosses++; - } + if (ranked) + rankedLosses++; + else + unRankedLosses++; } public void increaseWinStreak(boolean ranked) { if (ranked) { - this.rankedWinStreak++; - this.rankedLoseStreak = 0; + rankedWinStreak++; + rankedLoseStreak = 0; - if (this.rankedWinStreak > this.rankedBestWinStreak) { - this.rankedBestWinStreak = this.rankedWinStreak; - } + if (rankedWinStreak > rankedBestWinStreak) + rankedBestWinStreak = rankedWinStreak; } else { - this.unRankedWinStreak++; - this.unRankedLoseStreak = 0; + unRankedWinStreak++; + unRankedLoseStreak = 0; - if (this.unRankedWinStreak > this.unRankedBestWinStreak) { - this.unRankedBestWinStreak = this.unRankedWinStreak; - } + if (unRankedWinStreak > unRankedBestWinStreak) + unRankedBestWinStreak = unRankedWinStreak; } } public void increaseLoseStreak(boolean ranked) { if (ranked) { - this.rankedLoseStreak++; - this.rankedWinStreak = 0; + rankedLoseStreak++; + rankedWinStreak = 0; - if (this.rankedLoseStreak > this.rankedBestLoseStreak) { - this.rankedBestLoseStreak = this.rankedLoseStreak; - } + if (rankedLoseStreak > rankedBestLoseStreak) + rankedBestLoseStreak = rankedLoseStreak; } else { - this.unRankedLoseStreak++; - this.unRankedWinStreak = 0; + unRankedLoseStreak++; + unRankedWinStreak = 0; - if (this.unRankedLoseStreak > this.unRankedBestLoseStreak) { - this.unRankedBestLoseStreak = this.unRankedLoseStreak; - } + if (unRankedLoseStreak > unRankedBestLoseStreak) + unRankedBestLoseStreak = unRankedLoseStreak; } } @@ -97,79 +91,80 @@ public void decreaseElo(int elo) { } public void increaseKills() { - this.kills++; + kills++; } public void increaseDeaths() { - this.deaths++; + deaths++; } public void setData(String ladderName, boolean ranked) { - config.set("stats.ladder-stats." + ladderName + ".unranked.wins", unRankedWins); - config.set("stats.ladder-stats." + ladderName + ".unranked.losses", unRankedLosses); - config.set("stats.ladder-stats." + ladderName + ".unranked.win-streak", unRankedWinStreak); - config.set("stats.ladder-stats." + ladderName + ".unranked.best-win-streak", unRankedBestWinStreak); - config.set("stats.ladder-stats." + ladderName + ".unranked.lose-streak", unRankedLoseStreak); - config.set("stats.ladder-stats." + ladderName + ".unranked.best-lose-streak", unRankedBestLoseStreak); + String base = "stats.ladder-stats." + ladderName; + config.set(base + ".unranked.wins", unRankedWins); + config.set(base + ".unranked.losses", unRankedLosses); + config.set(base + ".unranked.win-streak", unRankedWinStreak); + config.set(base + ".unranked.best-win-streak", unRankedBestWinStreak); + config.set(base + ".unranked.lose-streak", unRankedLoseStreak); + config.set(base + ".unranked.best-lose-streak", unRankedBestLoseStreak); if (ranked) { - config.set("stats.ladder-stats." + ladderName + ".ranked.wins", rankedWins); - config.set("stats.ladder-stats." + ladderName + ".ranked.losses", rankedLosses); - config.set("stats.ladder-stats." + ladderName + ".ranked.win-streak", rankedWinStreak); - config.set("stats.ladder-stats." + ladderName + ".ranked.best-win-streak", rankedBestWinStreak); - config.set("stats.ladder-stats." + ladderName + ".ranked.lose-streak", rankedLoseStreak); - config.set("stats.ladder-stats." + ladderName + ".ranked.best-lose-streak", rankedBestLoseStreak); - config.set("stats.ladder-stats." + ladderName + ".ranked.elo", elo != 0 ? elo : LadderManager.getDEFAULT_ELO()); + config.set(base + ".ranked.wins", rankedWins); + config.set(base + ".ranked.losses", rankedLosses); + config.set(base + ".ranked.win-streak", rankedWinStreak); + config.set(base + ".ranked.best-win-streak", rankedBestWinStreak); + config.set(base + ".ranked.lose-streak", rankedLoseStreak); + config.set(base + ".ranked.best-lose-streak", rankedBestLoseStreak); + config.set(base + ".ranked.elo", elo != 0 ? elo : LadderManager.getDEFAULT_ELO()); } - config.set("stats.ladder-stats." + ladderName + ".global.kills", kills); - config.set("stats.ladder-stats." + ladderName + ".global.deaths", deaths); + config.set(base + ".global.kills", kills); + config.set(base + ".global.deaths", deaths); } public void getData(String ladderName, boolean ranked) { - this.unRankedWins = config.getInt("stats.ladder-stats." + ladderName + ".unranked.wins"); - this.unRankedLosses = config.getInt("stats.ladder-stats." + ladderName + ".unranked.losses"); - this.unRankedWinStreak = config.getInt("stats.ladder-stats." + ladderName + ".unranked.win-streak"); - this.unRankedBestWinStreak = config.getInt("stats.ladder-stats." + ladderName + ".unranked.best-win-streak"); - this.unRankedLoseStreak = config.getInt("stats.ladder-stats." + ladderName + ".unranked.lose-streak"); - this.unRankedBestLoseStreak = config.getInt("stats.ladder-stats." + ladderName + ".unranked.best-lose-streak"); + String base = "stats.ladder-stats." + ladderName; + unRankedWins = config.getInt(base + ".unranked.wins"); + unRankedLosses = config.getInt(base + ".unranked.losses"); + unRankedWinStreak = config.getInt(base + ".unranked.win-streak"); + unRankedBestWinStreak = config.getInt(base + ".unranked.best-win-streak"); + unRankedLoseStreak = config.getInt(base + ".unranked.lose-streak"); + unRankedBestLoseStreak = config.getInt(base + ".unranked.best-lose-streak"); if (ranked) { - this.rankedWins = config.getInt("stats.ladder-stats." + ladderName + ".ranked.wins"); - this.rankedLosses = config.getInt("stats.ladder-stats." + ladderName + ".ranked.losses"); - this.rankedWinStreak = config.getInt("stats.ladder-stats." + ladderName + ".ranked.win-streak"); - this.rankedBestWinStreak = config.getInt("stats.ladder-stats." + ladderName + ".ranked.best-win-streak"); - this.rankedLoseStreak = config.getInt("stats.ladder-stats." + ladderName + ".ranked.lose-streak"); - this.rankedBestLoseStreak = config.getInt("stats.ladder-stats." + ladderName + ".ranked.best-lose-streak"); - this.elo = config.getInt("stats.ladder-stats." + ladderName + ".ranked.elo"); - - if (this.elo == 0) { - this.elo = LadderManager.getDEFAULT_ELO(); - } + rankedWins = config.getInt(base + ".ranked.wins"); + rankedLosses = config.getInt(base + ".ranked.losses"); + rankedWinStreak = config.getInt(base + ".ranked.win-streak"); + rankedBestWinStreak = config.getInt(base + ".ranked.best-win-streak"); + rankedLoseStreak = config.getInt(base + ".ranked.lose-streak"); + rankedBestLoseStreak = config.getInt(base + ".ranked.best-lose-streak"); + elo = config.getInt(base + ".ranked.elo"); + + if (elo == 0) + elo = LadderManager.getDEFAULT_ELO(); } - this.kills = config.getInt("stats.ladder-stats." + ladderName + ".global.kills"); - this.deaths = config.getInt("stats.ladder-stats." + ladderName + ".global.deaths"); + kills = config.getInt(base + ".global.kills"); + deaths = config.getInt(base + ".global.deaths"); } public void reset() { - this.unRankedWins = 0; - this.unRankedLosses = 0; - this.unRankedWinStreak = 0; - this.unRankedBestWinStreak = 0; - this.unRankedLoseStreak = 0; - this.unRankedBestLoseStreak = 0; - - this.rankedWins = 0; - this.rankedLosses = 0; - this.rankedWinStreak = 0; - this.rankedBestWinStreak = 0; - this.rankedLoseStreak = 0; - this.rankedBestLoseStreak = 0; - this.elo = LadderManager.getDEFAULT_ELO(); - - this.kills = 0; - this.deaths = 0; + unRankedWins = 0; + unRankedLosses = 0; + unRankedWinStreak = 0; + unRankedBestWinStreak = 0; + unRankedLoseStreak = 0; + unRankedBestLoseStreak = 0; + + rankedWins = 0; + rankedLosses = 0; + rankedWinStreak = 0; + rankedBestWinStreak = 0; + rankedLoseStreak = 0; + rankedBestLoseStreak = 0; + elo = LadderManager.getDEFAULT_ELO(); + + kills = 0; + deaths = 0; } } diff --git a/core/src/main/java/dev/nandi0813/practice/manager/profile/statistics/ProfileStat.java b/core/src/main/java/dev/nandi0813/practice/manager/profile/statistics/ProfileStat.java index f193fee4e..c8780d419 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/profile/statistics/ProfileStat.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/profile/statistics/ProfileStat.java @@ -86,20 +86,11 @@ public void increaseLoseStreak(NormalLadder ladder, boolean ranked) { } public void setData(boolean save) { - if (experience != 0) config.set("experience", experience); - else config.set("experience", null); - - if (winStreak != 0) config.set("winStreak", winStreak); - else config.set("winStreak", null); - - if (bestWinStreak != 0) config.set("bestWinStreak", bestWinStreak); - else config.set("bestWinStreak", null); - - if (loseStreak != 0) config.set("loseStreak", loseStreak); - else config.set("loseStreak", null); - - if (bestLoseStreak != 0) config.set("bestLoseStreak", bestLoseStreak); - else config.set("bestLoseStreak", null); + setConfigIntIfNonZero("experience", experience); + setConfigIntIfNonZero("winStreak", winStreak); + setConfigIntIfNonZero("bestWinStreak", bestWinStreak); + setConfigIntIfNonZero("loseStreak", loseStreak); + setConfigIntIfNonZero("bestLoseStreak", bestLoseStreak); for (NormalLadder ladder : LadderManager.getInstance().getLadders()) { getLadderStat(ladder).setData(ladder.getName().toLowerCase(), ladder.isRanked()); @@ -109,21 +100,19 @@ public void setData(boolean save) { profileFile.saveFile(); } - public void getData() { - if (config.isInt("experience")) - this.setExperience(config.getInt("experience")); - - if (config.isInt("winStreak")) - this.setWinStreak(config.getInt("winStreak")); - - if (config.isInt("bestWinStreak")) - this.setBestWinStreak(config.getInt("bestWinStreak")); - - if (config.isInt("loseStreak")) - this.setLoseStreak(config.getInt("loseStreak")); + private void setConfigIntIfNonZero(String path, int value) { + if (value != 0) + config.set(path, value); + else + config.set(path, null); + } - if (config.isInt("bestLoseStreak")) - this.setBestLoseStreak(config.getInt("bestLoseStreak")); + public void getData() { + setExperience(getConfigInt("experience")); + setWinStreak(getConfigInt("winStreak")); + setBestWinStreak(getConfigInt("bestWinStreak")); + setLoseStreak(getConfigInt("loseStreak")); + setBestLoseStreak(getConfigInt("bestLoseStreak")); for (NormalLadder ladder : LadderManager.getInstance().getLadders()) { LadderStats ladderStat = new LadderStats(config); @@ -132,6 +121,10 @@ public void getData() { } } + private int getConfigInt(String path) { + return config.isInt(path) ? config.getInt(path) : 0; + } + public void loadDefaultStats(NormalLadder ladder) { LadderStats ladderStat = getLadderStat(ladder); ladderStat.reset(); diff --git a/core/src/main/java/dev/nandi0813/practice/manager/sidebar/adapter/AdapterUtil.java b/core/src/main/java/dev/nandi0813/practice/manager/sidebar/adapter/AdapterUtil.java index eea1db117..81412d95a 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/sidebar/adapter/AdapterUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/sidebar/adapter/AdapterUtil.java @@ -1,6 +1,5 @@ package dev.nandi0813.practice.manager.sidebar.adapter; -import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.fight.ffa.game.FFA; import dev.nandi0813.practice.manager.fight.match.Match; import dev.nandi0813.practice.manager.fight.match.Round; @@ -16,9 +15,11 @@ import dev.nandi0813.practice.manager.profile.Profile; import dev.nandi0813.practice.manager.profile.ProfileManager; import dev.nandi0813.practice.manager.sidebar.SidebarManager; +import dev.nandi0813.practice.util.Common; import dev.nandi0813.practice.util.NameFormatUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.intellij.lang.annotations.RegExp; @@ -30,7 +31,13 @@ private static String getRoundSymbol() { return symbol == null || symbol.isBlank() ? "|" : symbol; } - // ==================== Helper Methods ==================== + private static int getRoundSymbolMaxRounds() { + if (!SidebarManager.getInstance().getConfig().contains("MATCH.ROUND-SYMBOL-MAX-ROUNDS")) { + return 3; + } + return Math.max(0, SidebarManager.getInstance().getConfig().getInt("MATCH.ROUND-SYMBOL-MAX-ROUNDS")); + } + /** * Creates a text replacement config for a simple string replacement @@ -72,8 +79,8 @@ private static Component replaceCommonMatchPlaceholders(Component line, Match ma .replaceText(replace("%roundDuration%", roundDuration)) .replaceText(replace("%matchDuration%", match.getFormattedTime())) .replaceText(replace("%ping%", String.valueOf(PlayerUtil.getPing(player)))) - .replaceText(replace("%arena%", match.getArena().getDisplayName())) - .replaceText(replace("%ladder%", match.getLadder().getDisplayName())); + .replaceText(replace("%arena%", Common.deserializeMiniMessage(match.getArena().getDisplayName()))) + .replaceText(replace("%ladder%", Common.deserializeMiniMessage(match.getLadder().getDisplayName()))); } /** @@ -81,12 +88,16 @@ private static Component replaceCommonMatchPlaceholders(Component line, Match ma */ private static Component replaceTeamPlaceholders(Component line, String prefix, TeamEnum team, dev.nandi0813.practice.manager.fight.match.type.playersvsplayers.PlayersVsPlayers match, int winsNeeded) { + Component rounds = getRoundString(winsNeeded, match.getWonRounds(team)); + Component coloredRounds = team.getColor().append(getRoundString(winsNeeded, match.getWonRounds(team), team.getColor())); + return line .replaceText(replace("%" + prefix + "name%", team.getNameComponent())) .replaceText(replace("%" + prefix + "color%", team.getColor())) .replaceText(replace("%" + prefix + "players%", String.valueOf(match.getTeamPlayers(team).size()))) .replaceText(replace("%" + prefix + "alivePlayers%", String.valueOf(match.getTeamAlivePlayers(team).size()))) - .replaceText(replace("%" + prefix + "rounds%", getRoundString(winsNeeded, match.getWonRounds(team)))) + .replaceText(replace("%" + prefix + "color%%" + prefix + "rounds%", coloredRounds)) + .replaceText(replace("%" + prefix + "rounds%", rounds)) .replaceText(replace("%" + prefix + "roundsNumber%", String.valueOf(match.getWonRounds(team)))); } @@ -124,25 +135,39 @@ private static Component getSidebarName(Player player) { return NameFormatUtil.resolveFullName(profile, player, player.getName()); } - // ==================== Public Methods ==================== public static Component getRoundString(int rounds, int wonRounds) { - StringBuilder string = new StringBuilder(); - boolean firstNotWon = true; + return getRoundString(rounds, wonRounds, null); + } + + public static Component getRoundString(int rounds, int wonRounds, Component wonColor) { + if (rounds <= 0) { + return Component.empty(); + } + + int clampedWonRounds = Math.max(0, Math.min(wonRounds, rounds)); + int symbolMaxRounds = getRoundSymbolMaxRounds(); + if (symbolMaxRounds > 0 && rounds > symbolMaxRounds) { + String counter = clampedWonRounds + "/" + rounds; + return wonColor == null ? Component.text(counter) : wonColor.append(Component.text(counter)); + } + + Component component = Component.empty(); + String roundSymbol = getRoundSymbol(); + Component wonSymbol = wonColor == null + ? Component.text(roundSymbol) + : wonColor.append(Component.text(roundSymbol)); + Component notWonSymbol = Component.text(roundSymbol, NamedTextColor.GRAY); for (int i = 1; i <= rounds; i++) { - if (i <= wonRounds) { - string.append(getRoundSymbol()); + if (i <= clampedWonRounds) { + component = component.append(wonSymbol); } else { - if (firstNotWon) { - string.append("").append(getRoundSymbol()); - firstNotWon = false; - } else { - string.append(getRoundSymbol()); - } + component = component.append(notWonSymbol); } } - return ZonePractice.getMiniMessage().deserialize(string.toString()); + + return component; } public static Component replaceMatchPlaceholders(Player player, Component line, Match match) { @@ -170,8 +195,12 @@ private static Component handleDuelPlaceholders(Component line, Duel duel, Playe // Replace combined placeholders for colored player names (boxing) line = replaceColoredPlayerName(line, "%playerTeamColor%%player%", team, player) + .replaceText(replace("%playerTeamColor%%rounds%", + team.getColor().append(getRoundString(duel.getWinsNeeded(), duel.getWonRounds(player), team.getColor())))) .replaceText(replace("%enemyTeamColor%%enemyName%", - enemy == null ? Component.empty() : enemyTeam.getColor().append(getSidebarName(enemy)))); + enemy == null ? Component.empty() : enemyTeam.getColor().append(getSidebarName(enemy)))) + .replaceText(replace("%enemyTeamColor%%enemyRounds%", + enemy == null ? Component.empty() : enemyTeam.getColor().append(getRoundString(duel.getWinsNeeded(), duel.getWonRounds(enemy), enemyTeam.getColor())))); // Replace individual placeholders line = line @@ -228,8 +257,8 @@ public static Component replaceFFAPlaceholders(Player player, Component line, FF .replaceText(replace("%spectators%", String.valueOf(ffa.getSpectators().size()))) .replaceText(replace("%nextReset%", ffa.getBuildRollback() != null ? ffa.getBuildRollback().getFormattedTime() : "N/A")) .replaceText(replace("%ping%", String.valueOf(PlayerUtil.getPing(player)))) - .replaceText(replace("%ladder%", ffa.getPlayers().get(player).getDisplayName())) - .replaceText(replace("%arena%", ffa.getArena().getDisplayName())) + .replaceText(replace("%ladder%", Common.deserializeMiniMessage(ffa.getPlayers().get(player).getDisplayName()))) + .replaceText(replace("%arena%", Common.deserializeMiniMessage(ffa.getArena().getDisplayName()))) .replaceText(replace("%kills%", String.valueOf(statistic.getKills()))) .replaceText(replace("%deaths%", String.valueOf(statistic.getDeaths()))); } @@ -239,7 +268,7 @@ public static Component replaceFFASpecPlaceholders(Component line, FFA ffa) { .replaceText(replace("%players%", String.valueOf(ffa.getPlayers().size()))) .replaceText(replace("%spectators%", String.valueOf(ffa.getSpectators().size()))) .replaceText(replace("%nextReset%", ffa.getBuildRollback() != null ? ffa.getBuildRollback().getFormattedTime() : "N/A")) - .replaceText(replace("%arena%", ffa.getArena().getDisplayName())); + .replaceText(replace("%arena%", Common.deserializeMiniMessage(ffa.getArena().getDisplayName()))); } public static Component replaceMatchSpectatePlaceholders(Component line, Match match) { @@ -250,8 +279,8 @@ public static Component replaceMatchSpectatePlaceholders(Component line, Match m .replaceText(replace("%totalRounds%", String.valueOf(match.getLadder().getRounds()))) .replaceText(replace("%roundDuration%", roundDuration)) .replaceText(replace("%matchDuration%", match.getFormattedTime())) - .replaceText(replace("%arena%", match.getArena().getDisplayName())) - .replaceText(replace("%ladder%", match.getLadder().getDisplayName())); + .replaceText(replace("%arena%", Common.deserializeMiniMessage(match.getArena().getDisplayName()))) + .replaceText(replace("%ladder%", Common.deserializeMiniMessage(match.getLadder().getDisplayName()))); // Replace team colors for non-FFA matches if (!match.getType().equals(MatchType.PARTY_FFA)) { @@ -277,7 +306,11 @@ private static Component handleSpectatorDuelPlaceholders(Component line, Duel du // Replace colored player names for boxing line = replaceColoredPlayerName(line, "%team1color%%player1%", TeamEnum.TEAM1, player1) - .replaceText(replace("%team2color%%player2%", TeamEnum.TEAM2.getColor().append(getSidebarName(player2)))); + .replaceText(replace("%team2color%%player2%", TeamEnum.TEAM2.getColor().append(getSidebarName(player2)))) + .replaceText(replace("%team1color%%player1rounds%", + TeamEnum.TEAM1.getColor().append(getRoundString(duel.getWinsNeeded(), duel.getWonRounds(player1), TeamEnum.TEAM1.getColor())))) + .replaceText(replace("%team2color%%player2rounds%", + TeamEnum.TEAM2.getColor().append(getRoundString(duel.getWinsNeeded(), duel.getWonRounds(player2), TeamEnum.TEAM2.getColor())))); // Replace individual player info return line diff --git a/core/src/main/java/dev/nandi0813/practice/manager/sidebar/adapter/PracticeAdapter.java b/core/src/main/java/dev/nandi0813/practice/manager/sidebar/adapter/PracticeAdapter.java index 02da00688..65113e6ee 100644 --- a/core/src/main/java/dev/nandi0813/practice/manager/sidebar/adapter/PracticeAdapter.java +++ b/core/src/main/java/dev/nandi0813/practice/manager/sidebar/adapter/PracticeAdapter.java @@ -73,10 +73,6 @@ private static Component parseColoredText(String text) { return Component.empty(); } - if (text.contains("&") || text.contains("§")) { - text = StringUtil.legacyColorToMiniMessage(text); - } - return Common.deserializeMiniMessage(text); } @@ -91,37 +87,49 @@ public List getLines(Player player) { List sidebar = new ArrayList<>(); Profile profile = ProfileManager.getInstance().getProfile(player); - if (profile.getStatus().equals(ProfileStatus.LOBBY) || - profile.getStatus().equals(ProfileStatus.EDITOR) || - profile.getStatus().equals(ProfileStatus.STAFF_MODE) || - profile.getStatus().equals(ProfileStatus.CUSTOM_EDITOR)) { - Party party = PartyManager.getInstance().getParty(player); + switch (profile.getStatus()) { + case LOBBY, EDITOR, STAFF_MODE, CUSTOM_EDITOR -> buildLobbyLines(player, config, profile, sidebar); + case QUEUE -> buildQueueLines(player, config, profile, sidebar); + case MATCH -> buildMatchLines(player, config, sidebar); + case FFA -> buildFFALines(player, config, sidebar); + case EVENT -> buildEventLines(player, config, sidebar); + case SPECTATE -> buildSpectateLines(player, config, sidebar); + } - if (party == null) { - for (String line : config.getStringList("LOBBY.NORMAL")) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().match("%onlinePlayers%").replacement(String.valueOf(Bukkit.getOnlinePlayers().size())).build()) - .replaceText(TextReplacementConfig.builder().match("%inFightPlayers%").replacement(String.valueOf(MatchManager.getInstance().getPlayerInMatchSize())).build()) - .replaceText(TextReplacementConfig.builder().match("%inQueuePlayer%").replacement(String.valueOf(QueueManager.getInstance().getQueues().size())).build()) - .replaceText(TextReplacementConfig.builder().match("%division%").replacement(profile.getStats().getDivision() != null ? profile.getStats().getDivision().getComponentFullName() : Component.empty()).build()) - .replaceText(TextReplacementConfig.builder().match("%division_short%").replacement(profile.getStats().getDivision() != null ? profile.getStats().getDivision().getComponentShortName() : Component.empty()).build()); - sidebar.add(component); - } - } else { - for (String line : config.getStringList("LOBBY.PARTY")) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().match("%onlinePlayers%").replacement(String.valueOf(Bukkit.getOnlinePlayers().size())).build()) - .replaceText(TextReplacementConfig.builder().match("%inFightPlayers%").replacement(String.valueOf(MatchManager.getInstance().getPlayerInMatchSize())).build()) - .replaceText(TextReplacementConfig.builder().match("%inQueuePlayer%").replacement(String.valueOf(QueueManager.getInstance().getQueues().size())).build()) - .replaceText(TextReplacementConfig.builder().match("%partyLeader%").replacement(displayName(party.getLeader())).build()) - .replaceText(TextReplacementConfig.builder().match("%maxMember%").replacement(String.valueOf(party.getMaxPlayerLimit())).build()) - .replaceText(TextReplacementConfig.builder().match("%members%").replacement(String.valueOf(party.getMembers().size())).build()) - .replaceText(TextReplacementConfig.builder().match("%division%").replacement(profile.getStats().getDivision() != null ? profile.getStats().getDivision().getComponentFullName() : Component.empty()).build()) - .replaceText(TextReplacementConfig.builder().match("%division_short%").replacement(profile.getStats().getDivision() != null ? profile.getStats().getDivision().getComponentShortName() : Component.empty()).build()); - sidebar.add(component); - } + buildFooterLines(player, config, profile, sidebar); + return sidebar; + } + + private void buildLobbyLines(Player player, YamlConfiguration config, Profile profile, List sidebar) { + Party party = PartyManager.getInstance().getParty(player); + + if (party == null) { + for (String line : config.getStringList("LOBBY.NORMAL")) { + Component component = PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().match("%onlinePlayers%").replacement(String.valueOf(Bukkit.getOnlinePlayers().size())).build()) + .replaceText(TextReplacementConfig.builder().match("%inFightPlayers%").replacement(String.valueOf(MatchManager.getInstance().getPlayerInMatchSize())).build()) + .replaceText(TextReplacementConfig.builder().match("%inQueuePlayer%").replacement(String.valueOf(QueueManager.getInstance().getQueues().size())).build()) + .replaceText(TextReplacementConfig.builder().match("%division%").replacement(profile.getStats().getDivision() != null ? profile.getStats().getDivision().getComponentFullName() : Component.empty()).build()) + .replaceText(TextReplacementConfig.builder().match("%division_short%").replacement(profile.getStats().getDivision() != null ? profile.getStats().getDivision().getComponentShortName() : Component.empty()).build()); + sidebar.add(component); } - } else if (profile.getStatus().equals(ProfileStatus.QUEUE)) { + } else { + for (String line : config.getStringList("LOBBY.PARTY")) { + Component component = PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().match("%onlinePlayers%").replacement(String.valueOf(Bukkit.getOnlinePlayers().size())).build()) + .replaceText(TextReplacementConfig.builder().match("%inFightPlayers%").replacement(String.valueOf(MatchManager.getInstance().getPlayerInMatchSize())).build()) + .replaceText(TextReplacementConfig.builder().match("%inQueuePlayer%").replacement(String.valueOf(QueueManager.getInstance().getQueues().size())).build()) + .replaceText(TextReplacementConfig.builder().match("%partyLeader%").replacement(displayName(party.getLeader())).build()) + .replaceText(TextReplacementConfig.builder().match("%maxMember%").replacement(String.valueOf(party.getMaxPlayerLimit())).build()) + .replaceText(TextReplacementConfig.builder().match("%members%").replacement(String.valueOf(party.getMembers().size())).build()) + .replaceText(TextReplacementConfig.builder().match("%division%").replacement(profile.getStats().getDivision() != null ? profile.getStats().getDivision().getComponentFullName() : Component.empty()).build()) + .replaceText(TextReplacementConfig.builder().match("%division_short%").replacement(profile.getStats().getDivision() != null ? profile.getStats().getDivision().getComponentShortName() : Component.empty()).build()); + sidebar.add(component); + } + } + } + + private void buildQueueLines(Player player, YamlConfiguration config, Profile profile, List sidebar) { Queue queue = QueueManager.getInstance().getQueue(player); Event event = EventManager.getInstance().getEventByPlayer(player); CustomKitQueueManager.HostedCustomKitQueue hostedCustomKitQueue = CustomKitQueueManager.getInstance().getHostedQueue(player); @@ -218,477 +226,459 @@ public List getLines(Player player) { } } } - } else if (profile.getStatus().equals(ProfileStatus.MATCH)) { - Match match = MatchManager.getInstance().getLiveMatchByPlayer(player); - - if (match != null) { - Ladder ladder = match.getLadder(); - Round round; - LadderType ladderType = ladder.getType(); - - String path = "MATCH.LADDER." + ladder.getName().toUpperCase() + "." + match.getType().name(); - List configLines = config.getStringList(path); - boolean useLadderSpecificConfig = config.isList(path) && !configLines.isEmpty(); - - if (useLadderSpecificConfig) { - switch (match.getType()) { - case DUEL: - Duel duel = (Duel) match; - round = duel.getCurrentRound(); - - Player enemy = duel.getOppositePlayer(player); - - for (String line : config.getStringList(path)) { - Component component = AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), duel); - - switch (ladderType) { - case BOXING: - int playerHits = match.getCurrentStat(player) != null ? match.getCurrentStat(player).getHit() : 0; - int enemyHits = match.getCurrentStat(enemy) != null ? match.getCurrentStat(enemy).getHit() : 0; - int overAllHits = playerHits - enemyHits; - - component = component - .replaceText(TextReplacementConfig.builder().matchLiteral("%overAllHits%").replacement(ZonePractice.getMiniMessage().deserialize((overAllHits < 0 ? "" : "")).append(Component.text(overAllHits))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%hits%").replacement(String.valueOf(playerHits)).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%enemyHits%").replacement(String.valueOf(enemyHits)).build()); - break; - case BEDWARS: - case FIREBALL_FIGHT: - case MLG_RUSH: - component = component - .replaceText(TextReplacementConfig.builder().matchLiteral("%playerBedStatus%").replacement(ZonePractice.getMiniMessage().deserialize(Objects.requireNonNull(round != null && round.getBedStatus().get(duel.getTeam(player)) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%enemyBedStatus%").replacement(ZonePractice.getMiniMessage().deserialize(Objects.requireNonNull(round != null && round.getBedStatus().get(duel.getTeam(enemy)) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))).build()); - break; - } - - sidebar.add(component); - } - break; - case PARTY_FFA: - PartyFFA partyFFA = (PartyFFA) match; - - for (String line : config.getStringList(path)) { - Component component = AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), partyFFA); - - if (ladderType == LadderType.BOXING) { - for (int i = 1; i <= 3; i++) { - Player topPlayer = MatchUtil.getBoxingTopPlayer(partyFFA, i); - Component playerName = topPlayer != null - ? displayName(topPlayer) - : ZonePractice.getMiniMessage().deserialize("N/A"); - Component playerHits = topPlayer != null ? Component.text(match.getCurrentStat(topPlayer).getHit()) : ZonePractice.getMiniMessage().deserialize("N/A"); - - component = component - .replaceText(TextReplacementConfig.builder().matchLiteral("%player" + i + "boxing%").replacement(playerName).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%player" + i + "boxingHits%").replacement(playerHits).build()); - } - } - - sidebar.add(component); - } - break; - case PARTY_SPLIT: - PartySplit partySplit = (PartySplit) match; - round = partySplit.getCurrentRound(); - - for (String line : config.getStringList(path)) { - Component component = AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), partySplit); - - component = switch (ladderType) { - case BOXING -> component - .replaceText(TextReplacementConfig.builder().matchLiteral("%team1boxingHits%").replacement(String.valueOf(Boxing.getTeamBoxingStrokes(match, partySplit.getTeamPlayers(TeamEnum.TEAM1)))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%team2boxingHits%").replacement(String.valueOf(Boxing.getTeamBoxingStrokes(match, partySplit.getTeamPlayers(TeamEnum.TEAM2)))).build()); - case BEDWARS, FIREBALL_FIGHT, MLG_RUSH -> component - .replaceText(TextReplacementConfig.builder().matchLiteral("%team1BedStatus%").replacement(ZonePractice.getMiniMessage().deserialize(Objects.requireNonNull(round != null && round.getBedStatus().get(TeamEnum.TEAM1) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%team2BedStatus%").replacement(ZonePractice.getMiniMessage().deserialize(Objects.requireNonNull(round != null && round.getBedStatus().get(TeamEnum.TEAM2) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))).build()); - default -> component; - }; - - sidebar.add(component); - } - break; - case PARTY_VS_PARTY: - PartyVsParty partyVsParty = (PartyVsParty) match; - round = partyVsParty.getCurrentRound(); - - TeamEnum team = partyVsParty.getTeam(player); - TeamEnum enemyTeam = TeamUtil.getOppositeTeam(team); - - for (String line : config.getStringList(path)) { - Component component = AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), partyVsParty); - - component = switch (ladderType) { - case BOXING -> component - .replaceText(TextReplacementConfig.builder().matchLiteral("%partyTeamBoxingHits%").replacement(String.valueOf(Boxing.getTeamBoxingStrokes(match, partyVsParty.getTeamPlayers(team)))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%enemyTeamBoxingHits%").replacement(String.valueOf(Boxing.getTeamBoxingStrokes(match, partyVsParty.getTeamPlayers(enemyTeam)))).build()); - case BEDWARS, FIREBALL_FIGHT, MLG_RUSH -> component - .replaceText(TextReplacementConfig.builder().matchLiteral("%partyTeamBedStatus%").replacement(Objects.requireNonNull(round != null && round.getBedStatus().get(team) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED"))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%enemyTeamBedStatus%").replacement(Objects.requireNonNull(round != null && round.getBedStatus().get(enemyTeam) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED"))).build()); - default -> component; - }; - - sidebar.add(component); - } - break; - } - } else { - for (String line : config.getStringList("MATCH." + match.getType().name())) { - sidebar.add(AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), match)); - } - } + } + + private void buildMatchLines(Player player, YamlConfiguration config, List sidebar) { + Match match = MatchManager.getInstance().getLiveMatchByPlayer(player); + if (match == null) return; + + Ladder ladder = match.getLadder(); + LadderType ladderType = ladder.getType(); + + String path = "MATCH.LADDER." + ladder.getName().toUpperCase() + "." + match.getType().name(); + List configLines = config.getStringList(path); + boolean useLadderSpecificConfig = config.isList(path) && !configLines.isEmpty(); + + if (useLadderSpecificConfig) { + switch (match.getType()) { + case DUEL -> buildDuelMatchLines(player, config, sidebar, match, ladderType); + case PARTY_FFA -> buildPartyFFAMatchLines(player, config, sidebar, match, ladderType); + case PARTY_SPLIT -> buildPartySplitMatchLines(player, config, sidebar, match, ladderType); + case PARTY_VS_PARTY -> buildPartyVsPartyMatchLines(player, config, sidebar, match, ladderType); } - } else if (profile.getStatus().equals(ProfileStatus.FFA)) { - FFA ffa = FFAManager.getInstance().getFFAByPlayer(player); - if (ffa != null) { - if (ffa.getBuildRollback() != null) { - for (String line : config.getStringList("FFA.GAME.BUILD")) { - Component component = AdapterUtil.replaceFFAPlaceholders(player, PAPIUtil.runThroughFormat(player, line), ffa); - sidebar.add(component); - } - } else { - for (String line : config.getStringList("FFA.GAME.NON-BUILD")) { - Component component = AdapterUtil.replaceFFAPlaceholders(player, PAPIUtil.runThroughFormat(player, line), ffa); - sidebar.add(component); - } + } else { + for (String line : config.getStringList("MATCH." + match.getType().name())) { + sidebar.add(AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), match)); + } + } + } + + private void buildDuelMatchLines(Player player, YamlConfiguration config, List sidebar, Match match, LadderType ladderType) { + Duel duel = (Duel) match; + Round round = duel.getCurrentRound(); + Player enemy = duel.getOppositePlayer(player); + + for (String line : config.getStringList("MATCH.LADDER." + match.getLadder().getName().toUpperCase() + "." + match.getType().name())) { + Component component = AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), duel); + + switch (ladderType) { + case BOXING: + int playerHits = match.getCurrentStat(player) != null ? match.getCurrentStat(player).getHit() : 0; + int enemyHits = match.getCurrentStat(enemy) != null ? match.getCurrentStat(enemy).getHit() : 0; + int overAllHits = playerHits - enemyHits; + + component = component + .replaceText(TextReplacementConfig.builder().matchLiteral("%overAllHits%").replacement(ZonePractice.getMiniMessage().deserialize((overAllHits < 0 ? "" : "")).append(Component.text(overAllHits))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%hits%").replacement(String.valueOf(playerHits)).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%enemyHits%").replacement(String.valueOf(enemyHits)).build()); + break; + case BEDWARS: + case FIREBALL_FIGHT: + case MLG_RUSH: + component = component + .replaceText(TextReplacementConfig.builder().matchLiteral("%playerBedStatus%").replacement(ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(Objects.requireNonNull(round != null && round.getBedStatus().get(duel.getTeam(player)) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED"))))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%enemyBedStatus%").replacement(ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(Objects.requireNonNull(round != null && round.getBedStatus().get(duel.getTeam(enemy)) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED"))))).build()); + break; + } + + sidebar.add(component); + } + } + + private void buildPartyFFAMatchLines(Player player, YamlConfiguration config, List sidebar, Match match, LadderType ladderType) { + PartyFFA partyFFA = (PartyFFA) match; + + for (String line : config.getStringList("MATCH.LADDER." + match.getLadder().getName().toUpperCase() + "." + match.getType().name())) { + Component component = AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), partyFFA); + + if (ladderType == LadderType.BOXING) { + for (int i = 1; i <= 3; i++) { + Player topPlayer = MatchUtil.getBoxingTopPlayer(partyFFA, i); + Component playerName = topPlayer != null + ? displayName(topPlayer) + : ZonePractice.getMiniMessage().deserialize("N/A"); + Component playerHits = topPlayer != null ? Component.text(match.getCurrentStat(topPlayer).getHit()) : ZonePractice.getMiniMessage().deserialize("N/A"); + + component = component + .replaceText(TextReplacementConfig.builder().matchLiteral("%player" + i + "boxing%").replacement(playerName).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%player" + i + "boxingHits%").replacement(playerHits).build()); } } - } else if (profile.getStatus().equals(ProfileStatus.EVENT)) { - Event event = EventManager.getInstance().getEventByPlayer(player); - if (event != null) { - String path = "EVENT." + event.getType().name().toUpperCase(); - switch (event.getType()) { - case LMS: - LMS lms = (LMS) event; + sidebar.add(component); + } + } - for (String line : config.getStringList(path)) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(lms.getStartPlayerCount())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(lms.getPlayers().size())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%duration%").replacement(lms.getDurationRunnable().getFormattedTime()).build()); + private void buildPartySplitMatchLines(Player player, YamlConfiguration config, List sidebar, Match match, LadderType ladderType) { + PartySplit partySplit = (PartySplit) match; + Round round = partySplit.getCurrentRound(); - sidebar.add(component); - } - break; - case OITC: - OITC oitc = (OITC) event; - Player highestPointPlayer = oitc.getHighestPointPlayer(); - Component topPlayerName = highestPointPlayer != null ? displayName(highestPointPlayer) : ZonePractice.getMiniMessage().deserialize("N/A"); - String topPlayerScore = highestPointPlayer != null ? String.valueOf(oitc.getPlayerPoints().get(highestPointPlayer)) : "0"; - - for (String line : config.getStringList(path)) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().matchLiteral("%topPlayer%").replacement(topPlayerName).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%topScore%").replacement(topPlayerScore).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(oitc.getPlayerPoints().size())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%lives%").replacement(String.valueOf(oitc.getPlayerLives().get(player))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(oitc.getPlayers().size())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%duration%").replacement(oitc.getDurationRunnable().getFormattedTime()).build()); - - sidebar.add(component); - } + for (String line : config.getStringList("MATCH.LADDER." + match.getLadder().getName().toUpperCase() + "." + match.getType().name())) { + Component component = AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), partySplit); - break; - case TNTTAG: - TNTTag tntTag = (TNTTag) event; + component = switch (ladderType) { + case BOXING -> component + .replaceText(TextReplacementConfig.builder().matchLiteral("%team1boxingHits%").replacement(String.valueOf(Boxing.getTeamBoxingStrokes(match, partySplit.getTeamPlayers(TeamEnum.TEAM1)))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%team2boxingHits%").replacement(String.valueOf(Boxing.getTeamBoxingStrokes(match, partySplit.getTeamPlayers(TeamEnum.TEAM2)))).build()); + case BEDWARS, FIREBALL_FIGHT, MLG_RUSH -> component + .replaceText(TextReplacementConfig.builder().matchLiteral("%team1BedStatus%").replacement(ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(Objects.requireNonNull(round != null && round.getBedStatus().get(TeamEnum.TEAM1) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED"))))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%team2BedStatus%").replacement(ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(Objects.requireNonNull(round != null && round.getBedStatus().get(TeamEnum.TEAM2) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED"))))).build()); + default -> component; + }; - for (String line : config.getStringList(path)) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().matchLiteral("%explosionTime%").replacement(tntTag.getDurationRunnable() != null ? String.valueOf(tntTag.getDurationRunnable().getSeconds()) : "0").build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(tntTag.getPlayers().size())).build()); + sidebar.add(component); + } + } - sidebar.add(component); - } - break; - case BRACKETS: - case SUMO: - DuelEvent duelEvent = (DuelEvent) event; - - DuelFight bracketFight = duelEvent.getFight(player); - if (bracketFight != null) { - for (String line : config.getStringList(path)) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().matchLiteral("%enemy%").replacement(displayName(bracketFight.getOtherPlayer(player))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(duelEvent.getStartPlayerCount())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(duelEvent.getPlayers().size())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%timeLeft%").replacement(duelEvent.getDurationRunnable() != null ? duelEvent.getDurationRunnable().getFormattedTime() : "0").build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%round%").replacement(String.valueOf(duelEvent.getRound())).build()); - - sidebar.add(component); - } - } else { - for (String line : config.getStringList("SPECTATE." + path)) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(duelEvent.getStartPlayerCount())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(duelEvent.getPlayers().size())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%timeLeft%").replacement(duelEvent.getDurationRunnable() != null ? duelEvent.getDurationRunnable().getFormattedTime() : "0").build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%round%").replacement(String.valueOf(duelEvent.getRound())).build()); - - sidebar.add(component); - } - } - break; - case SPLEGG: - Splegg splegg = (Splegg) event; - - for (String line : config.getStringList(path)) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(splegg.getStartPlayerCount())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(splegg.getPlayers().size())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%timeLeft%").replacement(splegg.getDurationRunnable() != null ? splegg.getDurationRunnable().getFormattedTime() : "0").build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%firedEggs%").replacement(String.valueOf(splegg.getShotEggs().get(player))).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%brokenBlocks%").replacement(String.valueOf(splegg.getShotBlocks().get(player))).build()); - - sidebar.add(component); - } - break; - case JUGGERNAUT: - Juggernaut juggernaut = (Juggernaut) event; + private void buildPartyVsPartyMatchLines(Player player, YamlConfiguration config, List sidebar, Match match, LadderType ladderType) { + PartyVsParty partyVsParty = (PartyVsParty) match; + Round round = partyVsParty.getCurrentRound(); + TeamEnum team = partyVsParty.getTeam(player); + TeamEnum enemyTeam = TeamUtil.getOppositeTeam(team); + + for (String line : config.getStringList("MATCH.LADDER." + match.getLadder().getName().toUpperCase() + "." + match.getType().name())) { + Component component = AdapterUtil.replaceMatchPlaceholders(player, PAPIUtil.runThroughFormat(player, line), partyVsParty); + + component = switch (ladderType) { + case BOXING -> component + .replaceText(TextReplacementConfig.builder().matchLiteral("%partyTeamBoxingHits%").replacement(String.valueOf(Boxing.getTeamBoxingStrokes(match, partyVsParty.getTeamPlayers(team)))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%enemyTeamBoxingHits%").replacement(String.valueOf(Boxing.getTeamBoxingStrokes(match, partyVsParty.getTeamPlayers(enemyTeam)))).build()); + case BEDWARS, FIREBALL_FIGHT, MLG_RUSH -> component + .replaceText(TextReplacementConfig.builder().matchLiteral("%partyTeamBedStatus%").replacement(Objects.requireNonNull(round != null && round.getBedStatus().get(team) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED"))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%enemyTeamBedStatus%").replacement(Objects.requireNonNull(round != null && round.getBedStatus().get(enemyTeam) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED"))).build()); + default -> component; + }; + + sidebar.add(component); + } + } - for (String line : config.getStringList(path)) { - Component component = PAPIUtil.runThroughFormat(player, line) - .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(juggernaut.getStartPlayerCount())).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(juggernaut.getPlayers().size() - 1)).build()) - .replaceText(TextReplacementConfig.builder().matchLiteral("%duration%").replacement(juggernaut.getDurationRunnable().getFormattedTime()).build()); + private void buildFFALines(Player player, YamlConfiguration config, List sidebar) { + FFA ffa = FFAManager.getInstance().getFFAByPlayer(player); + if (ffa == null) return; - sidebar.add(component); - } - break; + if (ffa.getBuildRollback() != null) { + for (String line : config.getStringList("FFA.GAME.BUILD")) { + sidebar.add(AdapterUtil.replaceFFAPlaceholders(player, PAPIUtil.runThroughFormat(player, line), ffa)); + } + } else { + for (String line : config.getStringList("FFA.GAME.NON-BUILD")) { + sidebar.add(AdapterUtil.replaceFFAPlaceholders(player, PAPIUtil.runThroughFormat(player, line), ffa)); + } + } + } + + private void buildEventLines(Player player, YamlConfiguration config, List sidebar) { + Event event = EventManager.getInstance().getEventByPlayer(player); + if (event == null) return; + + String path = "EVENT." + event.getType().name().toUpperCase(); + switch (event.getType()) { + case LMS -> { + LMS lms = (LMS) event; + for (String line : config.getStringList(path)) { + sidebar.add(PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(lms.getStartPlayerCount())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(lms.getPlayers().size())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%duration%").replacement(lms.getDurationRunnable().getFormattedTime()).build())); } } - } else if (profile.getStatus().equals(ProfileStatus.SPECTATE)) { - Spectatable spectatable = SpectatorManager.getInstance().getSpectators().get(player); - - if (spectatable instanceof Match match) { - LadderType ladderType = match.getLadder().getType(); - Round round; - - String path = "SPECTATE.MATCH.LADDER." + match.getLadder().getName().toUpperCase() + "." + match.getType().name(); - // Check if ladder-specific config exists AND is non-empty, otherwise use generic match type config - List configLines = config.getStringList(path); - boolean useLadderSpecificConfig = config.isList(path) && !configLines.isEmpty(); - - if (useLadderSpecificConfig) { - switch (match.getType()) { - case DUEL: - Duel duel = (Duel) match; - round = duel.getCurrentRound(); - - for (String line : config.getStringList(path)) { - switch (ladderType) { - case BOXING: - Statistic player1stats = match.getCurrentStat(duel.getPlayer1()); - Statistic player2stats = match.getCurrentStat(duel.getPlayer2()); - line = line - .replace("%player1hits%", String.valueOf(player1stats != null ? player1stats.getHit() : 0)) - .replace("%player2hits%", String.valueOf(player2stats != null ? player2stats.getHit() : 0)); - break; - case BEDWARS: - case FIREBALL_FIGHT: - case MLG_RUSH: - line = line - .replace("%player1BedStatus%", (Objects.requireNonNull(round != null && round.getBedStatus().get(duel.getTeam(duel.getPlayer1())) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))) - .replace("%player2BedStatus%", (Objects.requireNonNull(round != null && round.getBedStatus().get(duel.getTeam(duel.getPlayer2())) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))); - break; - } - - sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), duel)); - } - break; - case PARTY_FFA: - PartyFFA partyFFA = (PartyFFA) match; - - for (String line : config.getStringList(path)) { - if (Objects.requireNonNull(ladderType) == LadderType.BOXING) { - Player player1 = MatchUtil.getBoxingTopPlayer(partyFFA, 1); - if (player1 != null) { - line = line - .replace("%player1boxing%", ZonePractice.getMiniMessage().serialize(displayName(player1))) - .replace("%player1boxingHits%", String.valueOf(match.getCurrentStat(player1).getHit())); - } else { - line = line - .replace("%player1boxing%", "N/A") - .replace("%player1boxingHits%", "N/A"); - } - - Player player2 = MatchUtil.getBoxingTopPlayer(partyFFA, 2); - if (player2 != null) { - line = line - .replace("%player2boxing%", ZonePractice.getMiniMessage().serialize(displayName(player2))) - .replace("%player2boxingHits%", String.valueOf(match.getCurrentStat(player2).getHit())); - } else { - line = line - .replace("%player2boxing%", "N/A") - .replace("%player2boxingHits%", "N/A"); - } - - Player player3 = MatchUtil.getBoxingTopPlayer(partyFFA, 3); - if (player3 != null) { - line = line - .replace("%player3boxing%", ZonePractice.getMiniMessage().serialize(displayName(player3))) - .replace("%player3boxingHits%", String.valueOf(match.getCurrentStat(player3).getHit())); - } else { - line = line - .replace("%player3boxing%", "N/A") - .replace("%player3boxingHits%", "N/A"); - } - } - - sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), partyFFA)); - } - break; - case PARTY_SPLIT: - PartySplit partySplit = (PartySplit) match; - round = partySplit.getCurrentRound(); - - for (String line : config.getStringList(path)) { - switch (ladderType) { - case BOXING: - line = line - .replace("%team1boxingHits%", String.valueOf(Boxing.getTeamBoxingStrokes(match, partySplit.getTeamPlayers(TeamEnum.TEAM1)))) - .replace("%team2boxingHits%", String.valueOf(Boxing.getTeamBoxingStrokes(match, partySplit.getTeamPlayers(TeamEnum.TEAM2)))); - break; - case BEDWARS: - case FIREBALL_FIGHT: - case MLG_RUSH: - line = line - .replace("%team1BedStatus%", (Objects.requireNonNull(round != null && round.getBedStatus().get(TeamEnum.TEAM1) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))) - .replace("%team2BedStatus%", (Objects.requireNonNull(round != null && round.getBedStatus().get(TeamEnum.TEAM2) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))); - break; - } - - sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), partySplit)); - } - break; - case PARTY_VS_PARTY: - PartyVsParty partyVsParty = (PartyVsParty) match; - round = partyVsParty.getCurrentRound(); - - for (String line : config.getStringList(path)) { - switch (ladderType) { - case BOXING: - line = line - .replace("%team1boxingHits%", String.valueOf(Boxing.getTeamBoxingStrokes(match, partyVsParty.getTeamPlayers(TeamEnum.TEAM1)))) - .replace("%team2boxingHits%", String.valueOf(Boxing.getTeamBoxingStrokes(match, partyVsParty.getTeamPlayers(TeamEnum.TEAM2)))); - break; - case BEDWARS: - case FIREBALL_FIGHT: - case MLG_RUSH: - line = line - .replace("%team1BedStatus%", (Objects.requireNonNull(round.getBedStatus().get(TeamEnum.TEAM1) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))) - .replace("%team2BedStatus%", (Objects.requireNonNull(round.getBedStatus().get(TeamEnum.TEAM2) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))); - break; - } - - sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), partyVsParty)); - } - break; - } - } else { - for (String line : config.getStringList("SPECTATE.MATCH." + match.getType().name())) { - sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), match)); - } + case OITC -> { + OITC oitc = (OITC) event; + Player highestPointPlayer = oitc.getHighestPointPlayer(); + Component topPlayerName = highestPointPlayer != null ? displayName(highestPointPlayer) : ZonePractice.getMiniMessage().deserialize("N/A"); + String topPlayerScore = highestPointPlayer != null ? String.valueOf(oitc.getPlayerPoints().get(highestPointPlayer)) : "0"; + + for (String line : config.getStringList(path)) { + sidebar.add(PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().matchLiteral("%topPlayer%").replacement(topPlayerName).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%topScore%").replacement(topPlayerScore).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(oitc.getPlayerPoints().size())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%lives%").replacement(String.valueOf(oitc.getPlayerLives().get(player))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(oitc.getPlayers().size())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%duration%").replacement(oitc.getDurationRunnable().getFormattedTime()).build())); + } + } + case TNTTAG -> { + TNTTag tntTag = (TNTTag) event; + for (String line : config.getStringList(path)) { + sidebar.add(PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().matchLiteral("%explosionTime%").replacement(tntTag.getDurationRunnable() != null ? String.valueOf(tntTag.getDurationRunnable().getSeconds()) : "0").build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(tntTag.getPlayers().size())).build())); } - } else if (spectatable instanceof FFA ffa) { - if (ffa.getBuildRollback() != null) { - for (String line : config.getStringList("FFA.SPECTATE.BUILD")) { - sidebar.add(AdapterUtil.replaceFFASpecPlaceholders(PAPIUtil.runThroughFormat(player, line), ffa)); + } + case BRACKETS, SUMO -> { + DuelEvent duelEvent = (DuelEvent) event; + DuelFight bracketFight = duelEvent.getFight(player); + if (bracketFight != null) { + for (String line : config.getStringList(path)) { + sidebar.add(PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().matchLiteral("%enemy%").replacement(displayName(bracketFight.getOtherPlayer(player))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(duelEvent.getStartPlayerCount())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(duelEvent.getPlayers().size())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%timeLeft%").replacement(duelEvent.getDurationRunnable() != null ? duelEvent.getDurationRunnable().getFormattedTime() : "0").build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%round%").replacement(String.valueOf(duelEvent.getRound())).build())); } } else { - for (String line : config.getStringList("FFA.SPECTATE.NON-BUILD")) { - sidebar.add(AdapterUtil.replaceFFASpecPlaceholders(PAPIUtil.runThroughFormat(player, line), ffa)); + for (String line : config.getStringList("SPECTATE." + path)) { + sidebar.add(PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(duelEvent.getStartPlayerCount())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(duelEvent.getPlayers().size())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%timeLeft%").replacement(duelEvent.getDurationRunnable() != null ? duelEvent.getDurationRunnable().getFormattedTime() : "0").build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%round%").replacement(String.valueOf(duelEvent.getRound())).build())); } } - } else if (spectatable instanceof Event event) { - String path = "SPECTATE.EVENT." + event.getType().name().toUpperCase(); - switch (event.getType()) { - case LMS: - LMS lms = (LMS) event; - - for (String line : config.getStringList(path)) { - line = line - .replace("%players%", String.valueOf(lms.getStartPlayerCount())) - .replace("%alivePlayers%", String.valueOf(lms.getPlayers().size())) - .replace("%duration%", lms.getDurationRunnable().getFormattedTime()); - - sidebar.add(PAPIUtil.runThroughFormat(player, line)); - } - break; - case OITC: - OITC oitc = (OITC) event; - Player highestPointPlayer = oitc.getHighestPointPlayer(); - String topPlayerName = highestPointPlayer != null - ? ZonePractice.getMiniMessage().serialize(displayName(highestPointPlayer)) - : "N/A"; - String topPlayerScore = highestPointPlayer != null - ? String.valueOf(oitc.getPlayerPoints().get(highestPointPlayer)) - : "0"; - - for (String line : config.getStringList(path)) { - line = line - .replace("%topPlayer%", topPlayerName) - .replace("%topScore%", topPlayerScore) - .replace("%players%", String.valueOf(oitc.getPlayerPoints().size())) - .replace("%alivePlayers%", String.valueOf(oitc.getPlayers().size())) - .replace("%duration%", oitc.getDurationRunnable().getFormattedTime()); - - sidebar.add(PAPIUtil.runThroughFormat(player, line)); - } + } + case SPLEGG -> { + Splegg splegg = (Splegg) event; + for (String line : config.getStringList(path)) { + sidebar.add(PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(splegg.getStartPlayerCount())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(splegg.getPlayers().size())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%timeLeft%").replacement(splegg.getDurationRunnable() != null ? splegg.getDurationRunnable().getFormattedTime() : "0").build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%firedEggs%").replacement(String.valueOf(splegg.getShotEggs().get(player))).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%brokenBlocks%").replacement(String.valueOf(splegg.getShotBlocks().get(player))).build())); + } + } + case JUGGERNAUT -> { + Juggernaut juggernaut = (Juggernaut) event; + for (String line : config.getStringList(path)) { + sidebar.add(PAPIUtil.runThroughFormat(player, line) + .replaceText(TextReplacementConfig.builder().matchLiteral("%players%").replacement(String.valueOf(juggernaut.getStartPlayerCount())).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%alivePlayers%").replacement(String.valueOf(juggernaut.getPlayers().size() - 1)).build()) + .replaceText(TextReplacementConfig.builder().matchLiteral("%duration%").replacement(juggernaut.getDurationRunnable().getFormattedTime()).build())); + } + } + } + } - break; - case TNTTAG: - TNTTag tntTag = (TNTTag) event; + private void buildSpectateLines(Player player, YamlConfiguration config, List sidebar) { + Spectatable spectatable = SpectatorManager.getInstance().getSpectators().get(player); + if (spectatable == null) return; - for (String line : config.getStringList(path)) { - line = line - .replace("%explosionTime%", (tntTag.getDurationRunnable() != null ? String.valueOf(tntTag.getDurationRunnable().getSeconds()) : "0")) - .replace("%alivePlayers%", String.valueOf(tntTag.getPlayers().size())); + if (spectatable instanceof Match match) { + buildSpectateMatchLines(player, config, sidebar, match); + } else if (spectatable instanceof FFA ffa) { + if (ffa.getBuildRollback() != null) { + for (String line : config.getStringList("FFA.SPECTATE.BUILD")) { + sidebar.add(AdapterUtil.replaceFFASpecPlaceholders(PAPIUtil.runThroughFormat(player, line), ffa)); + } + } else { + for (String line : config.getStringList("FFA.SPECTATE.NON-BUILD")) { + sidebar.add(AdapterUtil.replaceFFASpecPlaceholders(PAPIUtil.runThroughFormat(player, line), ffa)); + } + } + } else if (spectatable instanceof Event event) { + buildSpectateEventLines(player, config, sidebar, event); + } + } - sidebar.add(PAPIUtil.runThroughFormat(player, line)); - } - break; - case BRACKETS: - case SUMO: - DuelEvent duelEvent = (DuelEvent) event; - - for (String line : config.getStringList(path)) { - line = line - .replace("%players%", String.valueOf(duelEvent.getStartPlayerCount())) - .replace("%alivePlayers%", String.valueOf(duelEvent.getPlayers().size())) - .replace("%timeLeft%", (duelEvent.getDurationRunnable() != null ? duelEvent.getDurationRunnable().getFormattedTime() : "0")) - .replace("%round%", String.valueOf(duelEvent.getRound())); - - sidebar.add(PAPIUtil.runThroughFormat(player, line)); + private void buildSpectateMatchLines(Player player, YamlConfiguration config, List sidebar, Match match) { + Round round; + String path = "SPECTATE.MATCH.LADDER." + match.getLadder().getName().toUpperCase() + "." + match.getType().name(); + List configLines = config.getStringList(path); + boolean useLadderSpecificConfig = config.isList(path) && !configLines.isEmpty(); + + if (useLadderSpecificConfig) { + switch (match.getType()) { + case DUEL -> { + Duel duel = (Duel) match; + round = duel.getCurrentRound(); + LadderType ladderType = match.getLadder().getType(); + + for (String line : config.getStringList(path)) { + switch (ladderType) { + case BOXING: + Statistic player1stats = match.getCurrentStat(duel.getPlayer1()); + Statistic player2stats = match.getCurrentStat(duel.getPlayer2()); + line = line + .replace("%player1hits%", String.valueOf(player1stats != null ? player1stats.getHit() : 0)) + .replace("%player2hits%", String.valueOf(player2stats != null ? player2stats.getHit() : 0)); + break; + case BEDWARS: + case FIREBALL_FIGHT: + case MLG_RUSH: + line = line + .replace("%player1BedStatus%", (Objects.requireNonNull(round != null && round.getBedStatus().get(duel.getTeam(duel.getPlayer1())) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))) + .replace("%player2BedStatus%", (Objects.requireNonNull(round != null && round.getBedStatus().get(duel.getTeam(duel.getPlayer2())) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))); + break; } - break; - case SPLEGG: - Splegg splegg = (Splegg) event; + sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), duel)); + } + } + case PARTY_FFA -> { + PartyFFA partyFFA = (PartyFFA) match; + LadderType ladderType = match.getLadder().getType(); + + for (String line : config.getStringList(path)) { + if (ladderType == LadderType.BOXING) { + Player player1 = MatchUtil.getBoxingTopPlayer(partyFFA, 1); + if (player1 != null) { + line = line + .replace("%player1boxing%", ZonePractice.getMiniMessage().serialize(displayName(player1))) + .replace("%player1boxingHits%", String.valueOf(match.getCurrentStat(player1).getHit())); + } else { + line = line + .replace("%player1boxing%", "N/A") + .replace("%player1boxingHits%", "N/A"); + } - for (String line : config.getStringList(path)) { - line = line - .replace("%players%", String.valueOf(splegg.getStartPlayerCount())) - .replace("%alivePlayers%", String.valueOf(splegg.getPlayers().size())) - .replace("%timeLeft%", (splegg.getDurationRunnable() != null ? splegg.getDurationRunnable().getFormattedTime() : "0")); + Player player2 = MatchUtil.getBoxingTopPlayer(partyFFA, 2); + if (player2 != null) { + line = line + .replace("%player2boxing%", ZonePractice.getMiniMessage().serialize(displayName(player2))) + .replace("%player2boxingHits%", String.valueOf(match.getCurrentStat(player2).getHit())); + } else { + line = line + .replace("%player2boxing%", "N/A") + .replace("%player2boxingHits%", "N/A"); + } - sidebar.add(PAPIUtil.runThroughFormat(player, line)); + Player player3 = MatchUtil.getBoxingTopPlayer(partyFFA, 3); + if (player3 != null) { + line = line + .replace("%player3boxing%", ZonePractice.getMiniMessage().serialize(displayName(player3))) + .replace("%player3boxingHits%", String.valueOf(match.getCurrentStat(player3).getHit())); + } else { + line = line + .replace("%player3boxing%", "N/A") + .replace("%player3boxingHits%", "N/A"); + } } - break; - case JUGGERNAUT: - Juggernaut juggernaut = (Juggernaut) event; - - for (String line : config.getStringList(path)) { - line = line - .replace("%players%", String.valueOf(juggernaut.getStartPlayerCount())) - .replace("%alivePlayers%", String.valueOf(juggernaut.getPlayers().size() - 1)) - .replace("%duration%", juggernaut.getDurationRunnable().getFormattedTime()); - - sidebar.add(PAPIUtil.runThroughFormat(player, line)); + sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), partyFFA)); + } + } + case PARTY_SPLIT -> { + PartySplit partySplit = (PartySplit) match; + round = partySplit.getCurrentRound(); + LadderType ladderType = match.getLadder().getType(); + + for (String line : config.getStringList(path)) { + switch (ladderType) { + case BOXING: + line = line + .replace("%team1boxingHits%", String.valueOf(Boxing.getTeamBoxingStrokes(match, partySplit.getTeamPlayers(TeamEnum.TEAM1)))) + .replace("%team2boxingHits%", String.valueOf(Boxing.getTeamBoxingStrokes(match, partySplit.getTeamPlayers(TeamEnum.TEAM2)))); + break; + case BEDWARS: + case FIREBALL_FIGHT: + case MLG_RUSH: + line = line + .replace("%team1BedStatus%", (Objects.requireNonNull(round != null && round.getBedStatus().get(TeamEnum.TEAM1) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))) + .replace("%team2BedStatus%", (Objects.requireNonNull(round != null && round.getBedStatus().get(TeamEnum.TEAM2) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))); + break; + } + sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), partySplit)); + } + } + case PARTY_VS_PARTY -> { + PartyVsParty partyVsParty = (PartyVsParty) match; + round = partyVsParty.getCurrentRound(); + LadderType ladderType = match.getLadder().getType(); + + for (String line : config.getStringList(path)) { + switch (ladderType) { + case BOXING: + line = line + .replace("%team1boxingHits%", String.valueOf(Boxing.getTeamBoxingStrokes(match, partyVsParty.getTeamPlayers(TeamEnum.TEAM1)))) + .replace("%team2boxingHits%", String.valueOf(Boxing.getTeamBoxingStrokes(match, partyVsParty.getTeamPlayers(TeamEnum.TEAM2)))); + break; + case BEDWARS: + case FIREBALL_FIGHT: + case MLG_RUSH: + line = line + .replace("%team1BedStatus%", (Objects.requireNonNull(round.getBedStatus().get(TeamEnum.TEAM1) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))) + .replace("%team2BedStatus%", (Objects.requireNonNull(round.getBedStatus().get(TeamEnum.TEAM2) ? config.getString("MATCH.BED-STATUS.NOT-DESTROYED") : config.getString("MATCH.BED-STATUS.DESTROYED")))); + break; } - break; + sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), partyVsParty)); + } + } + } + } else { + for (String line : config.getStringList("SPECTATE.MATCH." + match.getType().name())) { + sidebar.add(AdapterUtil.replaceMatchSpectatePlaceholders(PAPIUtil.runThroughFormat(player, line), match)); + } + } + } + + private void buildSpectateEventLines(Player player, YamlConfiguration config, List sidebar, Event event) { + String path = "SPECTATE.EVENT." + event.getType().name().toUpperCase(); + switch (event.getType()) { + case LMS -> { + LMS lms = (LMS) event; + for (String line : config.getStringList(path)) { + line = line + .replace("%players%", String.valueOf(lms.getStartPlayerCount())) + .replace("%alivePlayers%", String.valueOf(lms.getPlayers().size())) + .replace("%duration%", lms.getDurationRunnable().getFormattedTime()); + sidebar.add(PAPIUtil.runThroughFormat(player, line)); + } + } + case OITC -> { + OITC oitc = (OITC) event; + Player highestPointPlayer = oitc.getHighestPointPlayer(); + String topPlayerName = highestPointPlayer != null + ? ZonePractice.getMiniMessage().serialize(displayName(highestPointPlayer)) + : "N/A"; + String topPlayerScore = highestPointPlayer != null + ? String.valueOf(oitc.getPlayerPoints().get(highestPointPlayer)) + : "0"; + + for (String line : config.getStringList(path)) { + line = line + .replace("%topPlayer%", topPlayerName) + .replace("%topScore%", topPlayerScore) + .replace("%players%", String.valueOf(oitc.getPlayerPoints().size())) + .replace("%alivePlayers%", String.valueOf(oitc.getPlayers().size())) + .replace("%duration%", oitc.getDurationRunnable().getFormattedTime()); + sidebar.add(PAPIUtil.runThroughFormat(player, line)); + } + } + case TNTTAG -> { + TNTTag tntTag = (TNTTag) event; + for (String line : config.getStringList(path)) { + line = line + .replace("%explosionTime%", (tntTag.getDurationRunnable() != null ? String.valueOf(tntTag.getDurationRunnable().getSeconds()) : "0")) + .replace("%alivePlayers%", String.valueOf(tntTag.getPlayers().size())); + sidebar.add(PAPIUtil.runThroughFormat(player, line)); + } + } + case BRACKETS, SUMO -> { + DuelEvent duelEvent = (DuelEvent) event; + for (String line : config.getStringList(path)) { + line = line + .replace("%players%", String.valueOf(duelEvent.getStartPlayerCount())) + .replace("%alivePlayers%", String.valueOf(duelEvent.getPlayers().size())) + .replace("%timeLeft%", (duelEvent.getDurationRunnable() != null ? duelEvent.getDurationRunnable().getFormattedTime() : "0")) + .replace("%round%", String.valueOf(duelEvent.getRound())); + sidebar.add(PAPIUtil.runThroughFormat(player, line)); + } + } + case SPLEGG -> { + Splegg splegg = (Splegg) event; + for (String line : config.getStringList(path)) { + line = line + .replace("%players%", String.valueOf(splegg.getStartPlayerCount())) + .replace("%alivePlayers%", String.valueOf(splegg.getPlayers().size())) + .replace("%timeLeft%", (splegg.getDurationRunnable() != null ? splegg.getDurationRunnable().getFormattedTime() : "0")); + sidebar.add(PAPIUtil.runThroughFormat(player, line)); + } + } + case JUGGERNAUT -> { + Juggernaut juggernaut = (Juggernaut) event; + for (String line : config.getStringList(path)) { + line = line + .replace("%players%", String.valueOf(juggernaut.getStartPlayerCount())) + .replace("%alivePlayers%", String.valueOf(juggernaut.getPlayers().size() - 1)) + .replace("%duration%", juggernaut.getDurationRunnable().getFormattedTime()); + sidebar.add(PAPIUtil.runThroughFormat(player, line)); } } } + } + private void buildFooterLines(Player player, YamlConfiguration config, Profile profile, List sidebar) { Group group = profile.getGroup(); if (group != null && group.getSidebarExtensionRaw() != null && !group.getSidebarExtensionRaw().isEmpty()) { for (String rawLine : group.getSidebarExtensionRaw()) { @@ -709,8 +699,6 @@ public List getLines(Player player) { sidebar.add(PAPIUtil.runThroughFormat(player, line)); } } - - return sidebar; } } diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/CombatEvent.java b/core/src/main/java/dev/nandi0813/practice/telemetry/CombatEvent.java deleted file mode 100644 index 6e32502e3..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/CombatEvent.java +++ /dev/null @@ -1,49 +0,0 @@ -package dev.nandi0813.practice.telemetry; - -import org.json.JSONObject; - -/** - * Represents a granular time-series combat event during a match. - * Used for ML analytics, coaching reports, and playstyle detection. - */ -public record CombatEvent( - TelemetryEvent eventType, - long eventTs, - int eventSeq, - String actorUuid, - String targetUuid, - Double x, - Double y, - Double z, - Double distance, - Float deltaYaw, - Float deltaPitch, - Double damageAmount, - JSONObject meta -) { - - public JSONObject toJson() { - JSONObject json = new JSONObject(); - json.put("event_type", eventType.name()); - json.put("event_ts", eventTs); - json.put("event_seq", eventSeq); - json.put("actor_uuid", actorUuid); - putNullable(json, "target_uuid", targetUuid); - putNullable(json, "x", x); - putNullable(json, "y", y); - putNullable(json, "z", z); - putNullable(json, "distance", distance); - putNullable(json, "delta_yaw", deltaYaw); - putNullable(json, "delta_pitch", deltaPitch); - putNullable(json, "damage_amount", damageAmount); - if (meta != null && !meta.isEmpty()) { - json.put("meta", meta); - } - return json; - } - - private static void putNullable(JSONObject json, String key, Object value) { - json.put(key, value != null ? value : JSONObject.NULL); - } -} - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/MatchTelemetry.java b/core/src/main/java/dev/nandi0813/practice/telemetry/MatchTelemetry.java deleted file mode 100644 index 6c9c6b525..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/MatchTelemetry.java +++ /dev/null @@ -1,71 +0,0 @@ -package dev.nandi0813.practice.telemetry; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.util.List; - -public record MatchTelemetry( - int schemaVersion, - String matchId, - String matchType, - String ladder, - String arena, - boolean ranked, - int winsNeeded, - String serverId, - String pluginVersion, - String mcProtocolVersion, - long matchStartTs, - long matchEndTs, - long matchDurationMs, - String terminationReason, - List players, - List rounds, - List events, - int droppedEventCount, - long createdAtTs -) { - - public JSONObject toJson() { - JSONObject json = new JSONObject(); - json.put("schema_version", schemaVersion); - json.put("match_id", matchId); - json.put("match_type", matchType); - json.put("ladder", ladder); - json.put("arena", arena); - json.put("ranked", ranked); - json.put("wins_needed", winsNeeded); - json.put("server_id", serverId); - json.put("plugin_version", pluginVersion); - json.put("mc_protocol_version", mcProtocolVersion); - json.put("match_start_ts", matchStartTs); - json.put("match_end_ts", matchEndTs); - json.put("match_duration_ms", matchDurationMs); - json.put("termination_reason", terminationReason); - json.put("dropped_event_count", droppedEventCount); - json.put("created_at_ts", createdAtTs); - - JSONArray playersArray = new JSONArray(); - for (PlayerTelemetry player : players) { - playersArray.put(player.toJson()); - } - json.put("players", playersArray); - - JSONArray roundsArray = new JSONArray(); - for (RoundTelemetry round : rounds) { - roundsArray.put(round.toJson()); - } - json.put("rounds", roundsArray); - - JSONArray eventsArray = new JSONArray(); - for (CombatEvent event : events) { - eventsArray.put(event.toJson()); - } - json.put("events", eventsArray); - - return json; - } -} - - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/PlayerTelemetry.java b/core/src/main/java/dev/nandi0813/practice/telemetry/PlayerTelemetry.java deleted file mode 100644 index 032a2d5f8..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/PlayerTelemetry.java +++ /dev/null @@ -1,92 +0,0 @@ -package dev.nandi0813.practice.telemetry; - -import org.json.JSONObject; - -import java.util.UUID; - -public record PlayerTelemetry( - UUID playerUuid, - String playerUsername, - UUID opponentUuid, - String opponentUsername, - Integer eloBefore, - Integer eloAfter, - Integer eloDelta, - Long queueWaitMs, - Integer queueSearchRangeStart, - Integer queueSearchRangeEnd, - boolean winner, - int roundsWon, - int kills, - int deaths, - int hitsLanded, - int hitsTaken, - int longestCombo, - double avgCps, - int potionThrown, - int potionMissed, - int potionAccuracy, - double reachAvg, - double reachMax, - int sprintResetCount, - double aimDeltaYawAvg, - double aimDeltaPitchAvg, - double damageDealt, - double damageTaken, - Integer pingAvg, - Integer pingP95, - double forwardMovementRatio, - double retreatingMovementRatio, - int sprintResetFrequency, - int blockPlaceCount, - int healingItemUsageCount -) { - - public JSONObject toJson() { - JSONObject json = new JSONObject(); - json.put("player_uuid", playerUuid.toString()); - json.put("player_username", playerUsername != null ? playerUsername : JSONObject.NULL); - putNullableUuid(json, "opponent_uuid", opponentUuid); - json.put("opponent_username", opponentUsername != null ? opponentUsername : JSONObject.NULL); - putNullable(json, "elo_before", eloBefore); - putNullable(json, "elo_after", eloAfter); - putNullable(json, "elo_delta", eloDelta); - json.put("queue_wait_ms", queueWaitMs != null ? queueWaitMs : 0L); - json.put("queue_search_range_start", queueSearchRangeStart != null ? queueSearchRangeStart : 0); - json.put("queue_search_range_end", queueSearchRangeEnd != null ? queueSearchRangeEnd : 0); - json.put("winner", winner); - json.put("rounds_won", roundsWon); - json.put("kills", kills); - json.put("deaths", deaths); - json.put("hits_landed", hitsLanded); - json.put("hits_taken", hitsTaken); - json.put("longest_combo", longestCombo); - json.put("avg_cps", avgCps); - json.put("potion_thrown", potionThrown); - json.put("potion_missed", potionMissed); - json.put("potion_accuracy", potionAccuracy); - json.put("reach_avg", reachAvg); - json.put("reach_max", reachMax); - json.put("sprint_reset_count", sprintResetCount); - json.put("aim_delta_yaw_avg", aimDeltaYawAvg); - json.put("aim_delta_pitch_avg", aimDeltaPitchAvg); - json.put("damage_dealt", damageDealt); - json.put("damage_taken", damageTaken); - putNullable(json, "ping_avg", pingAvg); - putNullable(json, "ping_p95", pingP95); - json.put("forward_movement_ratio", forwardMovementRatio); - json.put("retreating_movement_ratio", retreatingMovementRatio); - json.put("sprint_reset_frequency", sprintResetFrequency); - json.put("block_place_count", blockPlaceCount); - json.put("healing_item_usage_count", healingItemUsageCount); - return json; - } - - private static void putNullable(JSONObject json, String key, Object value) { - json.put(key, value != null ? value : JSONObject.NULL); - } - - private static void putNullableUuid(JSONObject json, String key, UUID value) { - json.put(key, value != null ? value.toString() : JSONObject.NULL); - } -} diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/RoundTelemetry.java b/core/src/main/java/dev/nandi0813/practice/telemetry/RoundTelemetry.java deleted file mode 100644 index 605c31ca0..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/RoundTelemetry.java +++ /dev/null @@ -1,63 +0,0 @@ -package dev.nandi0813.practice.telemetry; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.util.List; -import java.util.UUID; - -public record RoundTelemetry( - int roundNumber, - long roundStartTs, - long roundEndTs, - long roundDurationMs, - UUID roundWinnerUuid, - List playerRoundStats -) { - - public JSONObject toJson() { - JSONObject json = new JSONObject(); - json.put("round_number", roundNumber); - json.put("round_start_ts", roundStartTs); - json.put("round_end_ts", roundEndTs); - json.put("round_duration_ms", roundDurationMs); - json.put("round_winner_uuid", roundWinnerUuid != null ? roundWinnerUuid.toString() : JSONObject.NULL); - - JSONArray players = new JSONArray(); - for (PlayerRoundTelemetry playerRoundStat : playerRoundStats) { - players.put(playerRoundStat.toJson()); - } - json.put("player_round_stats", players); - return json; - } - - public record PlayerRoundTelemetry( - UUID playerUuid, - int hitsLanded, - int hitsTaken, - int kills, - int deaths, - int potionThrown, - int potionMissed, - int potionAccuracy, - int longestCombo, - double avgCps - ) { - - public JSONObject toJson() { - JSONObject json = new JSONObject(); - json.put("player_uuid", playerUuid.toString()); - json.put("hits_landed", hitsLanded); - json.put("hits_taken", hitsTaken); - json.put("kills", kills); - json.put("deaths", deaths); - json.put("potion_thrown", potionThrown); - json.put("potion_missed", potionMissed); - json.put("potion_accuracy", potionAccuracy); - json.put("longest_combo", longestCombo); - json.put("avg_cps", avgCps); - return json; - } - } -} - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/ServerFingerprintUtil.java b/core/src/main/java/dev/nandi0813/practice/telemetry/ServerFingerprintUtil.java deleted file mode 100644 index e8cd7c8bc..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/ServerFingerprintUtil.java +++ /dev/null @@ -1,91 +0,0 @@ -package dev.nandi0813.practice.telemetry; - -import java.net.NetworkInterface; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.util.*; - -public enum ServerFingerprintUtil { - ; - - private static final String FALLBACK_SERVER_ID = "unknown-host"; - private static volatile String cachedServerId; - - public static String getServerId() { - String current = cachedServerId; - if (current != null && !current.isBlank()) { - return current; - } - - String resolved = resolveServerIdFingerprint(); - cachedServerId = resolved; - return resolved; - } - - private static String resolveServerIdFingerprint() { - List macs = collectMacAddresses(); - if (!macs.isEmpty()) { - macs.sort(String::compareTo); - String joined = String.join("|", macs); - return "macsha256:" + sha256Hex(joined); - } - - String host = System.getenv("HOSTNAME"); - if (host == null || host.isBlank()) { - host = System.getProperty("user.name", "unknown") + "@" + System.getProperty("os.name", "unknown"); - } - return "hostuuid:" + UUID.nameUUIDFromBytes(host.getBytes(StandardCharsets.UTF_8)); - } - - private static List collectMacAddresses() { - List result = new ArrayList<>(); - try { - Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); - while (interfaces.hasMoreElements()) { - NetworkInterface networkInterface = interfaces.nextElement(); - if (!networkInterface.isUp() || networkInterface.isLoopback() || networkInterface.isVirtual()) { - continue; - } - - byte[] hardwareAddress = networkInterface.getHardwareAddress(); - String mac = normalizeMac(hardwareAddress); - if (mac != null) { - result.add(mac); - } - } - } catch (Exception ignored) { - } - return result; - } - - private static String normalizeMac(byte[] mac) { - if (mac == null || mac.length < 6) { - return null; - } - - StringBuilder builder = new StringBuilder(); - for (byte b : mac) { - builder.append(String.format(Locale.ROOT, "%02x", b)); - } - - String value = builder.toString(); - if (value.equals("000000000000") || value.equals("ffffffffffff")) { - return null; - } - return value; - } - - private static String sha256Hex(String input) { - try { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8)); - StringBuilder builder = new StringBuilder(hash.length * 2); - for (byte b : hash) { - builder.append(String.format(Locale.ROOT, "%02x", b)); - } - return builder.toString(); - } catch (Exception ignored) { - return FALLBACK_SERVER_ID; - } - } -} diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/TelemetryEvent.java b/core/src/main/java/dev/nandi0813/practice/telemetry/TelemetryEvent.java deleted file mode 100644 index 191086aa8..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/TelemetryEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -package dev.nandi0813.practice.telemetry; - -/** - * Combat action event types for time-series telemetry logging. - * Events track granular combat interactions, movement, and ability usage. - */ -public enum TelemetryEvent { - - // Combat actions - ATTACK_LANDED, - ATTACK_MISSED, - DAMAGE_TAKEN, - POTION_THROWN, - POTION_LANDED, - POTION_MISSED, - - // Movement & positioning - SPRINT_START, - SPRINT_RESET, - BLOCK_PLACE, - BLOCK_BREAK, - MOVEMENT_FORWARD, - MOVEMENT_RETREAT, - - // Match/round lifecycle - MATCH_START, - MATCH_END, - ROUND_START, - ROUND_END, - PLAYER_DEATH, - PLAYER_RESPAWN, - - // Aim/reach metrics - REACH_ATTEMPT, - AIM_ADJUSTMENT, - CAMERA_ANGLE_CHANGE - -} - - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/bootstrap/TelemetryBootstrap.java b/core/src/main/java/dev/nandi0813/practice/telemetry/bootstrap/TelemetryBootstrap.java deleted file mode 100644 index e52fc464a..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/bootstrap/TelemetryBootstrap.java +++ /dev/null @@ -1,232 +0,0 @@ -package dev.nandi0813.practice.telemetry.bootstrap; - -import dev.nandi0813.practice.telemetry.config.TelemetryConfig; -import org.json.JSONObject; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.Duration; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; - -public enum TelemetryBootstrap { - ; - - private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(3); - private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(5); - private static final AtomicBoolean initialized = new AtomicBoolean(false); - private static final AtomicBoolean resolved = new AtomicBoolean(false); - - private static final Object BOOTSTRAP_LOCK = new Object(); - private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder() - .connectTimeout(CONNECT_TIMEOUT) - .followRedirects(HttpClient.Redirect.NORMAL) - .build(); - - private static volatile boolean active; - private static volatile boolean aiCollectionActive; - private static volatile boolean practiceStatsActive; - private static volatile boolean debugEnabled; - private static volatile CompletableFuture initializationFuture; - - public static CompletableFuture initializeAsync() { - synchronized (BOOTSTRAP_LOCK) { - if (resolved.get()) { - return CompletableFuture.completedFuture(active); - } - - if (initializationFuture != null) { - return initializationFuture; - } - - if (!initialized.compareAndSet(false, true)) { - return initializationFuture != null ? initializationFuture : CompletableFuture.completedFuture(active); - } - - TelemetryDebugLog.setDebugEnabled(false); - debugEnabled = false; - - boolean regularEnabled = TelemetryConfig.isRegularEnabled(); - boolean aiEnabled = TelemetryConfig.isAiEnabled(); - if (!regularEnabled && !aiEnabled) { - active = false; - aiCollectionActive = false; - practiceStatsActive = false; - resolved.set(true); - initializationFuture = CompletableFuture.completedFuture(false); - return initializationFuture; - } - - URI statsEndpoint = TelemetryConfig.resolveStatsEnabledEndpoint(); - if (statsEndpoint == null) { - active = false; - aiCollectionActive = false; - practiceStatsActive = false; - resolved.set(true); - initializationFuture = CompletableFuture.completedFuture(false); - return initializationFuture; - } - - String token = TelemetryConfig.resolveConfiguredToken(); - initializationFuture = fetchStatsEnabledAsync(statsEndpoint, token) - .thenApply(result -> { - boolean receivingEnabled = false; - boolean aiRemoteEnabled = false; - boolean practiceStatsRemoteEnabled = false; - - if (!result.success()) { - } else { - try { - JSONObject jsonObject = new JSONObject(result.body); - receivingEnabled = extractBoolean(jsonObject, "is_receiving_enabled", false); - aiRemoteEnabled = extractBoolean(jsonObject, "is_ai_collection_enabled", false); - practiceStatsRemoteEnabled = extractBoolean(jsonObject, "is_practice_stats_enabled", false); - debugEnabled = extractBoolean(jsonObject, "is_debug_enabled", false); - TelemetryDebugLog.setDebugEnabled(debugEnabled); - } catch (Exception exception) { - debugEnabled = false; - TelemetryDebugLog.setDebugEnabled(false); - } - } - - active = regularEnabled && receivingEnabled; - aiCollectionActive = aiEnabled && aiRemoteEnabled; - practiceStatsActive = regularEnabled && practiceStatsRemoteEnabled; - resolved.set(true); - - TelemetryDebugLog.info( - "Telemetry flags -> regular=" + active + ", ai=" + aiCollectionActive - + " (localRegular=" + regularEnabled - + ", localAi=" + aiEnabled - + ", remoteRegular=" + receivingEnabled - + ", remoteAi=" + aiRemoteEnabled - + ", practiceStats=" + practiceStatsActive - + ", remotePracticeStats=" + practiceStatsRemoteEnabled - + ", debug=" + debugEnabled + ")" - ); - - return active || aiCollectionActive || practiceStatsActive; - }); - return initializationFuture; - } - } - - public static void initialize() { - initializeAsync(); - } - - public static boolean isActive() { - return resolved.get() && active; - } - - public static boolean isResolved() { - return resolved.get(); - } - - public static boolean isAiCollectionActive() { - return resolved.get() && aiCollectionActive; - } - - public static boolean isPracticeStatsActive() { - return resolved.get() && practiceStatsActive; - } - - public static boolean isDebugEnabled() { - return resolved.get() && debugEnabled; - } - - public static CompletableFuture fetchAiCollectionEnabledAsync() { - URI statsEndpoint = TelemetryConfig.resolveStatsEnabledEndpoint(); - if (statsEndpoint == null) { - return CompletableFuture.completedFuture(false); - } - - String token = TelemetryConfig.resolveConfiguredToken(); - return fetchStatsEnabledAsync(statsEndpoint, token) - .thenApply(result -> { - if (!result.success()) { - return false; - } - - try { - JSONObject jsonObject = new JSONObject(result.body); - return extractBoolean(jsonObject, "is_ai_collection_enabled", false); - } catch (Exception ignored) { - return false; - } - }); - } - - - private static CompletableFuture fetchStatsEnabledAsync(URI statsEndpoint, String token) { - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(statsEndpoint) - .timeout(REQUEST_TIMEOUT) - .GET() - .header("Accept", "application/json"); - - if (token != null && !token.isBlank()) { - requestBuilder.header("Authorization", "Bearer " + token); - } - - return HTTP_CLIENT - .sendAsync(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .handle((response, throwable) -> { - if (throwable != null) { - return StatsFetchResult.error(throwable.getMessage()); - } - - if (response == null) { - return StatsFetchResult.error("empty response"); - } - - if (response.statusCode() < 200 || response.statusCode() >= 300) { - return StatsFetchResult.failed(response.statusCode(), response.body()); - } - - return StatsFetchResult.success(response.statusCode(), response.body()); - }); - } - - private static boolean extractBoolean(JSONObject object, String key, boolean defaultValue) { - if (object.has(key)) { - return object.optBoolean(key, defaultValue); - } - - JSONObject dataObject = object.optJSONObject("data"); - if (dataObject != null && dataObject.has(key)) { - return dataObject.optBoolean(key, defaultValue); - } - - return defaultValue; - } - - private static final class StatsFetchResult { - private final int statusCode; - private final String body; - private final String error; - - private StatsFetchResult(int statusCode, String body, String error) { - this.statusCode = statusCode; - this.body = body; - this.error = error; - } - - private boolean success() { - return error == null && statusCode >= 200 && statusCode < 300 && body != null; - } - - private static StatsFetchResult success(int statusCode, String body) { - return new StatsFetchResult(statusCode, body, null); - } - - private static StatsFetchResult failed(int statusCode, String body) { - return new StatsFetchResult(statusCode, body, "non-2xx"); - } - - private static StatsFetchResult error(String error) { - return new StatsFetchResult(-1, null, error); - } - } -} diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/bootstrap/TelemetryDebugLog.java b/core/src/main/java/dev/nandi0813/practice/telemetry/bootstrap/TelemetryDebugLog.java deleted file mode 100644 index 301a13037..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/bootstrap/TelemetryDebugLog.java +++ /dev/null @@ -1,43 +0,0 @@ -package dev.nandi0813.practice.telemetry.bootstrap; - -import dev.nandi0813.practice.ZonePractice; -import dev.nandi0813.practice.util.Common; - -public enum TelemetryDebugLog { - ; - - private static volatile boolean debugEnabled; - - public static void setDebugEnabled(boolean enabled) { - debugEnabled = enabled; - } - - public static boolean isDebugEnabled() { - return debugEnabled; - } - - public static void info(String message) { - if (!debugEnabled) { - return; - } - - ZonePractice.getInstance().getLogger().info(message); - } - - public static void warning(String message) { - if (!debugEnabled) { - return; - } - - ZonePractice.getInstance().getLogger().warning(message); - } - - public static void console(String miniMessage) { - if (!debugEnabled) { - return; - } - - Common.sendConsoleMMMessage(miniMessage); - } -} - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/collector/AiTrainingCollector.java b/core/src/main/java/dev/nandi0813/practice/telemetry/collector/AiTrainingCollector.java deleted file mode 100644 index 21d668f31..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/collector/AiTrainingCollector.java +++ /dev/null @@ -1,690 +0,0 @@ -package dev.nandi0813.practice.telemetry.collector; - -import dev.nandi0813.practice.ZonePractice; -import dev.nandi0813.practice.manager.fight.match.Match; -import dev.nandi0813.practice.manager.ladder.enums.LadderType; -import dev.nandi0813.practice.telemetry.ServerFingerprintUtil; -import dev.nandi0813.practice.telemetry.transport.ai.AiTrainingMatchPayload; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.attribute.Attribute; -import org.bukkit.block.Block; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitTask; -import org.bukkit.util.RayTraceResult; -import org.bukkit.util.Vector; -import org.json.JSONObject; - -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public final class AiTrainingCollector { - - private static final int SCHEMA_VERSION = 1; - private static final Set ALLOWED_LADDER_TYPES = Set.of(LadderType.BASIC, LadderType.BUILD, LadderType.BOXING, LadderType.SUMO); - private static final long CAPTURE_INTERVAL_TICKS = 2L; - private static final int CACHED_REFRESH_SAMPLES_FAR = 2; // 2 samples x 2 ticks = 4 ticks - private static final double COMBAT_DISTANCE_SQUARED = 64.0D; - - private final Match match; - private final String matchId; - private final String ladderName; - private final String ladderType; - private final String arenaName; - private final String arenaType; - private final String serverHash; - - private final List rows = Collections.synchronizedList(new ArrayList<>()); - private final Map playerState = new ConcurrentHashMap<>(); - - private BukkitTask samplerTask; - private long lastTimestamp; - - public AiTrainingCollector(Match match) { - this.match = match; - this.matchId = normalizeMatchId(match.getId()); - this.ladderName = match.getLadder().getName(); - this.ladderType = normalizeLadderType(match); - this.arenaName = match.getArena().getName(); - this.arenaType = match.getLadder().isBuild() ? "build" : "flat"; - this.serverHash = ServerFingerprintUtil.getServerId(); - } - - public static boolean isSupportedLadder(Match match) { - if (match == null || match.getLadder() == null || match.getLadder().getType() == null) { - return false; - } - - return ALLOWED_LADDER_TYPES.contains(match.getLadder().getType()); - } - - public void start() { - if (samplerTask != null) { - return; - } - - samplerTask = ZonePractice.getInstance().getServer().getScheduler().runTaskTimer( - ZonePractice.getInstance(), - this::captureFrame, - 1L, - CAPTURE_INTERVAL_TICKS - ); - } - - public void stop() { - if (samplerTask != null) { - samplerTask.cancel(); - samplerTask = null; - } - } - - public void markLmb(Player player) { - state(player).inputLmb = true; - } - - public void markRmb(Player player) { - state(player).inputRmb = true; - } - - public void markInventoryOpen(Player player) { - state(player).inputInventoryOpen = true; - } - - public void incrementBlocksPlaced(Player player) { - state(player).blocksPlaced += 1; - } - - public void addDamageDealt(Player player, double amount) { - state(player).damageDealt += Math.max(0.0D, amount); - } - - public void addDamageTaken(Player player, double amount) { - state(player).damageTaken += Math.max(0.0D, amount); - } - - public AiTrainingMatchPayload toPayload() { - return new AiTrainingMatchPayload( - SCHEMA_VERSION, - matchId, - ladderName, - ladderType, - arenaName, - arenaType, - serverHash, - System.currentTimeMillis(), - new ArrayList<>(rows) - ); - } - - public boolean hasRows() { - return !rows.isEmpty(); - } - - private void captureFrame() { - for (Player player : match.getPlayers()) { - if (player == null || !player.isOnline()) { - continue; - } - - PlayerFrameState frameState = state(player); - Player target = resolveTarget(player); - Location currentLocation = player.getLocation(); - - JSONObject row = new JSONObject(); - row.put("timestamp", nextTimestamp()); - row.put("playerName", player.getName()); - row.put("ladderName", ladderName); - row.put("ladderType", ladderType); - row.put("arenaName", arenaName); - row.put("arenaType", arenaType); - row.put("serverHash", serverHash); - - row.put("health", player.getHealth() + player.getAbsorptionAmount()); - row.put("posX", currentLocation.getX()); - row.put("posY", currentLocation.getY()); - row.put("posZ", currentLocation.getZ()); - row.put("velX", player.getVelocity().getX()); - row.put("velY", player.getVelocity().getY()); - row.put("velZ", player.getVelocity().getZ()); - row.put("yaw", currentLocation.getYaw()); - row.put("pitch", currentLocation.getPitch()); - row.put("isOnGround", player.isOnGround()); - - MovementInput movementInput = resolveMovementInput(currentLocation, frameState.previousLocation, frameState.previousOnGround); - row.put("inputForward", movementInput.forward); - row.put("inputBackward", movementInput.backward); - row.put("inputLeft", movementInput.left); - row.put("inputRight", movementInput.right); - row.put("inputJump", movementInput.jump); - row.put("inputSneak", player.isSneaking()); - row.put("inputSprint", player.isSprinting()); - row.put("inputLmb", frameState.inputLmb); - row.put("inputRmb", frameState.inputRmb); - row.put("inputSlot", player.getInventory().getHeldItemSlot()); - row.put("inputInventoryOpen", frameState.inputInventoryOpen || isInventoryOpen(player)); - - row.put("foodLevel", Math.min(20, Math.max(0, player.getFoodLevel()))); - row.put("totalArmor", getTotalArmor(player)); - row.put("helmetArmor", getHelmetArmor(player)); - row.put("chestplateArmor", getChestplateArmor(player)); - row.put("leggingsArmor", getLeggingsArmor(player)); - row.put("bootsArmor", getBootsArmor(player)); - row.put("attackCooldown", getAttackCooldownPercent(player)); - row.put("isUsingItem", isUsingItem(player)); - row.put("itemUseDuration", getItemUseDuration(player)); - - PlayerInventory inventory = player.getInventory(); - row.put("selectedSlot", inventory.getHeldItemSlot()); - row.put("mainHandItem", serializeItem(inventory.getItemInMainHand())); - row.put("offHandItem", serializeItem(inventory.getItemInOffHand())); - row.put("hotbar0", serializeItem(inventory.getItem(0))); - row.put("hotbar1", serializeItem(inventory.getItem(1))); - row.put("hotbar2", serializeItem(inventory.getItem(2))); - row.put("hotbar3", serializeItem(inventory.getItem(3))); - row.put("hotbar4", serializeItem(inventory.getItem(4))); - row.put("hotbar5", serializeItem(inventory.getItem(5))); - row.put("hotbar6", serializeItem(inventory.getItem(6))); - row.put("hotbar7", serializeItem(inventory.getItem(7))); - row.put("hotbar8", serializeItem(inventory.getItem(8))); - row.put("inventoryBag", serializeInventoryBag(inventory)); - - row.put("hasSpeed", hasPotion(player, "SPEED")); - row.put("hasSlowness", hasPotion(player, "SLOW", "SLOWNESS")); - row.put("hasStrength", hasPotion(player, "INCREASE_DAMAGE", "STRENGTH")); - row.put("hasWeakness", hasPotion(player, "WEAKNESS")); - row.put("hasRegeneration", hasPotion(player, "REGENERATION")); - row.put("hasPoison", hasPotion(player, "POISON")); - - writeTargetState(row, player, target); - boolean inCombatRange = isInCombatRange(player, target); - ObstacleState obstacleState = resolveObstacleState(player, frameState, inCombatRange); - ThreatState threatState = resolveThreatState(player, frameState, inCombatRange); - writeObstacleState(row, obstacleState); - writeThreatState(row, threatState); - - row.put("damageDealt", consumeDamageDealt(frameState)); - row.put("damageTaken", consumeDamageTaken(frameState)); - row.put("blocksPlaced", consumeBlocksPlaced(frameState)); - - rows.add(row); - - frameState.previousLocation = currentLocation.clone(); - frameState.previousOnGround = player.isOnGround(); - frameState.inputLmb = false; - frameState.inputRmb = false; - frameState.inputInventoryOpen = false; - frameState.samplesCaptured += 1; - } - } - - private static boolean isInCombatRange(Player player, Player target) { - if (target == null) { - return false; - } - return target.getLocation().distanceSquared(player.getLocation()) <= COMBAT_DISTANCE_SQUARED; - } - - private static boolean shouldRefreshCachedState(PlayerFrameState frameState, boolean inCombatRange) { - if (inCombatRange) { - return true; - } - return frameState.samplesCaptured % CACHED_REFRESH_SAMPLES_FAR == 0; - } - - private static ObstacleState resolveObstacleState(Player player, PlayerFrameState frameState, boolean inCombatRange) { - if (frameState.obstacleState == null || shouldRefreshCachedState(frameState, inCombatRange)) { - frameState.obstacleState = computeObstacleState(player); - } - return frameState.obstacleState; - } - - private static ThreatState resolveThreatState(Player player, PlayerFrameState frameState, boolean inCombatRange) { - if (frameState.threatState == null || shouldRefreshCachedState(frameState, inCombatRange)) { - frameState.threatState = computeThreatState(player); - } - return frameState.threatState; - } - - private PlayerFrameState state(Player player) { - return playerState.computeIfAbsent(player.getUniqueId(), ignored -> new PlayerFrameState(player.getLocation().clone(), player.isOnGround())); - } - - private long nextTimestamp() { - long now = System.currentTimeMillis(); - if (now <= lastTimestamp) { - now = lastTimestamp + 1; - } - lastTimestamp = now; - return now; - } - - private int consumeBlocksPlaced(PlayerFrameState frameState) { - int delta = Math.max(0, frameState.blocksPlaced - frameState.blocksPlacedSent); - frameState.blocksPlacedSent = frameState.blocksPlaced; - return delta; - } - - private double consumeDamageDealt(PlayerFrameState frameState) { - double delta = Math.max(0.0D, frameState.damageDealt - frameState.damageDealtSent); - frameState.damageDealtSent = frameState.damageDealt; - return delta; - } - - private double consumeDamageTaken(PlayerFrameState frameState) { - double delta = Math.max(0.0D, frameState.damageTaken - frameState.damageTakenSent); - frameState.damageTakenSent = frameState.damageTaken; - return delta; - } - - private static MovementInput resolveMovementInput(Location current, Location previous, boolean previousOnGround) { - if (previous == null) { - return MovementInput.NONE; - } - - double dx = current.getX() - previous.getX(); - double dz = current.getZ() - previous.getZ(); - double yaw = Math.toRadians(current.getYaw()); - - double forwardComponent = -Math.sin(yaw) * dx + Math.cos(yaw) * dz; - double strafeComponent = Math.cos(yaw) * dx + Math.sin(yaw) * dz; - double threshold = 0.03D; - - boolean forward = forwardComponent > threshold; - boolean backward = forwardComponent < -threshold; - boolean left = strafeComponent > threshold; - boolean right = strafeComponent < -threshold; - boolean jump = !previousOnGround && current.getY() > previous.getY(); - - return new MovementInput(forward, backward, left, right, jump); - } - - private static boolean isInventoryOpen(Player player) { - try { - return player.getOpenInventory().getTopInventory().getType() != org.bukkit.event.inventory.InventoryType.CRAFTING; - } catch (Exception ignored) { - return false; - } - } - - private static double getTotalArmor(Player player) { - try { - var armor = player.getAttribute(Attribute.ARMOR); - if (armor != null) { - return armor.getValue(); - } - } catch (Exception ignored) { - } - return 0.0D; - } - - private static float getHelmetArmor(Player player) { - return getArmorPieceValue(player.getInventory().getHelmet()); - } - - private static float getChestplateArmor(Player player) { - return getArmorPieceValue(player.getInventory().getChestplate()); - } - - private static float getLeggingsArmor(Player player) { - return getArmorPieceValue(player.getInventory().getLeggings()); - } - - private static float getBootsArmor(Player player) { - return getArmorPieceValue(player.getInventory().getBoots()); - } - - private static float getArmorPieceValue(ItemStack armorPiece) { - if (armorPiece == null || armorPiece.getType() == Material.AIR) { - return 0.0f; - } - - // Return base armor points per item type - // Based on Minecraft's armor point values - switch (armorPiece.getType()) { - // Leather armor (1 point each) - case LEATHER_HELMET -> { return 1.0f; } - case LEATHER_CHESTPLATE -> { return 3.0f; } - case LEATHER_LEGGINGS -> { return 2.0f; } - case LEATHER_BOOTS -> { return 1.0f; } - - // Iron armor - case IRON_HELMET -> { return 2.0f; } - case IRON_CHESTPLATE -> { return 6.0f; } - case IRON_LEGGINGS -> { return 5.0f; } - case IRON_BOOTS -> { return 2.0f; } - - // Golden armor - case GOLDEN_HELMET -> { return 2.0f; } - case GOLDEN_CHESTPLATE -> { return 5.0f; } - case GOLDEN_LEGGINGS -> { return 3.0f; } - case GOLDEN_BOOTS -> { return 1.0f; } - - // Diamond armor - case DIAMOND_HELMET -> { return 3.0f; } - case DIAMOND_CHESTPLATE -> { return 8.0f; } - case DIAMOND_LEGGINGS -> { return 6.0f; } - case DIAMOND_BOOTS -> { return 3.0f; } - - // Netherite armor - case NETHERITE_HELMET -> { return 3.0f; } - case NETHERITE_CHESTPLATE -> { return 8.0f; } - case NETHERITE_LEGGINGS -> { return 6.0f; } - case NETHERITE_BOOTS -> { return 3.0f; } - - // Chain armor - case CHAINMAIL_HELMET -> { return 2.0f; } - case CHAINMAIL_CHESTPLATE -> { return 5.0f; } - case CHAINMAIL_LEGGINGS -> { return 4.0f; } - case CHAINMAIL_BOOTS -> { return 1.0f; } - - default -> { return 0.0f; } - } - } - - private static double getAttackCooldown(Player player) { - try { - return player.getAttackCooldown(); - } catch (Exception ignored) { - return 1.0D; - } - } - - private static int getAttackCooldownPercent(Player player) { - double cooldown = getAttackCooldown(player); - double clamped = Math.max(0.0D, Math.min(1.0D, cooldown)); - return (int) Math.round(clamped * 100.0D); - } - - private static boolean isUsingItem(Player player) { - try { - Object value = player.getClass().getMethod("isHandRaised").invoke(player); - if (value instanceof Boolean result) { - return result; - } - } catch (Exception ignored) { - } - - try { - Object value = player.getClass().getMethod("isBlocking").invoke(player); - if (value instanceof Boolean result) { - return result; - } - } catch (Exception ignored) { - } - - return false; - } - - private static int getItemUseDuration(Player player) { - try { - Object value = player.getClass().getMethod("getItemUseRemainingTime").invoke(player); - if (value instanceof Integer result) { - return Math.max(0, result); - } - } catch (Exception ignored) { - } - - return 0; - } - - private static boolean hasPotion(Player player, String... aliases) { - for (String alias : aliases) { - PotionEffectType type = PotionEffectType.getByName(alias); - if (type != null && player.hasPotionEffect(type)) { - return true; - } - } - return false; - } - - private static String serializeItem(ItemStack itemStack) { - if (itemStack == null || itemStack.getType().isAir()) { - return "AIR"; - } - - return itemStack.getType().name() + "x" + itemStack.getAmount(); - } - - private static String serializeInventoryBag(PlayerInventory inventory) { - StringBuilder builder = new StringBuilder(); - ItemStack[] storage = inventory.getStorageContents(); - for (int i = 0; i < storage.length; i++) { - if (i > 0) { - builder.append(';'); - } - builder.append(i).append('=').append(serializeItem(storage[i])); - } - return builder.toString(); - } - - private static void writeTargetState(JSONObject row, Player player, Player target) { - if (target == null) { - row.put("targetDistance", 0.0D); - row.put("targetRelX", 0.0D); - row.put("targetRelY", 0.0D); - row.put("targetRelZ", 0.0D); - row.put("targetYaw", 0.0F); - row.put("targetPitch", 0.0F); - row.put("targetVelX", 0.0D); - row.put("targetVelY", 0.0D); - row.put("targetVelZ", 0.0D); - row.put("targetHealth", 0.0D); - return; - } - - Vector delta = target.getLocation().toVector().subtract(player.getLocation().toVector()); - row.put("targetDistance", target.getLocation().distance(player.getLocation())); - row.put("targetRelX", delta.getX()); - row.put("targetRelY", delta.getY()); - row.put("targetRelZ", delta.getZ()); - row.put("targetYaw", target.getLocation().getYaw()); - row.put("targetPitch", target.getLocation().getPitch()); - row.put("targetVelX", target.getVelocity().getX()); - row.put("targetVelY", target.getVelocity().getY()); - row.put("targetVelZ", target.getVelocity().getZ()); - row.put("targetHealth", target.getHealth() + target.getAbsorptionAmount()); - } - - private static ObstacleState computeObstacleState(Player player) { - double rayForward = rayDistance(player, 0.0F); - double rayLeft = rayDistance(player, -90.0F); - double rayRight = rayDistance(player, 90.0F); - double rayBackward = rayDistance(player, 180.0F); - double distanceToGround = distanceToGround(player); - - Block targetBlock = resolveTargetBlock(player); - if (targetBlock == null) { - return new ObstacleState(rayForward, rayLeft, rayRight, rayBackward, distanceToGround, 0, 0, 0); - } - - return new ObstacleState( - rayForward, - rayLeft, - rayRight, - rayBackward, - distanceToGround, - targetBlock.getX(), - targetBlock.getY(), - targetBlock.getZ() - ); - } - - private static void writeObstacleState(JSONObject row, ObstacleState obstacleState) { - row.put("rayForward", obstacleState.rayForward()); - row.put("rayLeft", obstacleState.rayLeft()); - row.put("rayRight", obstacleState.rayRight()); - row.put("rayBackward", obstacleState.rayBackward()); - row.put("distanceToGround", obstacleState.distanceToGround()); - row.put("lookingAtBlockX", obstacleState.lookingAtBlockX()); - row.put("lookingAtBlockY", obstacleState.lookingAtBlockY()); - row.put("lookingAtBlockZ", obstacleState.lookingAtBlockZ()); - } - - private static Block resolveTargetBlock(Player player) { - try { - return player.getTargetBlockExact(6); - } catch (Exception ignored) { - return null; - } - } - - private static double rayDistance(Player player, float yawOffset) { - Location eye = player.getEyeLocation(); - Location adjustedEye = eye.clone(); - adjustedEye.setYaw(eye.getYaw() + yawOffset); - adjustedEye.setPitch(0.0F); - - Vector direction = adjustedEye.getDirection().normalize(); - RayTraceResult result = player.getWorld().rayTraceBlocks(eye, direction, 6.0D); - if (result == null) { - return 6.0D; - } - - return result.getHitPosition().distance(eye.toVector()); - } - - private static double distanceToGround(Player player) { - Location location = player.getLocation(); - World world = player.getWorld(); - int minY = world.getMinHeight(); - - for (int y = location.getBlockY(); y >= minY; y--) { - Material material = world.getBlockAt(location.getBlockX(), y, location.getBlockZ()).getType(); - if (!material.isAir()) { - return Math.max(0.0D, location.getY() - (y + 1)); - } - } - - return Math.max(0.0D, location.getY() - minY); - } - - private static ThreatState computeThreatState(Player player) { - Entity nearestProjectile = null; - double nearestDistanceSquared = Double.MAX_VALUE; - - for (Entity entity : player.getNearbyEntities(16.0D, 8.0D, 16.0D)) { - if (!(entity instanceof Projectile projectile)) { - continue; - } - - if (projectile.getShooter() instanceof Player shooter && shooter.equals(player)) { - continue; - } - - double currentDistanceSquared = entity.getLocation().distanceSquared(player.getLocation()); - if (currentDistanceSquared < nearestDistanceSquared) { - nearestDistanceSquared = currentDistanceSquared; - nearestProjectile = entity; - } - } - - if (nearestProjectile == null) { - return new ThreatState(0.0D, 0.0D, 0.0D); - } - - Vector delta = nearestProjectile.getLocation().toVector().subtract(player.getLocation().toVector()); - return new ThreatState(delta.getX(), delta.getY(), delta.getZ()); - } - - private static void writeThreatState(JSONObject row, ThreatState threatState) { - row.put("nearestProjectileDx", threatState.nearestProjectileDx()); - row.put("nearestProjectileDy", threatState.nearestProjectileDy()); - row.put("nearestProjectileDz", threatState.nearestProjectileDz()); - } - - private Player resolveTarget(Player player) { - Player nearest = null; - double nearestDistanceSquared = Double.MAX_VALUE; - - for (Player candidate : match.getPlayers()) { - if (candidate == null || !candidate.isOnline() || candidate.equals(player)) { - continue; - } - - try { - double currentDistanceSquared = candidate.getLocation().distanceSquared(player.getLocation()); - if (currentDistanceSquared < nearestDistanceSquared) { - nearestDistanceSquared = currentDistanceSquared; - nearest = candidate; - } - } catch (Exception ignored) {} - } - - return nearest; - } - - private static String normalizeLadderType(Match match) { - LadderType ladderType = match.getLadder().getType(); - if (ladderType == null) { - return ""; - } - return ladderType.name().toLowerCase(Locale.ROOT); - } - - private static String normalizeMatchId(String rawMatchId) { - if (rawMatchId == null || rawMatchId.isBlank()) { - return UUID.randomUUID().toString(); - } - - try { - return UUID.fromString(rawMatchId).toString(); - } catch (IllegalArgumentException ignored) { - return UUID.nameUUIDFromBytes(rawMatchId.getBytes(StandardCharsets.UTF_8)).toString(); - } - } - - private record MovementInput(boolean forward, boolean backward, boolean left, boolean right, boolean jump) { - private static final MovementInput NONE = new MovementInput(false, false, false, false, false); - } - - private record ObstacleState( - double rayForward, - double rayLeft, - double rayRight, - double rayBackward, - double distanceToGround, - int lookingAtBlockX, - int lookingAtBlockY, - int lookingAtBlockZ - ) { - } - - private record ThreatState( - double nearestProjectileDx, - double nearestProjectileDy, - double nearestProjectileDz - ) { - } - - private static final class PlayerFrameState { - private Location previousLocation; - private boolean previousOnGround; - private boolean inputLmb; - private boolean inputRmb; - private boolean inputInventoryOpen; - private long samplesCaptured; - private ObstacleState obstacleState; - private ThreatState threatState; - - private int blocksPlaced; - private int blocksPlacedSent; - private double damageDealt; - private double damageDealtSent; - private double damageTaken; - private double damageTakenSent; - - private PlayerFrameState(Location previousLocation, boolean previousOnGround) { - this.previousLocation = previousLocation; - this.previousOnGround = previousOnGround; - } - } -} - - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/collector/TelemetryMatchListener.java b/core/src/main/java/dev/nandi0813/practice/telemetry/collector/TelemetryMatchListener.java deleted file mode 100644 index 2545df15b..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/collector/TelemetryMatchListener.java +++ /dev/null @@ -1,479 +0,0 @@ -package dev.nandi0813.practice.telemetry.collector; - -import dev.nandi0813.api.Event.Match.MatchEndEvent; -import dev.nandi0813.api.Event.Match.MatchStartEvent; -import dev.nandi0813.practice.ZonePractice; -import dev.nandi0813.practice.manager.fight.match.Match; -import dev.nandi0813.practice.manager.fight.match.Round; -import dev.nandi0813.practice.manager.fight.match.type.duel.Duel; -import dev.nandi0813.practice.manager.fight.match.type.duel.DuelRound; -import dev.nandi0813.practice.manager.fight.util.Stats.Statistic; -import dev.nandi0813.practice.manager.ladder.abstraction.normal.NormalLadder; -import dev.nandi0813.practice.manager.profile.Profile; -import dev.nandi0813.practice.manager.profile.ProfileManager; -import dev.nandi0813.practice.manager.profile.statistics.LadderStats; -import dev.nandi0813.practice.telemetry.MatchTelemetry; -import dev.nandi0813.practice.telemetry.PlayerTelemetry; -import dev.nandi0813.practice.telemetry.RoundTelemetry; -import dev.nandi0813.practice.telemetry.ServerFingerprintUtil; -import dev.nandi0813.practice.telemetry.bootstrap.TelemetryBootstrap; -import dev.nandi0813.practice.telemetry.transport.ai.AiTrainingLogger; -import dev.nandi0813.practice.telemetry.transport.ai.AiTrainingMatchPayload; -import dev.nandi0813.practice.telemetry.transport.regular.TelemetryLogger; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.ProjectileLaunchEvent; -import org.bukkit.event.inventory.InventoryOpenEvent; -import org.bukkit.event.player.PlayerInteractEvent; - -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public class TelemetryMatchListener implements Listener { - - private static final int SCHEMA_VERSION = 1; - private static final int MAX_CONCURRENT_AI_RECORDINGS = 5; - private final Map snapshots = new ConcurrentHashMap<>(); - private final Map aiCollectors = new ConcurrentHashMap<>(); - - @EventHandler - public void onMatchStart(MatchStartEvent event) { - Match match = (Match) event.getMatch(); - Map eloBefore = new HashMap<>(); - - if (match.getLadder() instanceof NormalLadder normalLadder) { - for (Player player : match.getPlayers()) { - Profile profile = ProfileManager.getInstance().getProfile(player); - if (profile == null) { - continue; - } - - LadderStats ladderStats = profile.getStats().getLadderStat(normalLadder); - eloBefore.put(player.getUniqueId(), ladderStats.getElo()); - } - } - - snapshots.put(match.getId(), new MatchStartSnapshot(System.currentTimeMillis(), eloBefore)); - - if (AiTrainingCollector.isSupportedLadder(match)) { - if (aiCollectors.size() >= MAX_CONCURRENT_AI_RECORDINGS) { - // Bukkit.getLogger().warning("[ZonePractice] Skipping AI recording for match " + match.getId() + " (active recordings cap=" + MAX_CONCURRENT_AI_RECORDINGS + ")"); - return; - } - - AiTrainingCollector collector = new AiTrainingCollector(match); - aiCollectors.put(match.getId(), collector); - collector.start(); - } - } - - @EventHandler - public void onMatchEnd(MatchEndEvent event) { - Match match = (Match) event.getMatch(); - MatchStartSnapshot snapshot = snapshots.remove(match.getId()); - String telemetryMatchId = toTelemetryMatchUuid(match.getId()); - - long matchEndTs = System.currentTimeMillis(); - long matchStartTs = snapshot != null ? snapshot.startTs() : (matchEndTs - (match.getDuration() * 1000L)); - - Object winnerObject = match.getMatchWinner(); - UUID winnerUuid = winnerObject instanceof Player winnerPlayer ? winnerPlayer.getUniqueId() : null; - - MatchTelemetry telemetry = new MatchTelemetry( - SCHEMA_VERSION, - telemetryMatchId, - match.getType().name(), - match.getLadder().getName(), - match.getArena().getName(), - isRanked(match), - match.getWinsNeeded(), - ServerFingerprintUtil.getServerId(), - ZonePractice.getInstance().getPluginMeta().getVersion(), - Bukkit.getBukkitVersion(), - matchStartTs, - matchEndTs, - Math.max(0L, matchEndTs - matchStartTs), - determineTerminationReason(match, winnerUuid), - buildPlayerTelemetry(match, winnerUuid, snapshot), - buildRoundTelemetry(match, matchStartTs), - new ArrayList<>(), - TelemetryLogger.getDroppedRecords(), - System.currentTimeMillis() - ); - - if (TelemetryBootstrap.isActive()) { - TelemetryLogger.logAsync(telemetry); - } - if (TelemetryBootstrap.isAiCollectionActive()) { - AiTrainingCollector collector = aiCollectors.remove(match.getId()); - if (collector != null) { - collector.stop(); - if (collector.hasRows()) { - AiTrainingMatchPayload aiPayload = collector.toPayload(); - AiTrainingLogger.logAsync(aiPayload); - } - } - } else { - AiTrainingCollector collector = aiCollectors.remove(match.getId()); - if (collector != null) { - collector.stop(); - } - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerInteract(PlayerInteractEvent event) { - Action action = event.getAction(); - if (action != Action.LEFT_CLICK_AIR - && action != Action.LEFT_CLICK_BLOCK - && action != Action.RIGHT_CLICK_AIR - && action != Action.RIGHT_CLICK_BLOCK) { - return; - } - - AiTrainingCollector collector = getAiCollectorByPlayer(event.getPlayer()); - if (collector == null) { - return; - } - - if (action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK) { - collector.markLmb(event.getPlayer()); - } else { - collector.markRmb(event.getPlayer()); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onProjectileLaunch(ProjectileLaunchEvent event) { - if (!(event.getEntity().getShooter() instanceof Player player)) { - return; - } - - AiTrainingCollector collector = getAiCollectorByPlayer(player); - if (collector != null) { - collector.markRmb(player); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onInventoryOpen(InventoryOpenEvent event) { - if (!(event.getPlayer() instanceof Player player)) { - return; - } - - AiTrainingCollector collector = getAiCollectorByPlayer(player); - if (collector != null) { - collector.markInventoryOpen(player); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockPlace(BlockPlaceEvent event) { - AiTrainingCollector collector = getAiCollectorByPlayer(event.getPlayer()); - if (collector != null) { - collector.incrementBlocksPlaced(event.getPlayer()); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { - if (!(event.getEntity() instanceof Player target)) { - return; - } - - Player attacker = null; - if (event.getDamager() instanceof Player damager) { - attacker = damager; - } else if (event.getDamager() instanceof Projectile projectile && projectile.getShooter() instanceof Player shooter) { - attacker = shooter; - } - - if (attacker == null) { - return; - } - - AiTrainingCollector attackerCollector = getAiCollectorByPlayer(attacker); - AiTrainingCollector targetCollector = getAiCollectorByPlayer(target); - if (attackerCollector == null || attackerCollector != targetCollector) { - return; - } - - attackerCollector.markLmb(attacker); - attackerCollector.addDamageDealt(attacker, event.getFinalDamage()); - attackerCollector.addDamageTaken(target, event.getFinalDamage()); - } - - private AiTrainingCollector getAiCollectorByPlayer(Player player) { - Match match = dev.nandi0813.practice.manager.fight.match.MatchManager.getInstance().getLiveMatchByPlayer(player); - if (match == null) { - return null; - } - - return aiCollectors.get(match.getId()); - } - - private List buildPlayerTelemetry(Match match, UUID winnerUuid, MatchStartSnapshot snapshot) { - List players = new ArrayList<>(); - Map aggregateByPlayer = aggregateStats(match); - - for (Player player : match.getPlayers()) { - UUID playerUuid = player.getUniqueId(); - Player opponentPlayer = findOpponentPlayer(match, player); - UUID opponentUuid = opponentPlayer != null ? opponentPlayer.getUniqueId() : null; - String opponentUsername = resolveOpponentUsername(opponentPlayer); - AggregatedStat stat = aggregateByPlayer.getOrDefault(playerUuid, new AggregatedStat()); - - Integer eloBefore = snapshot != null ? snapshot.eloByPlayer().get(playerUuid) : null; - Integer eloAfter = getCurrentElo(match, player); - Integer eloDelta = (eloBefore != null && eloAfter != null) ? (eloAfter - eloBefore) : null; - Integer ping = getPingSafe(player); - - long queueWaitMs = 0L; - int queueSearchRangeStart = eloBefore != null ? eloBefore : 0; - int queueSearchRangeEnd = eloAfter != null ? eloAfter : queueSearchRangeStart; - - players.add(new PlayerTelemetry( - playerUuid, - player.getName(), - opponentUuid, - opponentUsername, - eloBefore, - eloAfter, - eloDelta, - queueWaitMs, - queueSearchRangeStart, - queueSearchRangeEnd, - winnerUuid != null && winnerUuid.equals(playerUuid), - match.getWonRounds(player), - stat.kills, - stat.deaths, - stat.hitsLanded, - stat.hitsTaken, - stat.longestCombo, - stat.getAvgCps(), - stat.potionThrown, - stat.potionMissed, - stat.getPotionAccuracy(), - 0.0D, - 0.0D, - 0, - 0.0D, - 0.0D, - 0.0D, - 0.0D, - ping, - ping, - 0.5D, - 0.5D, - 0, - 0, - 0 - )); - } - - return players; - } - - private List buildRoundTelemetry(Match match, long matchStartTs) { - List rounds = new ArrayList<>(); - List orderedRounds = new ArrayList<>(match.getRounds().values()); - orderedRounds.sort(Comparator.comparingInt(Round::getRoundNumber)); - - long rollingRoundStart = matchStartTs; - for (Round round : orderedRounds) { - long roundDurationMs = round.getDurationTime() * 1000L; - long roundStartTs = rollingRoundStart; - long roundEndTs = roundStartTs + roundDurationMs; - rollingRoundStart = roundEndTs; - - UUID roundWinnerUuid = null; - if (round instanceof DuelRound duelRound && duelRound.getRoundWinner() != null) { - roundWinnerUuid = duelRound.getRoundWinner().getUniqueId(); - } - - List roundPlayers = new ArrayList<>(); - for (Map.Entry entry : round.getStatistics().entrySet()) { - Statistic stat = entry.getValue(); - roundPlayers.add(new RoundTelemetry.PlayerRoundTelemetry( - entry.getKey(), - stat.getHit(), - stat.getGetHit(), - stat.getKills(), - stat.getDeaths(), - stat.getPotionThrown(), - stat.getPotionMissed(), - stat.getPotionAccuracy(), - stat.getLongestCombo(), - stat.getAverageCPS() - )); - } - - rounds.add(new RoundTelemetry( - round.getRoundNumber(), - roundStartTs, - roundEndTs, - roundDurationMs, - roundWinnerUuid, - roundPlayers - )); - } - - return rounds; - } - - private Map aggregateStats(Match match) { - Map byPlayer = new HashMap<>(); - - for (Round round : match.getRounds().values()) { - for (Map.Entry entry : round.getStatistics().entrySet()) { - AggregatedStat aggregate = byPlayer.computeIfAbsent(entry.getKey(), ignored -> new AggregatedStat()); - aggregate.add(entry.getValue()); - } - } - - return byPlayer; - } - - private Integer getCurrentElo(Match match, Player player) { - if (!(match.getLadder() instanceof NormalLadder normalLadder)) { - return null; - } - - Profile profile = ProfileManager.getInstance().getProfile(player); - if (profile == null) { - return null; - } - - return profile.getStats().getLadderStat(normalLadder).getElo(); - } - - - private Player findOpponentPlayer(Match match, Player player) { - if (match instanceof Duel duel) { - return duel.getOppositePlayer(player); - } - - List players = match.getPlayers(); - if (players.size() != 2) { - return null; - } - - for (Player currentPlayer : players) { - if (!currentPlayer.equals(player)) { - return currentPlayer; - } - } - - return null; - } - - private String resolveOpponentUsername(Player opponentPlayer) { - if (opponentPlayer == null) { - return "unknown"; - } - - String opponentName = opponentPlayer.getName(); - if (opponentName == null || opponentName.isBlank()) { - return "unknown"; - } - - return opponentName; - } - - - private String toTelemetryMatchUuid(String rawMatchId) { - if (rawMatchId == null || rawMatchId.isBlank()) { - return UUID.randomUUID().toString(); - } - - try { - return UUID.fromString(rawMatchId).toString(); - } catch (IllegalArgumentException ignored) { - return UUID.nameUUIDFromBytes(rawMatchId.getBytes(StandardCharsets.UTF_8)).toString(); - } - } - - private boolean isRanked(Match match) { - return match instanceof Duel duel && duel.isRanked(); - } - - private String determineTerminationReason(Match match, UUID winnerUuid) { - if (winnerUuid == null) { - return "draw"; - } - - if (match instanceof Duel duel && duel.getLoser() == null) { - return "forfeit"; - } - - if (match.getLadder() instanceof NormalLadder normalLadder && match.getDuration() >= normalLadder.getMaxDuration()) { - return "timeout"; - } - - return "completed"; - } - - private Integer getPingSafe(Player player) { - try { - Object value = player.getClass().getMethod("getPing").invoke(player); - if (value instanceof Integer ping) { - return ping; - } - } catch (Exception ignored) { - } - return null; - } - - private record MatchStartSnapshot(long startTs, Map eloByPlayer) { - } - - private static class AggregatedStat { - private int hitsLanded; - private int hitsTaken; - private int kills; - private int deaths; - private int potionThrown; - private int potionMissed; - private int longestCombo; - private double avgCpsSum; - private int avgCpsSamples; - - private void add(Statistic stat) { - hitsLanded += stat.getHit(); - hitsTaken += stat.getGetHit(); - kills += stat.getKills(); - deaths += stat.getDeaths(); - potionThrown += stat.getPotionThrown(); - potionMissed += stat.getPotionMissed(); - if (stat.getLongestCombo() > longestCombo) { - longestCombo = stat.getLongestCombo(); - } - if (stat.getAverageCPS() > 0) { - avgCpsSum += stat.getAverageCPS(); - avgCpsSamples++; - } - } - - private int getPotionAccuracy() { - if (potionThrown == 0) { - return 0; - } - return 100 - (int) Math.ceil((potionMissed / (double) potionThrown) * 100.0D); - } - - private double getAvgCps() { - if (avgCpsSamples == 0) { - return 0; - } - return avgCpsSum / avgCpsSamples; - } - } -} diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/config/TelemetryConfig.java b/core/src/main/java/dev/nandi0813/practice/telemetry/config/TelemetryConfig.java deleted file mode 100644 index 34fed3f09..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/config/TelemetryConfig.java +++ /dev/null @@ -1,203 +0,0 @@ -package dev.nandi0813.practice.telemetry.config; - -import dev.nandi0813.practice.manager.backend.ConfigManager; -import dev.nandi0813.practice.telemetry.bootstrap.TelemetryDebugLog; - -import java.net.URI; - -public enum TelemetryConfig { - ; - - private static final String DEFAULT_BASE_ENDPOINT = "https://nandi0813.hu"; - //private static final String DEFAULT_BASE_ENDPOINT = "http://localhost:8000"; - private static final String ACCESS_TOKEN = "c22afd81c269b86c3c479cf1941c4aba5b842afda8228ad3540dab20e014b746"; - - private static final String REGULAR_ENABLED_PATH = "TELEMETRY.ENABLED"; - private static final String AI_ENABLED_PATH = "TELEMETRY.AI.ENABLED"; - - private static final String TELEMETRY_PATH_PREFIX = "/api/v1/telemetry/"; - private static final String MATCHES_PATH = "matches/"; - private static final String AI_MATCHES_PATH = "ai-training/matches/"; - private static final String STATS_ENABLED_PATH = "stats-enabled/"; - private static final String PRACTICE_STATS_UPLOAD_PATH = "practice-stats/upload/"; - private static final String PRACTICE_STATS_SERVER_UPLOADED_PATH = "/api/v1/telemetry/practice-stats/server-uploaded/"; - private static final String PRACTICE_STATS_SERVER_UPLOADED_FALLBACK_PATH = "practice-stats/server-uploaded/"; - - public static boolean isRegularEnabled() { - return ConfigManager.getBoolean(REGULAR_ENABLED_PATH); - } - - public static boolean isAiEnabled() { - return ConfigManager.getBoolean(AI_ENABLED_PATH); - } - - public static URI resolveConfiguredBaseEndpoint() { - URI parsed = parseHttpUri(DEFAULT_BASE_ENDPOINT); - return normalizeToBaseHost(parsed); - } - - public static String resolveConfiguredToken() { - return ACCESS_TOKEN; - } - - public static URI resolveMatchesEndpoint() { - return appendTelemetryPath(MATCHES_PATH); - } - - public static URI resolveAiMatchesEndpoint() { - return appendTelemetryPath(AI_MATCHES_PATH); - } - - public static URI resolveStatsEnabledEndpoint() { - return appendTelemetryPath(STATS_ENABLED_PATH); - } - - public static URI resolvePracticeStatsUploadEndpoint() { - return appendTelemetryPath(PRACTICE_STATS_UPLOAD_PATH); - } - - public static URI resolvePracticeStatsServerUploadedEndpoint() { - return appendAbsolutePath(PRACTICE_STATS_SERVER_UPLOADED_PATH); - } - - public static URI resolvePracticeStatsServerUploadedFallbackEndpoint() { - return appendTelemetryPath(PRACTICE_STATS_SERVER_UPLOADED_FALLBACK_PATH); - } - - private static URI appendTelemetryPath(String suffix) { - URI baseEndpoint = resolveConfiguredBaseEndpoint(); - if (baseEndpoint == null) { - return null; - } - - try { - String basePath = baseEndpoint.getPath() == null ? "" : baseEndpoint.getPath(); - String normalizedBasePath = basePath.endsWith("/") ? basePath.substring(0, basePath.length() - 1) : basePath; - String fullPath = normalizedBasePath + TELEMETRY_PATH_PREFIX + suffix; - - return new URI( - baseEndpoint.getScheme(), - baseEndpoint.getUserInfo(), - baseEndpoint.getHost(), - baseEndpoint.getPort(), - fullPath, - null, - null - ); - } catch (Exception exception) { - TelemetryDebugLog.console("Invalid telemetry endpoint path (" + exception.getMessage() + ")"); - return null; - } - } - - private static URI appendAbsolutePath(String absolutePath) { - URI baseEndpoint = resolveConfiguredBaseEndpoint(); - if (baseEndpoint == null) { - return null; - } - - try { - return new URI( - baseEndpoint.getScheme(), - baseEndpoint.getUserInfo(), - baseEndpoint.getHost(), - baseEndpoint.getPort(), - absolutePath, - null, - null - ); - } catch (Exception exception) { - TelemetryDebugLog.console("Invalid telemetry endpoint path (" + exception.getMessage() + ")"); - return null; - } - } - - private static String firstNonBlank(String... values) { - if (values == null) { - return null; - } - - for (String value : values) { - if (value != null) { - String trimmed = value.trim(); - if (!trimmed.isBlank()) { - return trimmed; - } - } - } - - return null; - } - - private static String readRawString(String path) { - Object value = ConfigManager.get(path); - return value == null ? null : String.valueOf(value); - } - - private static URI parseHttpUri(String endpoint) { - if (endpoint == null || endpoint.isBlank()) { - return null; - } - - try { - URI uri = URI.create(endpoint.trim()); - String scheme = uri.getScheme(); - if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { - TelemetryDebugLog.console("Telemetry endpoint must use http/https: " + endpoint); - return null; - } - return uri; - } catch (Exception exception) { - TelemetryDebugLog.console("Invalid telemetry endpoint: " + endpoint + " (" + exception.getMessage() + ")"); - return null; - } - } - - private static URI normalizeToBaseHost(URI endpointUri) { - if (endpointUri == null) { - return null; - } - - String path = endpointUri.getPath(); - if (path == null || path.isBlank() || "/".equals(path)) { - return endpointUri; - } - - String normalizedPath = path; - String[] knownSuffixes = { - "/api/v1/telemetry/matches/", - "/api/v1/telemetry/matches", - "/api/v1/telemetry/ai-training/matches/", - "/api/v1/telemetry/ai-training/matches", - "/api/v1/telemetry/stats-enabled/", - "/api/v1/telemetry/stats-enabled", - "/api/v1/telemetry/", - "/api/v1/telemetry" - }; - - for (String suffix : knownSuffixes) { - if (normalizedPath.endsWith(suffix)) { - normalizedPath = normalizedPath.substring(0, normalizedPath.length() - suffix.length()); - if (normalizedPath.isBlank()) { - normalizedPath = "/"; - } - break; - } - } - - try { - return new URI( - endpointUri.getScheme(), - endpointUri.getUserInfo(), - endpointUri.getHost(), - endpointUri.getPort(), - normalizedPath, - null, - null - ); - } catch (Exception exception) { - return endpointUri; - } - } -} - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/transport/ai/AiTrainingLogger.java b/core/src/main/java/dev/nandi0813/practice/telemetry/transport/ai/AiTrainingLogger.java deleted file mode 100644 index d761de628..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/transport/ai/AiTrainingLogger.java +++ /dev/null @@ -1,208 +0,0 @@ -package dev.nandi0813.practice.telemetry.transport.ai; - -import dev.nandi0813.practice.telemetry.bootstrap.TelemetryBootstrap; -import dev.nandi0813.practice.telemetry.bootstrap.TelemetryDebugLog; -import dev.nandi0813.practice.telemetry.config.TelemetryConfig; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.Duration; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -public enum AiTrainingLogger { - ; - - private static final Set ALLOWED_LADDER_TYPES = Set.of("basic", "build", "sumo", "boxing"); - private static final int MAX_QUEUE_SIZE = 300; - private static final int MAX_ATTEMPTS = 3; - private static final long RETRY_BACKOFF_MS = 300L; - private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(3); - private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(5); - - private static final AtomicBoolean initialized = new AtomicBoolean(false); - private static final AtomicInteger droppedRecords = new AtomicInteger(0); - private static final AtomicInteger failedRequests = new AtomicInteger(0); - private static final AtomicInteger sentRequests = new AtomicInteger(0); - - private static ExecutorService writerExecutor; - private static HttpClient httpClient; - private static URI endpointUri; - private static String authToken; - private static volatile boolean transportEnabled; - - public static void logAsync(AiTrainingMatchPayload payload) { - if (payload == null || payload.rows() == null || payload.rows().isEmpty()) { - return; - } - - String normalizedLadderType = payload.ladderType() == null - ? "" - : payload.ladderType().trim().toLowerCase(Locale.ROOT); - if (!ALLOWED_LADDER_TYPES.contains(normalizedLadderType)) { - return; - } - - ensureInitialized(); - if (!transportEnabled || writerExecutor == null || writerExecutor.isShutdown()) { - droppedRecords.incrementAndGet(); - return; - } - - try { - writerExecutor.execute(() -> sendRecord(payload)); - } catch (Exception exception) { - droppedRecords.incrementAndGet(); - TelemetryDebugLog.console("AI training logger rejected a record: " + exception.getMessage()); - } - } - - public static void shutdown() { - if (writerExecutor == null) { - return; - } - - writerExecutor.shutdown(); - try { - if (!writerExecutor.awaitTermination(5, TimeUnit.SECONDS)) { - writerExecutor.shutdownNow(); - } - } catch (InterruptedException interruptedException) { - Thread.currentThread().interrupt(); - writerExecutor.shutdownNow(); - } finally { - initialized.set(false); - writerExecutor = null; - httpClient = null; - endpointUri = null; - authToken = null; - transportEnabled = false; - } - } - - private static void ensureInitialized() { - if (!initialized.compareAndSet(false, true)) { - return; - } - - if (!TelemetryBootstrap.isResolved()) { - initialized.set(false); - return; - } - - if (!TelemetryBootstrap.isAiCollectionActive()) { - transportEnabled = false; - return; - } - - endpointUri = TelemetryConfig.resolveAiMatchesEndpoint(); - authToken = TelemetryConfig.resolveConfiguredToken(); - - if (endpointUri == null) { - transportEnabled = false; - TelemetryDebugLog.console("AI training transport disabled: invalid AI endpoint."); - return; - } - - ThreadFactory factory = runnable -> { - Thread thread = new Thread(runnable, "zpp-ai-training-writer"); - thread.setDaemon(true); - return thread; - }; - - writerExecutor = new ThreadPoolExecutor( - 1, - 1, - 0L, - TimeUnit.MILLISECONDS, - new ArrayBlockingQueue<>(MAX_QUEUE_SIZE), - factory, - new ThreadPoolExecutor.AbortPolicy() - ); - - httpClient = HttpClient.newBuilder() - .connectTimeout(CONNECT_TIMEOUT) - .followRedirects(HttpClient.Redirect.NORMAL) - .build(); - transportEnabled = true; - } - - private static void sendRecord(AiTrainingMatchPayload payload) { - if (!transportEnabled || endpointUri == null || httpClient == null) { - droppedRecords.incrementAndGet(); - return; - } - - String jsonPayload = payload.toJson().toString(); - String idempotencyKey = payload.matchId(); - if (payload.schemaVersion() != 1 || idempotencyKey == null || idempotencyKey.isBlank()) { - droppedRecords.incrementAndGet(); - return; - } - - TelemetryBootstrap.fetchAiCollectionEnabledAsync() - .whenComplete((enabled, throwable) -> { - if (throwable != null || !Boolean.TRUE.equals(enabled)) { - return; - } - - sendRecordAttemptAsync(payload, jsonPayload, idempotencyKey, 1); - }); - } - - private static boolean isRetryable(int statusCode) { - return statusCode == 408 || statusCode == 429 || (statusCode >= 500 && statusCode <= 599); - } - - private static void sendRecordAttemptAsync(AiTrainingMatchPayload payload, String jsonPayload, String idempotencyKey, int attempt) { - HttpRequest.Builder builder = HttpRequest.newBuilder(endpointUri) - .timeout(REQUEST_TIMEOUT) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("X-Idempotency-Key", idempotencyKey) - .header("X-AI-Training-Schema-Version", String.valueOf(payload.schemaVersion())) - .POST(HttpRequest.BodyPublishers.ofString(jsonPayload)); - - if (authToken != null && !authToken.isBlank()) { - builder.header("Authorization", "Bearer " + authToken); - } - - httpClient.sendAsync(builder.build(), HttpResponse.BodyHandlers.ofString()) - .whenComplete((response, throwable) -> { - if (throwable == null && response != null) { - int statusCode = response.statusCode(); - if (statusCode == 200 || statusCode == 201 || statusCode == 202) { - sentRequests.incrementAndGet(); - return; - } - - if (!isRetryable(statusCode) || attempt >= MAX_ATTEMPTS) { - failedRequests.incrementAndGet(); - TelemetryDebugLog.console("AI training REST failed (status=" + statusCode + ", match=" + payload.matchId() + ")"); - return; - } - } else if (attempt >= MAX_ATTEMPTS) { - failedRequests.incrementAndGet(); - String message = throwable != null ? throwable.getMessage() : "unknown error"; - TelemetryDebugLog.console("AI training REST exception (match=" + payload.matchId() + "): " + message); - return; - } - - if (writerExecutor == null || writerExecutor.isShutdown()) { - droppedRecords.incrementAndGet(); - return; - } - - CompletableFuture.delayedExecutor(RETRY_BACKOFF_MS, TimeUnit.MILLISECONDS, writerExecutor) - .execute(() -> sendRecordAttemptAsync(payload, jsonPayload, idempotencyKey, attempt + 1)); - }); - } - -} - - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/transport/ai/AiTrainingMatchPayload.java b/core/src/main/java/dev/nandi0813/practice/telemetry/transport/ai/AiTrainingMatchPayload.java deleted file mode 100644 index fb7a358ad..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/transport/ai/AiTrainingMatchPayload.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.nandi0813.practice.telemetry.transport.ai; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.util.List; - -public record AiTrainingMatchPayload( - int schemaVersion, - String matchId, - String ladderName, - String ladderType, - String arenaName, - String arenaType, - String serverHash, - long createdAtTs, - List rows -) { - - public JSONObject toJson() { - JSONObject json = new JSONObject(); - json.put("schema_version", schemaVersion); - json.put("match_id", matchId); - json.put("ladderName", ladderName); - json.put("ladderType", ladderType); - json.put("arenaName", arenaName); - json.put("arenaType", arenaType); - json.put("serverHash", serverHash); - json.put("created_at_ts", createdAtTs); - - JSONArray rowArray = new JSONArray(); - for (JSONObject row : rows) { - rowArray.put(row); - } - json.put("rows", rowArray); - return json; - } -} - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/transport/regular/TelemetryLogger.java b/core/src/main/java/dev/nandi0813/practice/telemetry/transport/regular/TelemetryLogger.java deleted file mode 100644 index dd0659b5e..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/transport/regular/TelemetryLogger.java +++ /dev/null @@ -1,204 +0,0 @@ -package dev.nandi0813.practice.telemetry.transport.regular; - -import dev.nandi0813.practice.telemetry.MatchTelemetry; -import dev.nandi0813.practice.telemetry.bootstrap.TelemetryBootstrap; -import dev.nandi0813.practice.telemetry.bootstrap.TelemetryDebugLog; -import dev.nandi0813.practice.telemetry.config.TelemetryConfig; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.Duration; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -public enum TelemetryLogger { - ; - - private static final int MAX_QUEUE_SIZE = 2000; - private static final int MAX_ATTEMPTS = 3; - private static final long RETRY_BACKOFF_MS = 300L; - private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(3); - private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(5); - - private static final AtomicBoolean initialized = new AtomicBoolean(false); - private static final AtomicInteger droppedRecords = new AtomicInteger(0); - private static final AtomicInteger failedRequests = new AtomicInteger(0); - private static final AtomicInteger sentRequests = new AtomicInteger(0); - - private static ExecutorService writerExecutor; - private static HttpClient httpClient; - private static URI endpointUri; - private static String authToken; - private static volatile boolean transportEnabled; - - public static void logAsync(MatchTelemetry telemetry) { - if (telemetry == null) { - return; - } - - ensureInitialized(); - if (!transportEnabled || writerExecutor == null || writerExecutor.isShutdown()) { - droppedRecords.incrementAndGet(); - return; - } - - try { - writerExecutor.execute(() -> sendRecord(telemetry)); - } catch (Exception exception) { - droppedRecords.incrementAndGet(); - TelemetryDebugLog.console("Telemetry logger rejected a record: " + exception.getMessage()); - } - } - - public static int getDroppedRecords() { - return droppedRecords.get(); - } - - public static int getFailedRequests() { - return failedRequests.get(); - } - - public static int getSentRequests() { - return sentRequests.get(); - } - - public static void shutdown() { - if (writerExecutor == null) { - return; - } - - writerExecutor.shutdown(); - try { - if (!writerExecutor.awaitTermination(5, TimeUnit.SECONDS)) { - writerExecutor.shutdownNow(); - } - } catch (InterruptedException interruptedException) { - Thread.currentThread().interrupt(); - writerExecutor.shutdownNow(); - } finally { - initialized.set(false); - writerExecutor = null; - httpClient = null; - endpointUri = null; - authToken = null; - transportEnabled = false; - } - } - - private static void ensureInitialized() { - if (initialized.compareAndSet(false, true)) { - if (!TelemetryBootstrap.isResolved()) { - initialized.set(false); - return; - } - - if (!TelemetryBootstrap.isActive()) { - transportEnabled = false; - return; - } - - endpointUri = TelemetryConfig.resolveMatchesEndpoint(); - authToken = TelemetryConfig.resolveConfiguredToken(); - - if (endpointUri == null) { - transportEnabled = false; - TelemetryDebugLog.console("Telemetry transport disabled: invalid telemetry endpoint in TelemetryLogger."); - return; - } - - ThreadFactory factory = runnable -> { - Thread thread = new Thread(runnable, "zpp-telemetry-writer"); - thread.setDaemon(true); - return thread; - }; - - writerExecutor = new ThreadPoolExecutor( - 1, - 1, - 0L, - TimeUnit.MILLISECONDS, - new java.util.concurrent.ArrayBlockingQueue<>(MAX_QUEUE_SIZE), - factory, - new ThreadPoolExecutor.AbortPolicy() - ); - - httpClient = HttpClient.newBuilder() - .connectTimeout(CONNECT_TIMEOUT) - .followRedirects(HttpClient.Redirect.NORMAL) - .build(); - transportEnabled = true; - } - } - - public static URI resolveConfiguredBaseEndpoint() { - return TelemetryConfig.resolveConfiguredBaseEndpoint(); - } - - public static String resolveConfiguredToken() { - return TelemetryConfig.resolveConfiguredToken(); - } - - private static void sendRecord(MatchTelemetry telemetry) { - if (!transportEnabled || endpointUri == null || httpClient == null) { - droppedRecords.incrementAndGet(); - return; - } - - sendRecordAttemptAsync(telemetry, telemetry.toJson().toString(), telemetry.matchId(), 1); - } - - private static boolean isRetryable(int statusCode) { - return statusCode == 408 || statusCode == 429 || (statusCode >= 500 && statusCode <= 599); - } - - private static void sendRecordAttemptAsync(MatchTelemetry telemetry, String payload, String idempotencyKey, int attempt) { - HttpRequest.Builder builder = HttpRequest.newBuilder(endpointUri) - .timeout(REQUEST_TIMEOUT) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .header("X-Telemetry-Schema-Version", String.valueOf(telemetry.schemaVersion())) - .header("X-Telemetry-Source", "ZonePracticePro") - .header("X-Idempotency-Key", idempotencyKey) - .POST(HttpRequest.BodyPublishers.ofString(payload)); - - if (authToken != null && !authToken.isBlank()) { - builder.header("Authorization", "Bearer " + authToken); - } - - httpClient.sendAsync(builder.build(), HttpResponse.BodyHandlers.ofString()) - .whenComplete((response, throwable) -> { - if (throwable == null && response != null) { - int statusCode = response.statusCode(); - if (statusCode >= 200 && statusCode < 300) { - sentRequests.incrementAndGet(); - return; - } - - if (!isRetryable(statusCode) || attempt >= MAX_ATTEMPTS) { - failedRequests.incrementAndGet(); - TelemetryDebugLog.console("Telemetry REST failed (status=" + statusCode + ", match=" + telemetry.matchId() + ")"); - return; - } - } else if (attempt >= MAX_ATTEMPTS) { - failedRequests.incrementAndGet(); - String message = throwable != null ? throwable.getMessage() : "unknown error"; - TelemetryDebugLog.console("Telemetry REST exception (match=" + telemetry.matchId() + "): " + message); - return; - } - - if (writerExecutor == null || writerExecutor.isShutdown()) { - droppedRecords.incrementAndGet(); - return; - } - - CompletableFuture.delayedExecutor(RETRY_BACKOFF_MS, TimeUnit.MILLISECONDS, writerExecutor) - .execute(() -> sendRecordAttemptAsync(telemetry, payload, idempotencyKey, attempt + 1)); - }); - } - -} - - diff --git a/core/src/main/java/dev/nandi0813/practice/telemetry/transport/stats/PracticeStatsTelemetryLogger.java b/core/src/main/java/dev/nandi0813/practice/telemetry/transport/stats/PracticeStatsTelemetryLogger.java deleted file mode 100644 index ae01e4067..000000000 --- a/core/src/main/java/dev/nandi0813/practice/telemetry/transport/stats/PracticeStatsTelemetryLogger.java +++ /dev/null @@ -1,545 +0,0 @@ -package dev.nandi0813.practice.telemetry.transport.stats; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import dev.nandi0813.practice.ZonePractice; -import dev.nandi0813.practice.manager.backend.BackendManager; -import dev.nandi0813.practice.manager.ladder.abstraction.normal.NormalLadder; -import dev.nandi0813.practice.manager.profile.Profile; -import dev.nandi0813.practice.manager.profile.ProfileManager; -import dev.nandi0813.practice.manager.profile.statistics.LadderStats; -import dev.nandi0813.practice.manager.profile.statistics.ProfileStat; -import dev.nandi0813.practice.telemetry.ServerFingerprintUtil; -import dev.nandi0813.practice.telemetry.bootstrap.TelemetryDebugLog; -import dev.nandi0813.practice.telemetry.config.TelemetryConfig; -import org.bukkit.Bukkit; -import org.bukkit.scheduler.BukkitTask; - -import java.net.URI; -import java.net.URLEncoder; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -public enum PracticeStatsTelemetryLogger { - ; - - private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(3); - private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(5); - private static final long FLUSH_PERIOD_TICKS = 20L * 60L * 2L; - private static final long BOOTSTRAP_BURST_PERIOD_TICKS = 5L; - private static final int MAX_BATCH_SIZE = 200; - private static final int MAX_IN_FLIGHT_UPLOADS = 4; - - private static final AtomicBoolean initialized = new AtomicBoolean(false); - private static final AtomicBoolean flushInProgress = new AtomicBoolean(false); - private static final AtomicBoolean unauthorizedLogged = new AtomicBoolean(false); - private static final AtomicBoolean bootstrapCheckStarted = new AtomicBoolean(false); - private static final AtomicBoolean profilesLoaded = new AtomicBoolean(false); - private static final AtomicBoolean bootstrapBurstActive = new AtomicBoolean(false); - private static final AtomicInteger inFlightUploads = new AtomicInteger(0); - - private static final Set dirtyPlayers = ConcurrentHashMap.newKeySet(); - private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create(); - - private static volatile BukkitTask flushTask; - private static volatile BukkitTask bootstrapBurstTask; - private static volatile URI endpointUri; - private static volatile URI serverUploadedEndpointUri; - private static volatile URI serverUploadedFallbackEndpointUri; - private static volatile String authToken; - private static volatile String serverHash; - private static volatile HttpClient httpClient; - private static volatile boolean transportEnabled; - - public static void initialize() { - if (!initialized.compareAndSet(false, true)) { - return; - } - - if (!TelemetryConfig.isRegularEnabled()) { - return; - } - - endpointUri = TelemetryConfig.resolvePracticeStatsUploadEndpoint(); - serverUploadedEndpointUri = TelemetryConfig.resolvePracticeStatsServerUploadedEndpoint(); - serverUploadedFallbackEndpointUri = TelemetryConfig.resolvePracticeStatsServerUploadedFallbackEndpoint(); - authToken = TelemetryConfig.resolveConfiguredToken(); - serverHash = resolveServerHash(); - - if (endpointUri == null) { - TelemetryDebugLog.warning("Practice stats telemetry disabled: endpoint is not configured."); - return; - } - - if (serverHash == null || serverHash.isBlank()) { - TelemetryDebugLog.warning("Practice stats telemetry disabled: server hash is missing."); - return; - } - - httpClient = HttpClient.newBuilder() - .connectTimeout(CONNECT_TIMEOUT) - .followRedirects(HttpClient.Redirect.NORMAL) - .build(); - - transportEnabled = true; - - flushTask = Bukkit.getScheduler().runTaskTimer( - ZonePractice.getInstance(), - PracticeStatsTelemetryLogger::flushDirtyBatch, - FLUSH_PERIOD_TICKS, - FLUSH_PERIOD_TICKS - ); - - tryStartBootstrapCheck("initialize"); - } - - public static void markDirty(Profile profile) { - if (profile == null) { - return; - } - - markDirty(profile.getUuid()); - } - - public static void markDirty(UUID uuid) { - if (uuid == null || !initialized.get() || !transportEnabled) { - return; - } - - dirtyPlayers.add(uuid); - } - - public static void shutdown() { - BukkitTask currentTask = flushTask; - if (currentTask != null) { - currentTask.cancel(); - flushTask = null; - } - - BukkitTask currentBootstrapTask = bootstrapBurstTask; - if (currentBootstrapTask != null) { - currentBootstrapTask.cancel(); - bootstrapBurstTask = null; - } - - flushDirtyBatchNow(); - - dirtyPlayers.clear(); - httpClient = null; - endpointUri = null; - serverUploadedEndpointUri = null; - serverUploadedFallbackEndpointUri = null; - authToken = null; - serverHash = null; - transportEnabled = false; - initialized.set(false); - unauthorizedLogged.set(false); - bootstrapCheckStarted.set(false); - profilesLoaded.set(false); - bootstrapBurstActive.set(false); - inFlightUploads.set(0); - } - - public static void onProfilesLoaded() { - profilesLoaded.set(true); - tryStartBootstrapCheck("profiles-loaded"); - } - - private static void tryStartBootstrapCheck(String source) { - if (!initialized.get() || !transportEnabled || httpClient == null || serverUploadedEndpointUri == null || serverHash == null) { - TelemetryDebugLog.info("Practice stats bootstrap check skipped (source=" + source + "): telemetry transport is not ready yet."); - return; - } - - if (!profilesLoaded.get()) { - TelemetryDebugLog.info("Practice stats bootstrap check waiting for profiles (source=" + source + ")."); - return; - } - - if (!bootstrapCheckStarted.compareAndSet(false, true)) { - return; - } - - TelemetryDebugLog.info("Practice stats bootstrap check started for server hash " + serverHash - + " using endpoint " + serverUploadedEndpointUri + "."); - checkServerUploaded(serverUploadedEndpointUri, true); - } - - private static void checkServerUploaded(URI endpoint, boolean allowFallbackOn404) { - if (endpoint == null || httpClient == null) { - return; - } - - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(resolveServerUploadedCheckUri(endpoint)) - .timeout(REQUEST_TIMEOUT) - .header("Accept", "application/json") - .GET(); - - if (authToken != null && !authToken.isBlank()) { - requestBuilder.header("Authorization", "Bearer " + authToken); - } - - httpClient.sendAsync(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()) - .whenComplete((response, throwable) -> { - if (throwable != null || response == null) { - TelemetryDebugLog.warning("Practice stats bootstrap check failed; continuing with incremental updates only."); - return; - } - - if (response.statusCode() == 401 && unauthorizedLogged.compareAndSet(false, true)) { - TelemetryDebugLog.warning("Practice stats telemetry unauthorized (401). Check Bearer token configuration."); - return; - } - - if (response.statusCode() == 404 && allowFallbackOn404 && shouldUseFallbackEndpoint(endpoint)) { - TelemetryDebugLog.info("Practice stats bootstrap check got 404 on " + endpoint + ", retrying fallback endpoint " + serverUploadedFallbackEndpointUri + "."); - checkServerUploaded(serverUploadedFallbackEndpointUri, false); - return; - } - - if (response.statusCode() < 200 || response.statusCode() >= 300) { - TelemetryDebugLog.warning("Practice stats bootstrap check returned HTTP " + response.statusCode() + "; continuing with incremental updates only."); - return; - } - - Boolean uploaded = parseUploadedFlag(response.body()); - if (uploaded == null) { - TelemetryDebugLog.warning("Practice stats bootstrap check returned invalid JSON; continuing with incremental updates only."); - return; - } - - if (uploaded) { - TelemetryDebugLog.info("Practice stats bootstrap check reports uploaded=true; skipping full initial sync."); - return; - } - - Bukkit.getScheduler().runTask(ZonePractice.getInstance(), () -> { - Set allProfileUuids = new HashSet<>(ProfileManager.getInstance().getProfiles().keySet()); - dirtyPlayers.addAll(allProfileUuids); - TelemetryDebugLog.info("Practice stats bootstrap check reports uploaded=false; queued " - + allProfileUuids.size() + " profiles for full initial sync."); - startBootstrapBurstFlush(); - }); - }); - } - - private static void startBootstrapBurstFlush() { - if (!bootstrapBurstActive.compareAndSet(false, true)) { - return; - } - - bootstrapBurstTask = Bukkit.getScheduler().runTaskTimer( - ZonePractice.getInstance(), - () -> { - if (!transportEnabled) { - stopBootstrapBurstFlush(); - return; - } - - flushDirtyBatch(); - - if (dirtyPlayers.isEmpty() && inFlightUploads.get() == 0) { - TelemetryDebugLog.info("Practice stats full initial sync completed."); - stopBootstrapBurstFlush(); - } - }, - 1L, - BOOTSTRAP_BURST_PERIOD_TICKS - ); - } - - private static void stopBootstrapBurstFlush() { - BukkitTask currentTask = bootstrapBurstTask; - if (currentTask != null) { - currentTask.cancel(); - bootstrapBurstTask = null; - } - bootstrapBurstActive.set(false); - } - - private static boolean shouldUseFallbackEndpoint(URI endpoint) { - if (serverUploadedFallbackEndpointUri == null) { - return false; - } - - return !serverUploadedFallbackEndpointUri.toString().equals(endpoint.toString()); - } - - private static void flushDirtyBatch() { - if (!flushInProgress.compareAndSet(false, true)) { - return; - } - - if (!transportEnabled) { - flushInProgress.set(false); - return; - } - - try { - if (inFlightUploads.get() >= MAX_IN_FLIGHT_UPLOADS) { - return; - } - - List batch = drainDirtyUuids(MAX_BATCH_SIZE); - if (batch.isEmpty()) { - return; - } - - uploadBatch(batch, false); - } finally { - flushInProgress.set(false); - } - } - - private static void flushDirtyBatchNow() { - List batch = drainDirtyUuids(Integer.MAX_VALUE); - if (batch.isEmpty()) { - return; - } - - uploadBatch(batch, true); - } - - private static List drainDirtyUuids(int limit) { - List drained = new ArrayList<>(); - - for (UUID uuid : dirtyPlayers) { - if (drained.size() >= limit) { - break; - } - - if (dirtyPlayers.remove(uuid)) { - drained.add(uuid); - } - } - - return drained; - } - - private static void uploadBatch(List uuids, boolean syncOnCurrentThread) { - if (uuids.isEmpty() || endpointUri == null || httpClient == null || serverHash == null) { - return; - } - - Map payload = buildPayload(uuids); - if (payload == null) { - return; - } - - String payloadJson = GSON.toJson(payload); - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(endpointUri) - .timeout(REQUEST_TIMEOUT) - .header("Content-Type", "application/json") - .header("Accept", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(payloadJson)); - - if (authToken != null && !authToken.isBlank()) { - requestBuilder.header("Authorization", "Bearer " + authToken); - } - - HttpRequest request = requestBuilder.build(); - - if (syncOnCurrentThread) { - try { - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - handleResponse(response.statusCode(), uuids); - } catch (Exception ignored) { - } - return; - } - - if (inFlightUploads.incrementAndGet() > MAX_IN_FLIGHT_UPLOADS) { - inFlightUploads.decrementAndGet(); - requeue(uuids); - return; - } - - httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()) - .whenComplete((response, throwable) -> { - try { - if (throwable != null) { - requeue(uuids); - return; - } - - if (response == null) { - requeue(uuids); - return; - } - - handleResponse(response.statusCode(), uuids); - } finally { - inFlightUploads.decrementAndGet(); - } - }); - } - - private static void handleResponse(int statusCode, List uuids) { - if (statusCode >= 200 && statusCode < 300) { - return; - } - - if (statusCode == 503) { - return; - } - - if (statusCode == 401) { - if (unauthorizedLogged.compareAndSet(false, true)) { - TelemetryDebugLog.warning("Practice stats telemetry unauthorized (401). Check Bearer token configuration."); - } - return; - } - - requeue(uuids); - } - - private static void requeue(List uuids) { - dirtyPlayers.addAll(uuids); - } - - private static Map buildPayload(List uuids) { - List> globalStats = new ArrayList<>(); - List> ladderStats = new ArrayList<>(); - - for (UUID uuid : uuids) { - Profile profile = ProfileManager.getInstance().getProfile(uuid); - if (profile == null) { - continue; - } - - ProfileStat stats = profile.getStats(); - String username = profile.getPlayer().getName() == null ? uuid.toString() : profile.getPlayer().getName(); - globalStats.add(toGlobalStatsMap(profile, stats, username)); - - for (Map.Entry entry : stats.getLadderStats().entrySet()) { - NormalLadder ladder = entry.getKey(); - LadderStats ladderStat = entry.getValue(); - ladderStats.add(toLadderStatsMap(profile, stats, username, ladder, ladderStat)); - } - } - - if (globalStats.isEmpty() && ladderStats.isEmpty()) { - return null; - } - - Map payload = new LinkedHashMap<>(); - payload.put("global_stats", globalStats); - payload.put("ladder_stats", ladderStats); - return payload; - } - - private static String resolveServerHash() { - String generated = ServerFingerprintUtil.getServerId(); - return BackendManager.getOrCreatePracticeStatsServerHash(generated); - } - - private static URI resolveServerUploadedCheckUri(URI endpoint) { - String encodedHash = URLEncoder.encode(serverHash, StandardCharsets.UTF_8); - - try { - return new URI( - endpoint.getScheme(), - endpoint.getUserInfo(), - endpoint.getHost(), - endpoint.getPort(), - endpoint.getPath(), - "server_hash=" + encodedHash, - null - ); - } catch (Exception exception) { - return endpoint; - } - } - - private static Boolean parseUploadedFlag(String responseBody) { - try { - JsonObject jsonObject = JsonParser.parseString(responseBody).getAsJsonObject(); - if (!jsonObject.has("uploaded")) { - return null; - } - return jsonObject.get("uploaded").getAsBoolean(); - } catch (Exception ignored) { - return null; - } - } - - private static Map toGlobalStatsMap(Profile profile, ProfileStat stats, String username) { - Map global = new LinkedHashMap<>(); - global.put("username", username); - global.put("uuid", profile.getUuid().toString()); - global.put("serverHash", serverHash); - global.put("firstJoin", profile.getFirstJoin()); - global.put("lastJoin", profile.getLastJoin()); - global.put("unrankedWins", stats.getWins(false)); - global.put("unrankedLosses", stats.getLosses(false)); - global.put("rankedWins", stats.getWins(true)); - global.put("rankedLosses", stats.getLosses(true)); - global.put("globalElo", stats.getGlobalElo()); - - String division = stats.getDivision() == null ? null : stripDivisionColors(stats.getDivision().getFullName()); - global.put("globalRank", division); - - global.put("experience", stats.getExperience()); - global.put("winStreak", stats.getWinStreak()); - global.put("bestWinStreak", stats.getBestWinStreak()); - global.put("loseStreak", stats.getLoseStreak()); - global.put("bestLoseStreak", stats.getBestLoseStreak()); - return global; - } - - private static Map toLadderStatsMap(Profile profile, - ProfileStat stats, - String username, - NormalLadder ladder, - LadderStats ladderStats) { - Map ladderMap = new LinkedHashMap<>(); - ladderMap.put("username", username); - ladderMap.put("uuid", profile.getUuid().toString()); - ladderMap.put("serverHash", serverHash); - ladderMap.put("ladder", ladder.getName().toLowerCase()); - ladderMap.put("unrankedWins", ladderStats.getUnRankedWins()); - ladderMap.put("unrankedLosses", ladderStats.getUnRankedLosses()); - ladderMap.put("unrankedWinStreak", ladderStats.getUnRankedWinStreak()); - ladderMap.put("unrankedBestWinStreak", ladderStats.getUnRankedBestWinStreak()); - ladderMap.put("unrankedLoseStreak", ladderStats.getUnRankedLoseStreak()); - ladderMap.put("unrankedBestLoseStreak", ladderStats.getUnRankedBestLoseStreak()); - ladderMap.put("rankedWins", ladderStats.getRankedWins()); - ladderMap.put("rankedLosses", ladderStats.getRankedLosses()); - ladderMap.put("rankedWinStreak", ladderStats.getRankedWinStreak()); - ladderMap.put("rankedBestWinStreak", ladderStats.getRankedBestWinStreak()); - ladderMap.put("rankedLoseStreak", ladderStats.getRankedLoseStreak()); - ladderMap.put("rankedBestLoseStreak", ladderStats.getRankedBestLoseStreak()); - ladderMap.put("elo", ladderStats.getElo()); - - String division = stats.getDivision() == null ? null : stripDivisionColors(stats.getDivision().getFullName()); - ladderMap.put("rank", division); - - ladderMap.put("kills", ladderStats.getKills()); - ladderMap.put("deaths", ladderStats.getDeaths()); - return ladderMap; - } - - /** - * Strips MiniMessage color codes (e.g., <gray>, <gold>) from a division name. - * Converts "<gray>Recruit" to "Recruit" - */ - private static String stripDivisionColors(String division) { - if (division == null || division.isEmpty()) { - return ""; - } - // Deserialize the MiniMessage format and extract plain text - return division.replaceAll("<[^>]+>", ""); - } -} - - - diff --git a/core/src/main/java/dev/nandi0813/practice/util/ArmorUtil.java b/core/src/main/java/dev/nandi0813/practice/util/ArmorUtil.java index d461d888d..af2ec6038 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/ArmorUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/ArmorUtil.java @@ -2,8 +2,9 @@ import org.bukkit.inventory.ItemStack; -public enum ArmorUtil { - ; +public final class ArmorUtil { + + private ArmorUtil() {} public static boolean isHelmet(ItemStack item) { return item.getType().name().endsWith("_HELMET") || item.getType().name().equalsIgnoreCase("CARVED_PUMPKIN"); diff --git a/core/src/main/java/dev/nandi0813/practice/util/ChatFormatUtil.java b/core/src/main/java/dev/nandi0813/practice/util/ChatFormatUtil.java index d21986f64..41151561a 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/ChatFormatUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/ChatFormatUtil.java @@ -12,8 +12,9 @@ import java.util.ArrayList; import java.util.List; -public enum ChatFormatUtil { - ; +public final class ChatFormatUtil { + + private ChatFormatUtil() {} private static String normalizeStaticSpacing(String formattedWithoutMessage) { if (formattedWithoutMessage == null || formattedWithoutMessage.isEmpty()) { diff --git a/core/src/main/java/dev/nandi0813/practice/util/Common.java b/core/src/main/java/dev/nandi0813/practice/util/Common.java index caa27cc7e..4844294b2 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/Common.java +++ b/core/src/main/java/dev/nandi0813/practice/util/Common.java @@ -4,6 +4,7 @@ import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; import me.clip.placeholderapi.PlaceholderAPI; +import dev.nandi0813.practice.manager.profile.Profile; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; @@ -16,12 +17,14 @@ import org.bukkit.inventory.meta.ItemMeta; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; -public enum Common { - ; +public final class Common { + + private Common() {} public static void send(CommandSender sender, Component component) { if (sender == null) return; @@ -29,15 +32,7 @@ public static void send(CommandSender sender, Component component) { } public static void sendMMMessage(Player player, String line) { - if (line == null) { - return; - } - - if (line.contains("&") || line.contains("§")) { - line = StringUtil.legacyColorToMiniMessage(line); - } - - if (line.isEmpty()) { + if (line == null || line.isEmpty()) { return; } @@ -45,15 +40,36 @@ public static void sendMMMessage(Player player, String line) { line = PlaceholderAPI.setPlaceholders(player, line); } - send(player, ZonePractice.getMiniMessage().deserialize(line)); + send(player, ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(line))); } public static void sendConsoleMMMessage(String string) { - send(ZonePractice.getInstance().getServer().getConsoleSender(), ZonePractice.getMiniMessage().deserialize(string)); + send(ZonePractice.getInstance().getServer().getConsoleSender(), ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(string))); + } + + public static void playDeathEffect(Profile killerProfile, org.bukkit.Location location, java.util.List viewers) { + try { + if (killerProfile == null || killerProfile.getCosmeticsData() == null) return; + var deathEffect = killerProfile.getCosmeticsData().getDeathEffect(); + if (deathEffect == null) return; + deathEffect.play(location, viewers); + } catch (Exception ignored) {} + } + + public static void sendMessage(Collection players, Collection spectators, String message, boolean includeSpectators) { + for (Player player : players) { + sendMMMessage(player, message); + } + if (includeSpectators) { + for (Player spectator : spectators) { + sendMMMessage(spectator, message); + } + } } public static Component deserializeMiniMessage(String line) { - return ZonePractice.getMiniMessage().deserialize(line); + if (line == null || line.isEmpty()) return Component.empty(); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(line)); } public static String serializeComponentToLegacyString(Component component) { @@ -61,35 +77,29 @@ public static String serializeComponentToLegacyString(Component component) { } public static String mmToNormal(String line) { - if (line.contains("&") || line.contains("§")) { - line = StringUtil.legacyColorToMiniMessage(line); - } - return StringUtil.CC(serializeComponentToLegacyString(deserializeMiniMessage(line))); } public static String serializeNormalToMMString(String normalString) { - String normalized = normalString.replace('&', LegacyComponentSerializer.SECTION_CHAR); - Component component = LegacyComponentSerializer.legacySection().deserialize(normalized); - return ZonePractice.getMiniMessage().serialize(component); + return StringUtil.legacyToMiniMessage(normalString); } public static String colorize(String message) { - return StringUtil.CC(message); + return serializeComponentToLegacyString(deserializeMiniMessage(message)); } public static Component legacyToComponent(String message) { if (message == null) { return Component.empty(); } - return LegacyComponentSerializer.legacyAmpersand().deserialize(message); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(message)); } public static String stripLegacyColor(String message) { if (message == null || message.isEmpty()) { return ""; } - Component component = LegacyComponentSerializer.legacyAmpersand().deserialize(message); + Component component = ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(message)); return PlainTextComponentSerializer.plainText().serialize(component); } @@ -108,6 +118,13 @@ public static String getItemDisplayName(ItemMeta itemMeta) { return serializeComponentToLegacyString(itemMeta.displayName()); } + public static String getItemDisplayNameMiniMessage(ItemMeta itemMeta) { + if (itemMeta == null || !itemMeta.hasDisplayName() || itemMeta.displayName() == null) { + return ""; + } + return ZonePractice.getMiniMessage().serialize(itemMeta.displayName()); + } + public static String getItemDisplayName(ItemStack itemStack) { if (itemStack == null || !itemStack.hasItemMeta()) { return ""; @@ -115,6 +132,13 @@ public static String getItemDisplayName(ItemStack itemStack) { return getItemDisplayName(itemStack.getItemMeta()); } + public static String getItemDisplayNameMiniMessage(ItemStack itemStack) { + if (itemStack == null || !itemStack.hasItemMeta()) { + return ""; + } + return getItemDisplayNameMiniMessage(itemStack.getItemMeta()); + } + public static short getItemDamage(ItemStack itemStack) { if (itemStack == null || !itemStack.hasItemMeta()) { return 0; @@ -183,4 +207,4 @@ public static Enchantment resolveEnchantment(String enchantmentName) { } return null; } -} \ No newline at end of file +} diff --git a/core/src/main/java/dev/nandi0813/practice/util/InventoryUtil.java b/core/src/main/java/dev/nandi0813/practice/util/InventoryUtil.java index de75215d8..ac38e4ff2 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/InventoryUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/InventoryUtil.java @@ -1,13 +1,17 @@ package dev.nandi0813.practice.util; +import dev.nandi0813.practice.ZonePractice; +import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.inventory.Inventory; -public enum InventoryUtil { - ; +public final class InventoryUtil { + + private InventoryUtil() {} public static Inventory createInventory(String title, int row) { - return Bukkit.getServer().createInventory(null, row * 9, StringUtil.CC(title)); + Component component = ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(title)); + return Bukkit.getServer().createInventory(null, row * 9, component); } } diff --git a/core/src/main/java/dev/nandi0813/practice/util/ItemCreateUtil.java b/core/src/main/java/dev/nandi0813/practice/util/ItemCreateUtil.java index 62a46bff1..ac75bfcca 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/ItemCreateUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/ItemCreateUtil.java @@ -1,10 +1,13 @@ package dev.nandi0813.practice.util; +import com.destroystokyo.paper.profile.PlayerProfile; import dev.nandi0813.practice.ZonePractice; import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; @@ -19,12 +22,12 @@ public class ItemCreateUtil { /** * Parses a raw config string into a {@link Component}, supporting all color formats: - * legacy {@code &c} / {@code §c} codes, shorthand hex {@code &#RRGGBB}, Bungeecord hex - * {@code &x&R&R&G&G&B&B}, bare {@code #RRGGBB}, and MiniMessage tags {@code }. + * legacy {@code } / {@code §c} codes, shorthand hex {@code &#RRGGBB}, Bungeecord hex + * {@code &x&G&G}, bare {@code #RRGGBB}, and MiniMessage tags {@code }. */ private static Component parseColor(String raw) { if (raw == null || raw.isEmpty()) return Component.empty(); - return ZonePractice.getMiniMessage().deserialize(StringUtil.translateColorsToMiniMessage(raw)) + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(raw)) .decorationIfAbsent(net.kyori.adventure.text.format.TextDecoration.ITALIC, net.kyori.adventure.text.format.TextDecoration.State.FALSE); } @@ -148,7 +151,14 @@ public static ItemStack hideItemFlags(ItemStack item) { public static ItemStack getPlayerHead(OfflinePlayer player) { ItemStack item = new ItemStack(Material.PLAYER_HEAD); SkullMeta meta = (SkullMeta) item.getItemMeta(); - if (meta != null) meta.setOwningPlayer(player); + if (meta != null && player != null) { + PlayerProfile profile = Bukkit.createProfile(player.getUniqueId(), player.getName()); + Player onlinePlayer = player.getPlayer(); + if (onlinePlayer != null) { + profile = onlinePlayer.getPlayerProfile(); + } + meta.setPlayerProfile(profile); + } item.setItemMeta(meta); return item; } diff --git a/core/src/main/java/dev/nandi0813/practice/util/ItemSerializationUtil.java b/core/src/main/java/dev/nandi0813/practice/util/ItemSerializationUtil.java index 99e931921..7b5d34b4f 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/ItemSerializationUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/ItemSerializationUtil.java @@ -9,8 +9,9 @@ import java.io.ByteArrayOutputStream; import java.util.Base64; -public enum ItemSerializationUtil { - ; +public final class ItemSerializationUtil { + + private ItemSerializationUtil() {} @Nullable public static String itemStackArrayToBase64(ItemStack[] items) { diff --git a/core/src/main/java/dev/nandi0813/practice/util/LastAttackerTracker.java b/core/src/main/java/dev/nandi0813/practice/util/LastAttackerTracker.java new file mode 100644 index 000000000..6d0d3c3e2 --- /dev/null +++ b/core/src/main/java/dev/nandi0813/practice/util/LastAttackerTracker.java @@ -0,0 +1,30 @@ +package dev.nandi0813.practice.util; + +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class LastAttackerTracker { + + private final Map lastAttackerMap = new HashMap<>(); + private final Map lastAttackerTime = new HashMap<>(); + private static final long LAST_ATTACKER_EXPIRY_MS = 4_000L; + + public void recordAttack(Player victim, Player attacker) { + if (victim == null || attacker == null || victim.equals(attacker)) return; + lastAttackerMap.put(victim.getUniqueId(), attacker.getUniqueId()); + lastAttackerTime.put(victim.getUniqueId(), System.currentTimeMillis()); + } + + public @Nullable Player getLastAttacker(Player victim, Collection candidates) { + Long time = lastAttackerTime.get(victim.getUniqueId()); + if (time == null || System.currentTimeMillis() - time > LAST_ATTACKER_EXPIRY_MS) return null; + UUID attackerUuid = lastAttackerMap.get(victim.getUniqueId()); + if (attackerUuid == null) return null; + for (Player p : candidates) { + if (attackerUuid.equals(p.getUniqueId())) return p; + } + return null; + } +} diff --git a/core/src/main/java/dev/nandi0813/practice/util/NameFormatUtil.java b/core/src/main/java/dev/nandi0813/practice/util/NameFormatUtil.java index 3242b3209..571633a73 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/NameFormatUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/NameFormatUtil.java @@ -12,13 +12,13 @@ import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.entity.Player; -public enum NameFormatUtil { - ; +public final class NameFormatUtil { - private static final PlainTextComponentSerializer PLAIN_TEXT_SERIALIZER = PlainTextComponentSerializer.plainText(); + private NameFormatUtil() {} - // ── Color helpers ──────────────────────────────────────────────────────── + private static final PlainTextComponentSerializer PLAIN_TEXT_SERIALIZER = PlainTextComponentSerializer.plainText(); + // Color helpers private static TextColor findFirstExplicitColor(Component component) { if (component == null) return null; if (component.color() != null) return component.color(); @@ -51,15 +51,10 @@ public static TextColor extractTrailingColor(Component component) { return findLastExplicitColor(component); } - // ── Template / placeholder helpers ────────────────────────────────────── - + // Template / placeholder helpers public static Component parseConfiguredComponent(String raw) { if (raw == null || raw.isEmpty()) return Component.empty(); - String normalized = raw; - if (normalized.contains("&") || normalized.contains("\u00A7")) { - normalized = StringUtil.legacyColorToMiniMessage(normalized); - } - return ZonePractice.getMiniMessage().deserialize(normalized); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(raw)); } public static Component applyDivisionPlaceholders(Component template, Profile profile) { @@ -83,8 +78,10 @@ public static Component applyPlayerPlaceholders(Component template, String playe /** * Applies any PlaceholderAPI placeholders present in {@code component} by - * serialising to MiniMessage, running PAPI, translating legacy/hex color codes, - * then re-parsing. Returns {@code component} unchanged if PAPI is not installed + * serialising to MiniMessage, running PAPI, then re-parsing. + * PAPI expansions may inject legacy {@code &} codes — these are converted + * to MiniMessage via the Adventure legacy serializer. + * Returns {@code component} unchanged if PAPI is not installed * or {@code player} is null. */ public static Component applyPAPIPlaceholders(Component component, Player player) { @@ -92,25 +89,19 @@ public static Component applyPAPIPlaceholders(Component component, Player player if (!SoftDependUtil.isPAPI_ENABLED) return component; String serialized = ZonePractice.getMiniMessage().serialize(component); String resolved = PlaceholderAPI.setPlaceholders(player, serialized); - String translated = StringUtil.translateColorsToMiniMessage(resolved); - return ZonePractice.getMiniMessage().deserialize(translated); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(resolved)); } public static String normalizePlayerNameTemplate(String rawTemplate) { if (rawTemplate == null || rawTemplate.isEmpty()) return rawTemplate; - String normalized = rawTemplate; - if (normalized.contains("&") || normalized.contains("\u00A7")) { - normalized = StringUtil.legacyColorToMiniMessage(normalized); - } - boolean hasPlayerPlaceholder = normalized.contains("%player%") || normalized.contains("%%player%%"); + boolean hasPlayerPlaceholder = rawTemplate.contains("%player%") || rawTemplate.contains("%%player%%"); if (hasPlayerPlaceholder) return rawTemplate; - String plainText = PLAIN_TEXT_SERIALIZER.serialize(ZonePractice.getMiniMessage().deserialize(normalized)).trim(); + String plainText = PLAIN_TEXT_SERIALIZER.serialize(ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(rawTemplate))).trim(); if (!plainText.isEmpty()) return rawTemplate; return rawTemplate + "%player%"; } - // ── Internal rendering ─────────────────────────────────────────────────── - + // Internal rendering private static Component renderTemplate(String rawTemplate, Profile profile, String playerName) { return renderTemplate(rawTemplate, profile, playerName, null); } @@ -135,7 +126,7 @@ private static Component renderTemplate(String rawTemplate, Profile profile, Str normalized = PlaceholderAPI.setPlaceholders(player, normalized); } - normalized = StringUtil.translateColorsToMiniMessage(normalized); + normalized = StringUtil.legacyToMiniMessage(normalized); String division = profile.getStats().getDivision() != null ? ZonePractice.getMiniMessage().serialize(profile.getStats().getDivision().getComponentFullName()) : ""; @@ -153,8 +144,7 @@ private static Component renderTemplate(String rawTemplate, Profile profile, Str return ZonePractice.getMiniMessage().deserialize(normalized); } - // ── Public resolution API ──────────────────────────────────────────────── - + // Public resolution API public static Component resolvePrefix(Profile profile) { return resolvePrefix(profile, null); } diff --git a/core/src/main/java/dev/nandi0813/practice/util/NumberUtil.java b/core/src/main/java/dev/nandi0813/practice/util/NumberUtil.java index f4201e05b..a8a9c1329 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/NumberUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/NumberUtil.java @@ -2,8 +2,9 @@ import java.text.DecimalFormat; -public enum NumberUtil { - ; +public final class NumberUtil { + + private NumberUtil() {} public static double roundDouble(double value) { DecimalFormat df = new DecimalFormat("0.00"); diff --git a/core/src/main/java/dev/nandi0813/practice/util/PAPIUtil.java b/core/src/main/java/dev/nandi0813/practice/util/PAPIUtil.java index d03376c4b..94193a4ce 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/PAPIUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/PAPIUtil.java @@ -5,8 +5,9 @@ import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; -public enum PAPIUtil { - ; +public final class PAPIUtil { + + private PAPIUtil() {} public static Component runThroughFormat(Player player, String line) { if (line == null || line.isEmpty()) { @@ -14,10 +15,10 @@ public static Component runThroughFormat(Player player, String line) { } if (SoftDependUtil.isPAPI_ENABLED) { - return ZonePractice.getMiniMessage().deserialize(PlaceholderAPI.setPlaceholders(player, line)); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(PlaceholderAPI.setPlaceholders(player, line))); } - return ZonePractice.getMiniMessage().deserialize(line); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(line)); } } diff --git a/core/src/main/java/dev/nandi0813/practice/util/PageUtil.java b/core/src/main/java/dev/nandi0813/practice/util/PageUtil.java index a62dd4ae7..009dec4fe 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/PageUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/PageUtil.java @@ -5,8 +5,9 @@ import java.util.ArrayList; import java.util.List; -public enum PageUtil { - ; +public final class PageUtil { + + private PageUtil() {} public static List getPageItems(List items, int page, int spaces) { int upperBound = page * spaces; diff --git a/core/src/main/java/dev/nandi0813/practice/util/PermanentConfig.java b/core/src/main/java/dev/nandi0813/practice/util/PermanentConfig.java index cff582620..40ad5d141 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/PermanentConfig.java +++ b/core/src/main/java/dev/nandi0813/practice/util/PermanentConfig.java @@ -2,8 +2,9 @@ import dev.nandi0813.practice.manager.backend.ConfigManager; -public enum PermanentConfig { - ; +public final class PermanentConfig { + + private PermanentConfig() {} public static final boolean ARENA_FAST_COPY_ENABLED = ConfigManager.getBoolean("ARENA.FAST-COPY.ENABLED"); public static final boolean ARENA_COPY_FAWE_ENABLED = ConfigManager.getBoolean("ARENA.FAST-COPY.USE-FAWE"); diff --git a/core/src/main/java/dev/nandi0813/practice/util/SaveResource.java b/core/src/main/java/dev/nandi0813/practice/util/SaveResource.java index de610c521..5d5e1bda1 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/SaveResource.java +++ b/core/src/main/java/dev/nandi0813/practice/util/SaveResource.java @@ -7,11 +7,15 @@ import dev.dejvokep.boostedyaml.settings.loader.LoaderSettings; import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings; import dev.nandi0813.practice.ZonePractice; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.*; public class SaveResource { @@ -49,10 +53,13 @@ public class SaveResource { "spleef.yml", "sumo.yml", "tntsumo.yml", - "vanilla.yml" + "vanilla.yml", + "sword.yml" }; public void saveResources(ZonePractice practice) { + Map backup = backupCustomKeys(practice); + for (String fileName : ROOT_FILES) { InputStream resource = practice.getResource(fileName); if (resource == null) { @@ -62,6 +69,8 @@ public void saveResources(ZonePractice practice) { saveResource(new File(practice.getDataFolder(), fileName), resource); } + restoreCustomKeys(practice, backup); + File ladderFolder = new File(practice.getDataFolder(), "ladders"); if (!ladderFolder.exists()) { for (String fileName : LADDER_FILES) { @@ -70,6 +79,80 @@ public void saveResources(ZonePractice practice) { } } + private Map backupCustomKeys(ZonePractice practice) { + File file = new File(practice.getDataFolder(), "config.yml"); + if (!file.exists()) return Collections.emptyMap(); + + YamlConfiguration disk; + try { + disk = new YamlConfiguration(); + disk.load(file); + } catch (IOException | InvalidConfigurationException e) { + return Collections.emptyMap(); + } + + YamlConfiguration bundled; + try (InputStream in = practice.getResource("config.yml")) { + if (in == null) return Collections.emptyMap(); + bundled = new YamlConfiguration(); + bundled.load(new InputStreamReader(in)); + } catch (IOException | InvalidConfigurationException e) { + return Collections.emptyMap(); + } + + Map backup = new HashMap<>(); + for (String key : disk.getKeys(true)) { + if (!bundled.isSet(key)) { + backup.put(key, disk.get(key)); + } + } + return backup; + } + + private void restoreCustomKeys(ZonePractice practice, Map backup) { + if (backup.isEmpty()) return; + + File file = new File(practice.getDataFolder(), "config.yml"); + if (!file.exists()) return; + + YamlConfiguration config = new YamlConfiguration(); + try { + config.load(file); + } catch (IOException | InvalidConfigurationException e) { + return; + } + + boolean changed = false; + for (Map.Entry entry : backup.entrySet()) { + if (config.isSet(entry.getKey())) continue; + config.set(entry.getKey(), fixTimeStrings(entry.getValue())); + changed = true; + } + + if (!changed) return; + + try { + config.save(file); + } catch (IOException e) { + Common.sendConsoleMMMessage("Couldn't restore custom config keys."); + } + } + + private Object fixTimeStrings(Object value) { + if (!(value instanceof List)) return value; + + List list = (List) value; + List fixed = new ArrayList<>(list.size()); + for (Object el : list) { + if (el instanceof String && ((String) el).matches("\\d{1,2}:\\d{2}")) { + fixed.add(((String) el) + " "); + } else { + fixed.add(el); + } + } + return fixed; + } + private void saveResource(@NotNull File document, @NotNull InputStream defaults) { try { YamlDocument.create(document, defaults, diff --git a/core/src/main/java/dev/nandi0813/practice/util/SoftDependUtil.java b/core/src/main/java/dev/nandi0813/practice/util/SoftDependUtil.java index e8dc04f30..47450ca43 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/SoftDependUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/SoftDependUtil.java @@ -2,8 +2,9 @@ import org.bukkit.Bukkit; -public enum SoftDependUtil { - ; +public final class SoftDependUtil { + + private SoftDependUtil() {} public static boolean isPAPI_ENABLED = false; public static boolean isFAWE_ENABLED = false; diff --git a/core/src/main/java/dev/nandi0813/practice/util/StartUpUtil.java b/core/src/main/java/dev/nandi0813/practice/util/StartUpUtil.java index 48d6b56ce..5fdcc54a8 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/StartUpUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/StartUpUtil.java @@ -2,8 +2,9 @@ import dev.nandi0813.practice.ZonePractice; -public enum StartUpUtil { - ; +public final class StartUpUtil { + + private StartUpUtil() {} public static void loadStartUpProgressMap() { for (StartUpTypes startUpType : StartUpTypes.values()) diff --git a/core/src/main/java/dev/nandi0813/practice/util/StatisticUtil.java b/core/src/main/java/dev/nandi0813/practice/util/StatisticUtil.java index 5d20b8f65..638c74243 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/StatisticUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/StatisticUtil.java @@ -1,18 +1,19 @@ package dev.nandi0813.practice.util; -public enum StatisticUtil { - ; +public final class StatisticUtil { + + private StatisticUtil() {} public static String getProgressBar(final double progress) { int numberOfColoredBars = (int) Math.floor(progress / 10.0); int numberOfEmptyBars = 10 - numberOfColoredBars; - String progressBar = "&l"; + String progressBar = ""; for (int i = 0; i < numberOfColoredBars; i++) progressBar = progressBar.concat("┃"); if (numberOfEmptyBars > 0) { - progressBar = progressBar.concat("&7&l"); + progressBar = progressBar.concat(""); for (int i = 0; i < numberOfEmptyBars; i++) progressBar = progressBar.concat("┃"); } diff --git a/core/src/main/java/dev/nandi0813/practice/util/StringUtil.java b/core/src/main/java/dev/nandi0813/practice/util/StringUtil.java index 96c331443..56dda087a 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/StringUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/StringUtil.java @@ -8,9 +8,11 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; -public enum StringUtil { - ; +public final class StringUtil { + + private StringUtil() {} public static String CC(String string) { if (string == null) { @@ -27,6 +29,70 @@ public static List CC(List stringlist) { return list; } + private static final Map LEGACY_TO_MM = Map.ofEntries( + Map.entry('0', "black"), + Map.entry('1', "dark_blue"), + Map.entry('2', "dark_green"), + Map.entry('3', "dark_aqua"), + Map.entry('4', "dark_red"), + Map.entry('5', "dark_purple"), + Map.entry('6', "gold"), + Map.entry('7', "gray"), + Map.entry('8', "dark_gray"), + Map.entry('9', "blue"), + Map.entry('a', "green"), + Map.entry('b', "aqua"), + Map.entry('c', "red"), + Map.entry('d', "light_purple"), + Map.entry('e', "yellow"), + Map.entry('f', "white"), + Map.entry('k', "obfuscated"), + Map.entry('l', "bold"), + Map.entry('m', "strikethrough"), + Map.entry('n', "underlined"), + Map.entry('o', "italic"), + Map.entry('r', "reset") + ); + + public static String legacyToMiniMessage(String text) { + if (text == null || text.isEmpty()) return text; + + StringBuilder out = new StringBuilder(); + + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + + if ((c == '&' || c == '§') && i + 1 < text.length()) { + char code = Character.toLowerCase(text.charAt(++i)); + + // hex + if (code == '#' && i + 6 < text.length()) { + String hex = text.substring(i + 1, i + 7); + + if (hex.matches("[0-9a-fA-F]{6}")) { + out.append("<#").append(hex).append(">"); + i += 6; + continue; + } + } + + // legacy + String tag = LEGACY_TO_MM.get(code); + if (tag != null) { + out.append('<').append(tag).append('>'); + continue; + } + + out.append(c).append(code); + continue; + } + + out.append(c); + } + + return out.toString(); + } + public static String replaceSecondString(String string, double seconds) { if ((seconds == Math.floor(seconds)) && !Double.isInfinite(seconds)) { return string @@ -70,94 +136,4 @@ public static boolean isInteger(String s, int radix) { public static String getNormalizedName(String name) { return StringUtils.capitalize(name.replace("_", " ").toLowerCase()); } - - - /** - * Converts a string that may contain legacy color codes (both & and § prefix) - * as well as hex color codes in the formats &#RRGGBB, &x&R&R&G&G&B&B, - * §x§R§R§G§G§B§B, and #RRGGBB into their MiniMessage equivalents. - * - * This is the correct entry-point for strings returned by PlaceholderAPI, - * since PAPI expansions (e.g. LuckPerms) typically produce legacy-coded strings. - */ - public static String translateColorsToMiniMessage(String string) { - if (string == null || string.isEmpty()) return string; - - // ── 1. §x§R§R§G§G§B§B (Bungeecord/vanilla hex, section-prefixed) ── - // Pattern: §x followed by six § pairs - string = string.replaceAll( - "§x§([0-9A-Fa-f])§([0-9A-Fa-f])§([0-9A-Fa-f])§([0-9A-Fa-f])§([0-9A-Fa-f])§([0-9A-Fa-f])", - "<#$1$2$3$4$5$6>" - ); - - // ── 2. &x&R&R&G&G&B&B (same but ampersand-prefixed) ── - string = string.replaceAll( - "&x&([0-9A-Fa-f])&([0-9A-Fa-f])&([0-9A-Fa-f])&([0-9A-Fa-f])&([0-9A-Fa-f])&([0-9A-Fa-f])", - "<#$1$2$3$4$5$6>" - ); - - // ── 3. &#RRGGBB (common shorthand used by many plugins) ── - string = string.replaceAll("&#([0-9A-Fa-f]{6})", "<#$1>"); - - // ── 4. §#RRGGBB (section variant of the shorthand) ── - string = string.replaceAll("§#([0-9A-Fa-f]{6})", "<#$1>"); - - // ── 5. Standalone #RRGGBB at word boundary (bare hex, used by some expansions) ── - // ':' is excluded from the lookbehind so that MiniMessage gradient/transition tags - // such as are preserved — the '#' tokens there are always - // preceded by ':' and must NOT be re-wrapped in <#…>. - string = string.replaceAll("(?])", "<#$1>"); - - // ── 6. Standard legacy & and § codes ── - return legacyColorToMiniMessage(string); - } - - public static String legacyColorToMiniMessage(String string) { - return string - .replace("&0", "") - .replace("&1", "") - .replace("&2", "") - .replace("&3", "") - .replace("&4", "") - .replace("&5", "") - .replace("&6", "") - .replace("&7", "") - .replace("&8", "") - .replace("&9", "") - .replace("&a", "") - .replace("&b", "") - .replace("&c", "") - .replace("&d", "") - .replace("&e", "") - .replace("&f", "") - .replace("&k", "") - .replace("&l", "") - .replace("&m", "") - .replace("&n", "") - .replace("&o", "") - .replace("&r", "") - .replace("§0", "") - .replace("§1", "") - .replace("§2", "") - .replace("§3", "") - .replace("§4", "") - .replace("§5", "") - .replace("§6", "") - .replace("§7", "") - .replace("§8", "") - .replace("§9", "") - .replace("§a", "") - .replace("§b", "") - .replace("§c", "") - .replace("§d", "") - .replace("§e", "") - .replace("§f", "") - .replace("§k", "") - .replace("§l", "") - .replace("§m", "") - .replace("§n", "") - .replace("§o", "") - .replace("§r", ""); - } - } \ No newline at end of file diff --git a/core/src/main/java/dev/nandi0813/practice/util/TPSUtil.java b/core/src/main/java/dev/nandi0813/practice/util/TPSUtil.java index 7b261cf16..f3952eb83 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/TPSUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/TPSUtil.java @@ -7,8 +7,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; -public enum TPSUtil { - ; +public final class TPSUtil { + + private TPSUtil() {} private static Object minecraftServer; private static Field recentTps; diff --git a/core/src/main/java/dev/nandi0813/practice/util/UpdateChecker.java b/core/src/main/java/dev/nandi0813/practice/util/UpdateChecker.java index a5c333598..391e1edf5 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/UpdateChecker.java +++ b/core/src/main/java/dev/nandi0813/practice/util/UpdateChecker.java @@ -24,8 +24,9 @@ *

The check runs asynchronously so it never blocks the main thread. * Results are cached for the lifetime of the server session. */ -public enum UpdateChecker { - ; +public final class UpdateChecker { + + private UpdateChecker() {} /** Permission required to receive the update notification on join. */ public static final String NOTIFY_PERMISSION = "zpp.update.notify"; diff --git a/core/src/main/java/dev/nandi0813/practice/util/VersionChecker.java b/core/src/main/java/dev/nandi0813/practice/util/VersionChecker.java index c00149632..4258ee344 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/VersionChecker.java +++ b/core/src/main/java/dev/nandi0813/practice/util/VersionChecker.java @@ -11,8 +11,9 @@ * Utility for detecting the running Bukkit/MC version. * Replaces the previous empty-enum pattern with a normal utility class. */ -public enum VersionChecker { - ; +public final class VersionChecker { + + private VersionChecker() {} private static volatile BukkitVersion bukkitVersion; diff --git a/core/src/main/java/dev/nandi0813/practice/util/actionbar/ActionBar.java b/core/src/main/java/dev/nandi0813/practice/util/actionbar/ActionBar.java index e47ae9174..ada3102b6 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/actionbar/ActionBar.java +++ b/core/src/main/java/dev/nandi0813/practice/util/actionbar/ActionBar.java @@ -3,6 +3,7 @@ import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.profile.Profile; import dev.nandi0813.practice.util.Common; +import dev.nandi0813.practice.util.StringUtil; import lombok.Getter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; @@ -306,7 +307,7 @@ private void resetLastSentState() { private Component deserializeOrFallback(String text) { String safeText = text == null ? "" : text; try { - return ZonePractice.getMiniMessage().deserialize(safeText); + return ZonePractice.getMiniMessage().deserialize(StringUtil.legacyToMiniMessage(safeText)); } catch (Exception ignored) { return Component.text(Objects.toString(text, "")); } diff --git a/core/src/main/java/dev/nandi0813/practice/util/cooldown/PlayerCooldown.java b/core/src/main/java/dev/nandi0813/practice/util/cooldown/PlayerCooldown.java index 23bc4723a..fcc16e1ff 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/cooldown/PlayerCooldown.java +++ b/core/src/main/java/dev/nandi0813/practice/util/cooldown/PlayerCooldown.java @@ -8,8 +8,9 @@ import java.util.HashMap; import java.util.Map; -public enum PlayerCooldown { - ; +public final class PlayerCooldown { + + private PlayerCooldown() {} @Getter private static final Map> cooldowns = new HashMap<>(); diff --git a/core/src/main/java/dev/nandi0813/practice/util/entityhider/PlayerHider.java b/core/src/main/java/dev/nandi0813/practice/util/entityhider/PlayerHider.java index 39691d4b3..cbeb2f31d 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/entityhider/PlayerHider.java +++ b/core/src/main/java/dev/nandi0813/practice/util/entityhider/PlayerHider.java @@ -67,7 +67,7 @@ public void playerJoin(PlayerJoinEvent e) { */ if (onlineProfile.isHideFromPlayers() && !player.hasPermission("zpp.staffmode.see")) { hidePlayer(player, online, true); - } else if (profile.isHidePlayers() && ServerManager.getInstance().getInWorld().get(online).equals(WorldEnum.LOBBY)) { + } else if (profile.isHidePlayers() && ServerManager.getInstance().getInWorld().get(online) == WorldEnum.LOBBY) { hidePlayer(player, online, false); } } @@ -84,7 +84,7 @@ public void playerTeleport(PlayerTeleportEvent e) { Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> { - if (!ServerManager.getInstance().getInWorld().get(player).equals(WorldEnum.LOBBY)) return; + if (ServerManager.getInstance().getInWorld().get(player) != WorldEnum.LOBBY) return; for (Player online : Bukkit.getOnlinePlayers()) { if (player == online) continue; @@ -92,7 +92,7 @@ public void playerTeleport(PlayerTeleportEvent e) { Profile onlineProfile = ProfileManager.getInstance().getProfile(online); // Handle the teleported player - if (profile.isHidePlayers() && ServerManager.getInstance().getInWorld().get(online).equals(WorldEnum.LOBBY)) { + if (profile.isHidePlayers() && ServerManager.getInstance().getInWorld().get(online) == WorldEnum.LOBBY) { hidePlayer(player, online, false); } else if (!onlineProfile.isHideFromPlayers() || player.hasPermission("zpp.staffmode.see")) { showPlayer(player, online); @@ -102,7 +102,7 @@ public void playerTeleport(PlayerTeleportEvent e) { // Handle the online player if (!onlineProfile.getStatus().equals(ProfileStatus.MATCH) && !onlineProfile.getStatus().equals(ProfileStatus.EVENT) && !onlineProfile.getStatus().equals(ProfileStatus.FFA)) { - if (onlineProfile.isHidePlayers() && ServerManager.getInstance().getInWorld().get(online).equals(WorldEnum.LOBBY)) { + if (onlineProfile.isHidePlayers() && ServerManager.getInstance().getInWorld().get(online) == WorldEnum.LOBBY) { hidePlayer(online, player, false); } else if (!profile.isHideFromPlayers() || online.hasPermission("zpp.staffmode.see")) { showPlayer(online, player); @@ -228,7 +228,7 @@ public void toggleStaffVisibility(Player player) { hidePlayer(online, player, true); } else { - if (!ServerManager.getInstance().getInWorld().get(online).equals(WorldEnum.LOBBY)) continue; + if (ServerManager.getInstance().getInWorld().get(online) != WorldEnum.LOBBY) continue; Profile onlineProfile = ProfileManager.getInstance().getProfile(online); diff --git a/core/src/main/java/dev/nandi0813/practice/util/playerutil/PlayerUtil.java b/core/src/main/java/dev/nandi0813/practice/util/playerutil/PlayerUtil.java index a696ed981..dba08f36b 100644 --- a/core/src/main/java/dev/nandi0813/practice/util/playerutil/PlayerUtil.java +++ b/core/src/main/java/dev/nandi0813/practice/util/playerutil/PlayerUtil.java @@ -2,6 +2,7 @@ import dev.nandi0813.practice.ZonePractice; import dev.nandi0813.practice.manager.backend.LanguageManager; +import dev.nandi0813.practice.manager.ladder.abstraction.Ladder; import dev.nandi0813.practice.manager.profile.Profile; import dev.nandi0813.practice.manager.profile.ProfileManager; import dev.nandi0813.practice.util.Common; @@ -15,8 +16,11 @@ import java.lang.reflect.Method; import java.util.*; -public enum PlayerUtil { - ; +public final class PlayerUtil { + + private PlayerUtil() {} + + private static final double DEFAULT_FIGHT_MAX_HEALTH = 20.0D; private static void clearStuckArrows(Player player) { try { @@ -29,7 +33,8 @@ private static void clearStuckArrows(Player player) { public static void clearPlayer(Player player, boolean deleteInv, boolean fly, boolean entityCollide) { player.setFallDistance(0); - player.setHealth(20); + resetMaxHealth(player); + healToMaxHealth(player); player.setExp(0); player.setLevel(0); player.setFoodLevel(23); @@ -52,20 +57,20 @@ public static void clearPlayer(Player player, boolean deleteInv, boolean fly, bo } public static void setFightPlayer(Player player) { + setFightPlayer(player, null); + } + + public static void setFightPlayer(Player player, Ladder ladder) { Bukkit.getScheduler().runTask(ZonePractice.getInstance(), () -> { - player.setHealth(20); - Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> player.setHealth(20), 2L); + applyFightMaxHealth(player, ladder); + healToMaxHealth(player); + Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> { + applyFightMaxHealth(player, ladder); + healToMaxHealth(player); + }, 2L); Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () -> player.setFireTicks(0), 2L); player.setFoodLevel(25); - AttributeInstance maxHealth = player.getAttribute(Attribute.MAX_HEALTH); - if (maxHealth != null) { - maxHealth.setBaseValue(maxHealth.getDefaultValue()); - - if (player.getHealth() > maxHealth.getValue()) { - player.setHealth(maxHealth.getValue()); - } - } player.setFallDistance(0); player.setWalkSpeed(0.2F); for (PotionEffect potionEffect : player.getActivePotionEffects()) @@ -73,12 +78,34 @@ public static void setFightPlayer(Player player) { player.setGameMode(GameMode.SURVIVAL); player.setFlying(false); player.setAllowFlight(false); - // Players can be marked non-collidable while temporarily spectating; restore combat hitboxes. dev.nandi0813.practice.manager.fight.util.PlayerUtil.setCollidesWithEntities(player, true); - // Clear stale invulnerability frames so shield-stun / rapid follow-up hits work consistently. }); } + public static void healToMaxHealth(Player player) { + AttributeInstance maxHealth = player.getAttribute(Attribute.MAX_HEALTH); + double maxHealthValue = maxHealth != null ? maxHealth.getValue() : DEFAULT_FIGHT_MAX_HEALTH; + player.setHealth(Math.max(1.0D, maxHealthValue)); + } + + public static void resetMaxHealth(Player player) { + AttributeInstance maxHealth = player.getAttribute(Attribute.MAX_HEALTH); + if (maxHealth == null) return; + maxHealth.setBaseValue(maxHealth.getDefaultValue()); + } + + private static void applyFightMaxHealth(Player player, Ladder ladder) { + AttributeInstance maxHealth = player.getAttribute(Attribute.MAX_HEALTH); + if (maxHealth == null) return; + + double targetMaxHealth = DEFAULT_FIGHT_MAX_HEALTH; + if (ladder != null) { + targetMaxHealth = Math.clamp(ladder.getHearts() * 2.0D, 2.0D, 40.0D); + } + + maxHealth.setBaseValue(targetMaxHealth); + } + public static void setPlayerWorldTime(Player player) { Profile profile = ProfileManager.getInstance().getProfile(player); player.setPlayerTime(profile.getWorldTime().getTime(), false); diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 74c968ab8..70e51edfe 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -1,4 +1,4 @@ -VERSION: 57 +VERSION: 60 # Mysql database setup. MYSQL-DATABASE: @@ -11,11 +11,6 @@ MYSQL-DATABASE: USER: root PASSWORD: mysecretpassword -TELEMETRY: - ENABLED: true - AI: - ENABLED: true - # Knockback modifier - it very much depends on the hit delay. You should test what is the optimal for you. KNOCKBACK: NORMAL: @@ -23,11 +18,25 @@ KNOCKBACK: AIR-VERTICAL: 0.93 HORIZONTAL: 0.82 VERTICAL: 0.88 + MAX-AIR-HORIZONTAL: -1.0 # Set <= 0 to disable cap. + MAX-AIR-VERTICAL: -1.0 # Set <= 0 to disable cap. + MAX-HORIZONTAL: -1.0 # Set <= 0 to disable cap. + MAX-VERTICAL: -1.0 # Set <= 0 to disable cap. COMBO: AIR-HORIZONTAL: 2.8 AIR-VERTICAL: 2.8 HORIZONTAL: 2.5 VERTICAL: 2.5 + MAX-AIR-HORIZONTAL: 1.35 # Hard cap to avoid launch spikes. + MAX-AIR-VERTICAL: 0.62 # Hard cap to avoid launching players too high. + MAX-HORIZONTAL: 1.15 # Ground horizontal cap. + MAX-VERTICAL: 0.52 # Ground vertical cap. +# +# Setup limits +SETUP: + MAX-LADDERS: 0 # Set to 0 or -1 for unlimited ladders. + ALLOW-ICON-EDIT-WHILE-ENABLED: false # If true, admins can use /arena set icon and /ladder set icon even while enabled. + PRESERVE-CUSTOM-KITS-ON-LADDER-DISABLE: false # If true, disabling a ladder keeps player custom kits for that ladder. # # Queue settings QUEUE: @@ -212,13 +221,13 @@ MATCH-SETTINGS: COLOR: "" MATCH-TYPE-NAMES: - DUEL: "&e&lDuel" - PARTY_FFA: "&e&lParty FFA" - PARTY_SPLIT: "&e&lParty Split" - PARTY_VS_PARTY: "&e&lParty Vs Party" + DUEL: "Duel" + PARTY_FFA: "Party FFA" + PARTY_SPLIT: "Party Split" + PARTY_VS_PARTY: "Party Vs Party" WEIGHT-CLASS: - UNRANKED: "&aUnranked" - RANKED: "&cRanked" + UNRANKED: "Unranked" + RANKED: "Ranked" LEAVE-COMMAND: ENABLED: true WEIGHT-CLASS: @@ -253,6 +262,7 @@ MATCH-SETTINGS: LOW-HEALTH-DECIMAL-RATIO: true # If true, health below 2 hearts is shown as a decimal ratio (current/max). LOW-HEALTH-THRESHOLD: 4.0 SCALE: 20 # The scale setting defines the health display range between 10 and 100 with a default value of 20. + SYMBOL: "♥" # The symbol displayed after the health value in the below-name display. BUILD-LIMIT-DEFAULT: 4 # Counts from the first players positions Y level. You can set a unique number for this for every arena, then it will consider where you are standing. AFTER-COUNTDOWN: 3 # After the match is over this countdown start, and when it's over, the players teleport back to the lobby. ROLLBACK: @@ -262,13 +272,13 @@ MATCH-SETTINGS: COOLDOWN: 10 # Cooldown in seconds between Golden Head uses. ACTION-BAR-COOLDOWN-MSG: "🕒 %remaining%s" ITEM: - NAME: "&e&lGolden Head" + NAME: "Golden Head" MATERIAL: GOLDEN_APPLE DAMAGE: 1 LORE: - "" - - "&7This apple gives you extra" - - "&7health and effects." + - "This apple gives you extra" + - "health and effects." - "" # # You can add any potion effects for the golden head. @@ -347,10 +357,10 @@ MATCH-SETTINGS: EXPIRE-TIME: 20 # sec KIT-ITEMS: DEFAULT-KIT: - NAME: "&e&lDefault Kit" + NAME: "Default Kit" MATERIAL: ENCHANTED_BOOK CUSTOM-KIT: - NAME: "&a&lKit %kit%" + NAME: "Kit %kit%" MATERIAL: ENCHANTED_BOOK LADDER-SETTINGS: BRIDGE: @@ -466,99 +476,99 @@ LEADERBOARD: DYNAMIC-UPDATE: 10 # Sec. This type of hologram is switching between ladders. STATIC-UPDATE: 30 # Sec. This type of hologram is always show one ladder or global elo stats. FORMAT: # Also placeholders: %division%, %division_short%, %group%, %ladder_name% - NULL-LINE: "&6%number%. &cN/A" - NOTHING-TO-DISPLAY: "&cThere is nothing to display." + NULL-LINE: "%number%. N/A" + NOTHING-TO-DISPLAY: "There is nothing to display." ELO: TITLE-LINE-SPACING: 0.5 LINE-SPACING: 0.3 - FORMAT: "&6%placement%. %division% | %player%&8: &e%score%" + FORMAT: "%placement%. %division% | %player%: %score%" LINES: GLOBAL: - - "&6ELO Top" + - "ELO Top" - "%top%" LADDER: - - "&6ELO Top &7- &e%ladder_displayName%" + - "ELO Top - %ladder_displayName%" - "%top%" WIN: TITLE-LINE-SPACING: 0.5 LINE-SPACING: 0.3 - FORMAT: "&6%placement%. %division% | %player%&8: &e%score%" + FORMAT: "%placement%. %division% | %player%: %score%" LINES: GLOBAL: - - "&6Win Top" + - "Win Top" - "%top%" LADDER: - - "&6Win Top &7- &e%ladder_displayName%" + - "Win Top - %ladder_displayName%" - "%top%" KILLS: TITLE-LINE-SPACING: 0.5 LINE-SPACING: 0.3 - FORMAT: "&6%placement%. %division% | %player%&8: &e%score%" + FORMAT: "%placement%. %division% | %player%: %score%" LINES: GLOBAL: - - "&6Kill Top" + - "Kill Top" - "%top%" LADDER: - - "&6Kill Top &7- &e%ladder_displayName%" + - "Kill Top - %ladder_displayName%" - "%top%" DEATHS: TITLE-LINE-SPACING: 0.5 LINE-SPACING: 0.3 - FORMAT: "&6%placement%. %division% | %player%&8: &e%score%" + FORMAT: "%placement%. %division% | %player%: %score%" LINES: GLOBAL: - - "&6Deaths Top" + - "Deaths Top" - "%top%" LADDER: - - "&6Deaths Top &7- &e%ladder_displayName%" + - "Deaths Top - %ladder_displayName%" - "%top%" WIN_STREAK: TITLE-LINE-SPACING: 0.5 LINE-SPACING: 0.3 - FORMAT: "&6%placement%. %division% | %player%&8: &e%score%" + FORMAT: "%placement%. %division% | %player%: %score%" LINES: GLOBAL: - - "&6Win Streak Top" + - "Win Streak Top" - "%top%" LADDER: - - "&6Win Streak Top &7- &e%ladder_displayName%" + - "Win Streak Top - %ladder_displayName%" - "%top%" BEST_WIN_STREAK: TITLE-LINE-SPACING: 0.5 LINE-SPACING: 0.3 - FORMAT: "&6%placement%. %division% | %player%&8: &e%score%" + FORMAT: "%placement%. %division% | %player%: %score%" LINES: GLOBAL: - - "&6Best Win Streak Top" + - "Best Win Streak Top" - "%top%" LADDER: - - "&6Best Win Streak Top &7- &e%ladder_displayName%" + - "Best Win Streak Top - %ladder_displayName%" - "%top%" LOSE_STREAK: TITLE-LINE-SPACING: 0.5 LINE-SPACING: 0.3 - FORMAT: "&6%placement%. %division% | %player%&8: &e%score%" + FORMAT: "%placement%. %division% | %player%: %score%" LINES: GLOBAL: - - "&6Lose Streak Top" + - "Lose Streak Top" - "%top%" LADDER: - - "&6Lose Streak Top &7- &e%ladder_displayName%" + - "Lose Streak Top - %ladder_displayName%" - "%top%" BEST_LOSE_STREAK: TITLE-LINE-SPACING: 0.5 LINE-SPACING: 0.3 - FORMAT: "&6%placement%. %division% | %player%&8: &e%score%" + FORMAT: "%placement%. %division% | %player%: %score%" LINES: GLOBAL: - - "&6Best Lose Streak Top" + - "Best Lose Streak Top" - "%top%" LADDER: - - "&6Best Lose Streak Top &7- &e%ladder_displayName%" + - "Best Lose Streak Top - %ladder_displayName%" - "%top%" SETUP-HOLO: - TITLE: "&cThis hologram must be set." - LINE: "&6Hologram Name: &e%name%" + TITLE: "This hologram must be set." + LINE: "Hologram Name: %name%" # # Sidebar settings SIDEBAR: @@ -576,7 +586,7 @@ ARENA: DEFAULT-ICON: # If default icon is enabled it won't be necessary to set an arena icon, but you still can. ENABLED: false ICON: - NAME: "&6%arena%" + NAME: "%arena%" MATERIAL: FIREWORK_STAR # DAMAGE: 4 # You can set the damage to the material as well. # @@ -595,7 +605,7 @@ EVENT: IN-RANKED-MATCH: false # If true and the player is in a ranked match, he will receive the broadcast message. IN-EVENT: true # If true and the player is in another event, he will receive the broadcast message. PLAYER-TRACKER: # Shows the nearest player. - NAME: "&cPlayer Tracker &7(Right-Click)" + NAME: "Player Tracker (Right-Click)" MATERIAL: COMPASS LMS: # Please be aware that building is not yet supported for the event. NAME: "LMS" @@ -617,7 +627,7 @@ EVENT: WINNER-COMMAND: - "practice ranked add %player% 3" TAGGED-ITEM: - NAME: "&cYou're IT, tag someone!" + NAME: "You're IT, tag someone!" MATERIAL: TNT BRACKETS: # Please be aware that building is not yet supported for the event. NAME: "Brackets" @@ -634,7 +644,7 @@ EVENT: BREAKABLE-MATERIALS: # Generic entries like WOOL or TERRACOTTA also match colored variants. - "WOOL" EGG-LAUNCHER-ITEM: - NAME: "&aShoot The Blocks &7(Right-Click)" + NAME: "Shoot The Blocks (Right-Click)" MATERIAL: IRON_SHOVEL JUGGERNAUT: # Please be aware that building is not yet supported for the event. NAME: "Juggernaut" @@ -656,6 +666,7 @@ PLAYER: allow-hunger: false allow-block-break: false allow-block-place: false + allow-lobby-interact: false LOBBY-NAMETAG: ENABLED: true NAMETAG-MANAGEMENT: diff --git a/core/src/main/resources/guis.yml b/core/src/main/resources/guis.yml index 2087f253b..a35f26429 100644 --- a/core/src/main/resources/guis.yml +++ b/core/src/main/resources/guis.yml @@ -1,133 +1,133 @@ -VERSION: 36 +VERSION: 37 GENERAL-FILLER-ITEM: NAME: " " MATERIAL: BLACK_STAINED_GLASS_PANE GUIS: ARENA-CREATE: - TITLE: "&6What type for &c%arena%&6?" + TITLE: "What type for %arena%?" LADDER-CREATE: - TITLE: "&6What type for &c%ladder%&6?" + TITLE: "What type for %ladder%?" VALIDATION-GUI: - TITLE: "&8Validation" + TITLE: "Validation" ICONS: CANCEL: - NAME: "&cCancel" + NAME: "Cancel" MATERIAL: RED_STAINED_GLASS_PANE APPROVE: - NAME: "&aApprove" + NAME: "Approve" MATERIAL: LIME_STAINED_GLASS_PANE KIT-EDITOR: # %ladder% display the Display Name of the ladder (official icon name), but you can also use %ladderOriginal% which is the given name of the ladder. EDITOR-MENU: - TITLE: "&6&lSelect what to edit" + TITLE: "Select what to edit" ICONS: FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE PREMADE-LADDER: - NAME: "&6&lPremade Ladder" + NAME: "Premade Ladder" MATERIAL: GOLDEN_SWORD LORE: - - "&8&m------------------------" - - "&7Click here to edit a &6premade" - - "&7ladder." - - "&8&m------------------------" + - "------------------------" + - "Click here to edit a premade" + - "ladder." + - "------------------------" PLAYER-LADDER: - NAME: "&a&lOwn Ladder" + NAME: "Own Ladder" MATERIAL: FIRE_CHARGE LORE: - - "&8&m------------------------" - - "&7Click here to edit your &aown" - - "&7ladder." - - "&8&m------------------------" + - "------------------------" + - "Click here to edit your own" + - "ladder." + - "------------------------" PLAYER-CUSTOM-KIT-SELECTOR: - TITLE: "&8Select a kit to edit" + TITLE: "Select a kit to edit" ICONS: KIT: - NAME: "&7[&f%kit%&7]" + NAME: "[%kit%]" MATERIAL: WRITABLE_BOOK UNSELECTED: - NAME: "&7[&fUnselected&7]" + NAME: "[Unselected]" MATERIAL: CYAN_TERRACOTTA SELECTED: - NAME: "&7[&aSelected&7]" + NAME: "[Selected]" MATERIAL: LIME_TERRACOTTA GUIDE: - NAME: "&bGuide" + NAME: "Guide" MATERIAL: PAPER LORE: - - "&fAfter selecting a kit, you can" - - "&fplay with it by dueling other" - - "&fplayers or play in parties." + - "After selecting a kit, you can" + - "play with it by dueling other" + - "players or play in parties." LADDER-SELECTOR: - TITLE: "&9&lSelect a kit to edit." + TITLE: "Select a kit to edit." ICONS: NAME: "%ladder%" LORE: - "" - - "&aClick here to select &e%ladder%&a." + - "Click here to select %ladder%." DUEL-ROUND-SELECTOR: - TITLE: "&8Select the amount of rounds" + TITLE: "Select the amount of rounds" ICONS: BACK-TO: - NAME: "&cBack to" + NAME: "Back to" MATERIAL: ARROW ROUND-SELECTOR: - NAME: "&7Rounds: &6%rounds%" + NAME: "Rounds: %rounds%" MATERIAL: FIREWORK_STAR LORE: - "" - - "&7The first player/team to reach" - - "&7the, winning rounds wins." + - "The first player/team to reach" + - "the, winning rounds wins." - "" - - "&7Recommended: &e%recommended_rounds% rounds&7." + - "Recommended: %recommended_rounds% rounds." - "" - - "&a&lLEFT-CLICK &ato reduce the rounds." - - "&b&lRIGHT-CLICK &bto increase the rounds." + - "LEFT-CLICK to reduce the rounds." + - "RIGHT-CLICK to increase the rounds." SHOW-ARENA: - NAME: "&eSelected Arena: %arena%" + NAME: "Selected Arena: %arena%" MATERIAL: DIRT # In case the arena doesn't have an icon LORE: - "" - - "&7You've selected this arena for the match." + - "You've selected this arena for the match." SHOW-LADDER: - NAME: "&eSelected Ladder: %ladder%" + NAME: "Selected Ladder: %ladder%" MATERIAL: DIRT # In case the ladder doesn't have an icon LORE: - "" - - "&7You've selected this ladder for the match." + - "You've selected this ladder for the match." START-MATCH: - NAME: "&aStart Match" + NAME: "Start Match" MATERIAL: EMERALD LORE: - "" - - "&7Click here to start the match." - - "&7The match will start with the selected" - - "&7arena and ladder." + - "Click here to start the match." + - "The match will start with the selected" + - "arena and ladder." KIT-SELECTOR: - TITLE: "&8Viewing %ladder% kits" + TITLE: "Viewing %ladder% kits" ICONS: BACK-TO-KIT-SELECTOR: - NAME: "&cBack to kit selector" + NAME: "Back to kit selector" MATERIAL: ARROW CREATE-KIT: - NAME: "&a&lCreate Kit" + NAME: "Create Kit" MATERIAL: STONE_SWORD EXISTING-KIT: - NAME: "&6&lKit %kit%" + NAME: "Kit %kit%" MATERIAL: GOLDEN_SWORD EDIT-KIT: - NAME: "&a&lEdit Kit" + NAME: "Edit Kit" MATERIAL: BOOK DELETE-KIT: - NAME: "&c&lDelete Kit" + NAME: "Delete Kit" MATERIAL: REDSTONE LORE: - - "&8&m------------------------" - - "&c&lYou won't be able to" - - "&crecover this kit." - - "&8&m------------------------" + - "------------------------" + - "You won't be able to" + - "recover this kit." + - "------------------------" NO-PERMISSION: - NAME: "&cYou don't have permission" + NAME: "You don't have permission" MATERIAL: WOODEN_SWORD FILLER-ITEM-1: NAME: " " @@ -136,1197 +136,1197 @@ GUIS: NAME: " " MATERIAL: BLACK_STAINED_GLASS_PANE KIT-EDITOR: - TITLE: "&8Editing Kit %kit%" # Also available: %weightClass% + TITLE: "Editing Kit %kit%" # Also available: %weightClass% ICONS: INFO: - NAME: "&2Informations" + NAME: "Informations" MATERIAL: NAME_TAG LORE: - - "&8&m------------------------" - - " &e» &7Ladder: &e%ladder%" - - " &e» &7Kit: &e%kit%" - - " &e» &7WeightClass: &e%weightClass%" - - "&8&m------------------------" + - "------------------------" + - " » Ladder: %ladder%" + - " » Kit: %kit%" + - " » WeightClass: %weightClass%" + - "------------------------" SAVE: - NAME: "&a&lSave" + NAME: "Save" MATERIAL: LIME_WOOL LORE: - - "&8&m------------------------" - - "&e&lClick here &eto save" - - "ðe custom kit." - - "&8&m------------------------" + - "------------------------" + - "Click here to save" + - "the custom kit." + - "------------------------" LOAD-DEFAULT: - NAME: "&e&lLoad Default Kit" + NAME: "Load Default Kit" MATERIAL: YELLOW_WOOL LORE: - - "&8&m------------------------" - - "&e&lClick here &eto load the default" - - "&ekit to your inventory." - - "&8&m------------------------" + - "------------------------" + - "Click here to load the default" + - "kit to your inventory." + - "------------------------" CANCEL: - NAME: "&c&lCancel" + NAME: "Cancel" MATERIAL: RED_WOOL LORE: - - "&8&m------------------------" - - "&e&lClick here &eto abort editing the" - - "&ekit, and return to the kit menu." - - "&8&m------------------------" + - "------------------------" + - "Click here to abort editing the" + - "kit, and return to the kit menu." + - "------------------------" FILLER-ITEM: NAME: " " MATERIAL: ORANGE_STAINED_GLASS_PANE SWITCH-TO-UNRANKED: - NAME: "&aSwitch to %weightClass%" + NAME: "Switch to %weightClass%" MATERIAL: WOODEN_SWORD SWITCH-TO-RANKED: - NAME: "&aSwitch to %weightClass%" + NAME: "Switch to %weightClass%" MATERIAL: IRON_SWORD ONLY-UNRANKED: - NAME: "&cThis ladder is only %weightClass%" + NAME: "This ladder is only %weightClass%" MATERIAL: REDSTONE ONLY-RANKED: - NAME: "&cThis ladder is only %weightClass%" + NAME: "This ladder is only %weightClass%" MATERIAL: REDSTONE NO-EFFECT: - NAME: "&5Effects" + NAME: "Effects" MATERIAL: POTION DAMAGE: 8233 LORE: - - "&8&m------------------------" - - "&7This ladder has no effects." - - "&8&m------------------------" + - "------------------------" + - "This ladder has no effects." + - "------------------------" HAS-EFFECT: - FORMAT: "&d%name% %amplifier% &7for %time%" + FORMAT: "%name% %amplifier% for %time%" ICON: - NAME: "&5Effects" + NAME: "Effects" MATERIAL: POTION DAMAGE: 8233 LORE: - - "&8&m------------------------" - - "&eYou will get these effects," - - "&ewhen the game starts." + - "------------------------" + - "You will get these effects," + - "when the game starts." - "" - "%effects%" - - "&8&m------------------------" + - "------------------------" STATISTICS: SELECTOR: - TITLE: "&cSelect statistics to view" + TITLE: "Select statistics to view" ICONS: FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE OWN-PLAYER-STATS: - NAME: "&c%player% &7- &fStatistic" + NAME: "%player% - Statistic" LORE: - - "&8&m------------------------" - - "&7Click here to view your personal" - - "&7statistics for each kit." - - "&8&m------------------------" + - "------------------------" + - "Click here to view your personal" + - "statistics for each kit." + - "------------------------" PLAYER-STATS: - NAME: "&c%target% &7- &fStatistic" + NAME: "%target% - Statistic" LORE: - - "&8&m------------------------" - - "&7Click here to view" - - "&c%target%'s &7kit statistics." - - "&8&m------------------------" + - "------------------------" + - "Click here to view" + - "%target%'s kit statistics." + - "------------------------" ELO-LEADERBOARD: - NAME: "&eELO Leaderboards" + NAME: "ELO Leaderboards" MATERIAL: SNOWBALL LORE: - - "&8&m------------------------" - - "&7Click here to view the" - - "&eelo &7leaderboards." - - "&8&m------------------------" + - "------------------------" + - "Click here to view the" + - "elo leaderboards." + - "------------------------" TOP-WIN-LEADERBOARD: - NAME: "&6Top Win Leaderboard" + NAME: "Top Win Leaderboard" MATERIAL: SLIME_BALL LORE: - - "&8&m------------------------" - - "&7Click here to view the" - - "&6top win &7leaderboards." - - "&8&m------------------------" + - "------------------------" + - "Click here to view the" + - "top win leaderboards." + - "------------------------" VIEW-DIVISIONS: HAS-NEXT: - NAME: "&cDivisions" + NAME: "Divisions" MATERIAL: BOOK LORE: - "" - - " &c┃ &fCurrent Division: %division_fullName%" - - " &c┃ &fExperience: &c%exp%" - - " &c┃ &fWins: &c%wins%" - - " &c┃ &fElo: &c%elo%" + - " Current Division: %division_fullName%" + - " Experience: %exp%" + - " Wins: %wins%" + - " Elo: %elo%" - "" - - " &c┃ &fNext Division: %nextDivision_fullName%" - - " &c┃ &fProgress: &a%progress_bar% &f(%progress_percent%%)" + - " Next Division: %nextDivision_fullName%" + - " Progress: %progress_bar% (%progress_percent%%)" - "" - - "&aLeft Click &7to view all division." + - "Left Click to view all division." NO-NEXT: - NAME: "&cDivisions" + NAME: "Divisions" MATERIAL: BOOK LORE: - "" - - " &c┃ &fYour Division: %division_fullName%" - - " &c┃ &fExperience: &c%exp%" - - " &c┃ &fWins: &c%wins%" - - " &c┃ &fElo: &c%elo%" + - " Your Division: %division_fullName%" + - " Experience: %exp%" + - " Wins: %wins%" + - " Elo: %elo%" - "" - - "&eYou have reached the last division." + - "You have reached the last division." ELO-LEADERBOARD: - TITLE: "&eTop ELO Leaderboard" + TITLE: "Top ELO Leaderboard" ICONS: FILLER-ITEM: NAME: " " MATERIAL: YELLOW_STAINED_GLASS_PANE BACK-TO-HUB: - NAME: "&eBack to hub" + NAME: "Back to hub" MATERIAL: ARROW REFRESH-ITEM: - NAME: "&cRefresh" + NAME: "Refresh" MATERIAL: CLAY_BALL LORE: - - "&8&m------------------------" - - "&7Click here to refresh" - - "&7the leaderboard" + - "------------------------" + - "Click here to refresh" + - "the leaderboard" - "" - - "&c&lNOTE: &7The leaderboards automatically" - - "&7refresh every time you open the GUI." - - "&8&m------------------------" + - "NOTE: The leaderboards automatically" + - "refresh every time you open the GUI." + - "------------------------" GLOBAL-LEADERBOARD: - NAME: "&eGlobal Elo Leaderboard &7- &fTop %number%" + NAME: "Global Elo Leaderboard - Top %number%" MATERIAL: "NETHER_STAR" LORE: - FORMAT: "&6%number%. %division% | %player%&8: &e%global_elo%" - FORMAT-NULL: "&6%number%. &7| &cN/A" + FORMAT: "%number%. %division% | %player%: %global_elo%" + FORMAT-NULL: "%number%. | N/A" LEADERBOARD: - - "&8&m------------------------" + - "------------------------" - "%top%" - - "&8&m------------------------" + - "------------------------" NO-LEADERBOARD: - - "&8&m------------------------" - - "&cThere is no leaderboard to display" - - "&8&m------------------------" + - "------------------------" + - "There is no leaderboard to display" + - "------------------------" LADDER-LEADERBOARD: - NAME: "%ladder% &eELO &7- &fTop %number%" + NAME: "%ladder% ELO - Top %number%" LORE: - FORMAT: "&6%number%. %division% | %player%&8: &e%ladder_elo%" - FORMAT-NULL: "&6%number%. &7| &cN/A" + FORMAT: "%number%. %division% | %player%: %ladder_elo%" + FORMAT-NULL: "%number%. | N/A" LEADERBOARD: - - "&8&m------------------------" + - "------------------------" - "%top%" - - "&8&m------------------------" + - "------------------------" NO-LEADERBOARD: - - "&8&m------------------------" - - "&cThere is no leaderboard to display" - - "&8&m------------------------" + - "------------------------" + - "There is no leaderboard to display" + - "------------------------" WIN-LEADERBOARD: - TITLE: "&6Top Wins Leaderboards" + TITLE: "Top Wins Leaderboards" ICONS: FILLER-ITEM: NAME: " " MATERIAL: ORANGE_STAINED_GLASS_PANE BACK-TO-HUB: - NAME: "&eBack to hub" + NAME: "Back to hub" MATERIAL: ARROW GLOBAL-LEADERBOARD: - NAME: "&eGlobal Win Leaderboard &7- &fTop %number%" + NAME: "Global Win Leaderboard - Top %number%" MATERIAL: "NETHER_STAR" LORE: - FORMAT: "&6%number%. %division% | %player%&8: &e%global_win%" - FORMAT-NULL: "&6%number%. &7| &cN/A" + FORMAT: "%number%. %division% | %player%: %global_win%" + FORMAT-NULL: "%number%. | N/A" LEADERBOARD: - - "&8&m------------------------" + - "------------------------" - "%top%" - - "&8&m------------------------" + - "------------------------" NO-LEADERBOARD: - - "&8&m------------------------" - - "&cThere is no leaderboard to display" - - "&8&m------------------------" + - "------------------------" + - "There is no leaderboard to display" + - "------------------------" LADDER-LEADERBOARD: - NAME: "%ladder% &6Win &7- &fTop %number%" + NAME: "%ladder% Win - Top %number%" LORE: - FORMAT: "&6%number%. &7| &e%player%&8: &f%ladder_win%" - FORMAT-NULL: "&6%number%. &7| &cN/A" + FORMAT: "%number%. | %player%: %ladder_win%" + FORMAT-NULL: "%number%. | N/A" LEADERBOARD: - - "&8&m------------------------" + - "------------------------" - "%top%" - - "&8&m------------------------" + - "------------------------" NO-LEADERBOARD: - - "&8&m------------------------" - - "&cThere is no leaderboard to display" - - "&8&m------------------------" + - "------------------------" + - "There is no leaderboard to display" + - "------------------------" PLAYER-STATISTICS: - TITLE: "&c%player%'s &8Stats" + TITLE: "%player%'s Stats" ICONS: FILLER-ITEM: NAME: " " MATERIAL: ORANGE_STAINED_GLASS_PANE BACK-TO-HUB: - NAME: "&eBack to hub" + NAME: "Back to hub" MATERIAL: ARROW ALL-STAT: - NAME: "&c%player% &7- &fStatistics" + NAME: "%player% - Statistics" LORE: - - "&8&m------------------------" - - "&eUnranked Wins: &f%unranked_wins%" - - "&eUnranked Losses: &f%unranked_losses%" - - "&eUnranked W/L Ratio: &f%unranked_w/l_ratio%" + - "------------------------" + - "Unranked Wins: %unranked_wins%" + - "Unranked Losses: %unranked_losses%" + - "Unranked W/L Ratio: %unranked_w/l_ratio%" - "" - - "&eRanked Wins: &f%ranked_wins%" - - "&eRanked Losses: &f%ranked_losses%" - - "&eRanked W/L Ratio: &f%ranked_w/l_ratio%" + - "Ranked Wins: %ranked_wins%" + - "Ranked Losses: %ranked_losses%" + - "Ranked W/L Ratio: %ranked_w/l_ratio%" - "" - - "&eWins: &f%global_wins%" - - "&eLosses: &f%global_losses%" - - "&eW/L Ratio: &f%w/l_ratio%" + - "Wins: %global_wins%" + - "Losses: %global_losses%" + - "W/L Ratio: %w/l_ratio%" - "" - - "&eGlobal ELO: &f%global_elo%" - - "&eDivision: %division%" - - "&8&m------------------------" + - "Global ELO: %global_elo%" + - "Division: %division%" + - "------------------------" UNRANKED-LADDER-STATS: NAME: "%ladder%" LORE: - - "&8&m------------------------" - - "&eUnranked Wins: &f%unranked_wins%" - - "&eUnranked Losses: &f%unranked_losses%" - - "&eUnranked W/L Ratio: &f%unranked_w/l_ratio%" - - "&8&m------------------------" + - "------------------------" + - "Unranked Wins: %unranked_wins%" + - "Unranked Losses: %unranked_losses%" + - "Unranked W/L Ratio: %unranked_w/l_ratio%" + - "------------------------" RANKED-LADDER-STATS: NAME: "%ladder%" LORE: - - "&8&m------------------------" - - "&eRanked Wins: &f%ranked_wins%" - - "&eRanked Losses: &f%ranked_losses%" - - "&eRanked W/L Ratio: &f%ranked_w/l_ratio%" + - "------------------------" + - "Ranked Wins: %ranked_wins%" + - "Ranked Losses: %ranked_losses%" + - "Ranked W/L Ratio: %ranked_w/l_ratio%" - "" - - "&eELO: &f%elo%" - - "&8&m------------------------" + - "ELO: %elo%" + - "------------------------" UNRANKED-RANKED-STATS: NAME: "%ladder%" LORE: - - "&8&m------------------------" - - "&eUnranked Wins: &f%unranked_wins%" - - "&eUnranked Losses: &f%unranked_losses%" - - "&eUnranked W/L Ratio: &f%unranked_w/l_ratio%" + - "------------------------" + - "Unranked Wins: %unranked_wins%" + - "Unranked Losses: %unranked_losses%" + - "Unranked W/L Ratio: %unranked_w/l_ratio%" - "" - - "&eRanked Wins: &f%ranked_wins%" - - "&eRanked Losses: &f%ranked_losses%" - - "&eRanked W/L Ratio: &f%ranked_w/l_ratio%" + - "Ranked Wins: %ranked_wins%" + - "Ranked Losses: %ranked_losses%" + - "Ranked W/L Ratio: %ranked_w/l_ratio%" - "" - - "&eELO: &f%elo%" + - "ELO: %elo%" - "" - - "&eOverall W/L Ratio: &f%overall_w/l_ratio%" - - "&eDivision: %division%" - - "&8&m------------------------" + - "Overall W/L Ratio: %overall_w/l_ratio%" + - "Division: %division%" + - "------------------------" PARTY: PARTY-GAMES: - TITLE: "&8Party Games" + TITLE: "Party Games" ICONS: FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE PARTY_SPLIT: - NAME: "&bSplit Fight" + NAME: "Split Fight" MATERIAL: FIREWORK_STAR PARTY_FFA: - NAME: "&aParty FFA" + NAME: "Party FFA" MATERIAL: SLIME_BALL PARTY-SETTINGS: - TITLE: "&8Party Settings" + TITLE: "Party Settings" ICONS: FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE PLAYER-LIMIT: - NAME: "&ePlayer Limit: &c%limit%" + NAME: "Player Limit: %limit%" MATERIAL: PLAYER_HEAD LORE: - - "&8&m------------------------" - - "&7That many player can join" - - "&7your party maximum." + - "------------------------" + - "That many player can join" + - "your party maximum." - "" - - "&a&lLEFT-CLICK &ato decrease the limit." - - "&b&lRIGHT-CLICK &bto increase the limit." - - "&8&m------------------------" + - "LEFT-CLICK to decrease the limit." + - "RIGHT-CLICK to increase the limit." + - "------------------------" ACCESS-MODIFIERS: PUBLIC: - NAME: "&ePublic: &aTrue" + NAME: "Public: True" MATERIAL: CHEST LORE: - - "&8&m------------------------" - - "&7The party is &apublic" - - "&7anyone can join." + - "------------------------" + - "The party is public" + - "anyone can join." - "" - - "&e&lClick here &7to change the status." - - "&8&m------------------------" + - "Click here to change the status." + - "------------------------" PRIVATE: - NAME: "&ePublic: &cFalse" + NAME: "Public: False" MATERIAL: CHEST LORE: - - "&8&m------------------------" - - "&7The party is &cprivate &7only" - - "&7players with invite can join." + - "------------------------" + - "The party is private only" + - "players with invite can join." - "" - - "&e&lClick here &7to change the status." - - "&8&m------------------------" + - "Click here to change the status." + - "------------------------" BROADCAST: ENABLED: - NAME: "&eBroadcast Party: &aOn" + NAME: "Broadcast Party: On" MATERIAL: PAPER LORE: - - "&8&m------------------------" - - "&7The party is broadcasting" - - "&7to the players of the server." + - "------------------------" + - "The party is broadcasting" + - "to the players of the server." - "" - - "&e&lClick here &7to &cturn off &7broadcasting." - - "&8&m------------------------" + - "Click here to turn off broadcasting." + - "------------------------" DISABLED: - NAME: "&eBroadcast Party: &cOff" + NAME: "Broadcast Party: Off" MATERIAL: PAPER LORE: - - "&8&m------------------------" - - "&7The party isn't broadcasting." + - "------------------------" + - "The party isn't broadcasting." - "" - - "&e&lClick here &7to &aturn on &7broadcasting." - - "&8&m------------------------" + - "Click here to turn on broadcasting." + - "------------------------" ALL-INVITE: ENABLED: - NAME: "&eAll Invite: &aTrue" + NAME: "All Invite: True" MATERIAL: NAME_TAG LORE: - - "&8&m------------------------" - - "&7Everyone can invite players" - - "&7to the party." + - "------------------------" + - "Everyone can invite players" + - "to the party." - "" - - "&e&lClick here &7to change the status." - - "&8&m------------------------" + - "Click here to change the status." + - "------------------------" DISABLED: - NAME: "&eAll Invite: &cFalse" + NAME: "All Invite: False" MATERIAL: NAME_TAG LORE: - - "&8&m------------------------" - - "&7Only the party leader can invite" - - "&7players to the party." + - "------------------------" + - "Only the party leader can invite" + - "players to the party." - "" - - "&e&lClick here &7to change the status." - - "&8&m------------------------" + - "Click here to change the status." + - "------------------------" DUEL-REQUESTS: ENABLED: - NAME: "&eDuel Requests: &aTrue" + NAME: "Duel Requests: True" MATERIAL: DIAMOND_SWORD LORE: - - "&8&m------------------------" - - "&7Players can send duel requests" - - "&7to the party." + - "------------------------" + - "Players can send duel requests" + - "to the party." - "" - - "&e&lClick here &7to change the status." - - "&8&m------------------------" + - "Click here to change the status." + - "------------------------" DISABLED: - NAME: "&eDuel Requests: &cFalse" + NAME: "Duel Requests: False" MATERIAL: DIAMOND_SWORD LORE: - - "&8&m------------------------" - - "&7Players can't send duel requests" - - "&7to the party." + - "------------------------" + - "Players can't send duel requests" + - "to the party." - "" - - "&e&lClick here &7to change the status." - - "&8&m------------------------" + - "Click here to change the status." + - "------------------------" PARTY-CHAT: ENABLED: - NAME: "&eParty Chat: &aOn" + NAME: "Party Chat: On" MATERIAL: NOTE_BLOCK LORE: - - "&8&m------------------------" - - "&7Party members can use" - - "&7the party chat." + - "------------------------" + - "Party members can use" + - "the party chat." - "" - - "&e&lClick here &7to &cturn off &7party chat." - - "&8&m------------------------" + - "Click here to turn off party chat." + - "------------------------" DISABLED: - NAME: "&eParty Chat: &cOff" + NAME: "Party Chat: Off" MATERIAL: NOTE_BLOCK LORE: - - "&8&m------------------------" - - "&7Party members can't use" - - "&7the party chat." + - "------------------------" + - "Party members can't use" + - "the party chat." - "" - - "&e&lClick here &7to &aturn on &7party chat." - - "&8&m------------------------" + - "Click here to turn on party chat." + - "------------------------" OTHER-PARTIES: - TITLE: "&8Other Parties" + TITLE: "Other Parties" ICONS: FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE PARTY-ITEM: - NAME: "&b%leader%'s Party &7(&f%partySize%&7)" + NAME: "%leader%'s Party (%partySize%)" LORE: - MEMBER-FORMAT: " &7- &b%player%" + MEMBER-FORMAT: " - %player%" LORE: - - "&7&m------------------------" + - "------------------------" - "%members%" - "" - - "&f&lClick here &fto duel this party." - - "&7&m------------------------" + - "Click here to duel this party." + - "------------------------" FFA: ARENA-SELECTOR: - TITLE: "&8Select an &6FFA Arena" + TITLE: "Select an FFA Arena" ROWS: 3 ICONS: ARENA: BUILD-STATUS: - ENABLED: "&aEnabled" - DISABLED: "&cDisabled" - NAME: "&6%arena%" + ENABLED: "Enabled" + DISABLED: "Disabled" + NAME: "%arena%" LORE: - "" - - "&eBuild: &f%build_status%" - - "&eRe-Kit After Kill: &f%rekit_after_kill%" - - "&eHealth Reset On Kill: &f%health_reset_on_kill%" - - "&eLobby After Death: &f%lobby_after_death%" - - "&eLadders: &f%ladders%" - - "&ePlayers: &f%players%" + - "Build: %build_status%" + - "Re-Kit After Kill: %rekit_after_kill%" + - "Health Reset On Kill: %health_reset_on_kill%" + - "Lobby After Death: %lobby_after_death%" + - "Ladders: %ladders%" + - "Players: %players%" - "" - - "&aClick to join this arena!" + - "Click to join this arena!" FILLER: MATERIAL: ORANGE_STAINED_GLASS_PANE LADDER-SELECTOR: - TITLE: "&8Select a &6ladder &8to join" + TITLE: "Select a ladder to join" ICONS: LADDER: NAME: "%ladder%" LORE: - "" - - "&aClick here to select %ladder%&a." + - "Click here to select %ladder%." FILLER: MATERIAL: ORANGE_STAINED_GLASS_PANE DIVISION: - TITLE: "&8Division" + TITLE: "Division" ICONS: BACK-TO: - NAME: "&cBack to" + NAME: "Back to" MATERIAL: ARROW FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE FILLER-ITEM2: MATERIAL: ORANGE_STAINED_GLASS_PANE PAST-DIVISION: - NAME: "%fullName% &c(Past)" + NAME: "%fullName% (Past)" LORE: - "" - - " %color%┃ &fProgress: &a%progress_bar% &f(%progress_percent%%)" + - " %color%┃ Progress: %progress_bar% (%progress_percent%%)" - "" - - " &c┃ &fYou have passed this division." + - " You have passed this division." CURRENT-DIVISION: - NAME: "%fullName% &a(Current)" + NAME: "%fullName% (Current)" LORE: - "" - - " %color%┃ &fProgress: &a%progress_bar% &f(%progress_percent%%)" + - " %color%┃ Progress: %progress_bar% (%progress_percent%%)" - "" - - " &c┃ &fThis is your current division." + - " This is your current division." NEXT-DIVISION: NAME: "%fullName%" LORE: - "" - - " %color%┃ &fWins: %color%%current_wins%/%required_wins% &f(%win_progress_percent%%)" - - " %color%┃ &fElo: %color%%current_elo%/%required_elo% &f(%elo_progress_percent%%)" - - " %color%┃ &fExperience: %color%%current_exp%/%required_exp% &f(%exp_progress_percent%%)" + - " %color%┃ Wins: %color%%current_wins%/%required_wins% (%win_progress_percent%%)" + - " %color%┃ Elo: %color%%current_elo%/%required_elo% (%elo_progress_percent%%)" + - " %color%┃ Experience: %color%%current_exp%/%required_exp% (%exp_progress_percent%%)" - "" - - " %color%┃ &fProgress: &a%progress_bar% &f(%progress_percent%%)" + - " %color%┃ Progress: %progress_bar% (%progress_percent%%)" - "" PLAYER-SETTINGS: - TITLE: "&8Player Settings" # %player% + TITLE: "Player Settings" # %player% ICONS: FILLER-ITEM: NAME: " " MATERIAL: BLACK_STAINED_GLASS_PANE DUEL-REQUEST: ENABLED: - NAME: "&cToggle Duel Requests" + NAME: "Toggle Duel Requests" MATERIAL: DIAMOND_SWORD LORE: - - "&8&m--------------------------------" - - "&7If enabled, player will be" - - "&7able to send you duel requests." + - "--------------------------------" + - "If enabled, player will be" + - "able to send you duel requests." - "" - - " &a&l► &7Allow other players to duel you." - - " &7&l► &7Don't allow other players to duel you." - - "&8&m--------------------------------" + - " Allow other players to duel you." + - " Don't allow other players to duel you." + - "--------------------------------" DISABLED: - NAME: "&cToggle Duel Requests" + NAME: "Toggle Duel Requests" MATERIAL: DIAMOND_SWORD LORE: - - "&8&m--------------------------------" - - "&7If enabled, player will be" - - "&7able to send you duel requests." + - "--------------------------------" + - "If enabled, player will be" + - "able to send you duel requests." - "" - - " &7&l► &7Allow other players to duel you." - - " &c&l► &7Don't allow other players to duel you." - - "&8&m--------------------------------" + - " Allow other players to duel you." + - " Don't allow other players to duel you." + - "--------------------------------" SIDEBAR: ENABLED: - NAME: "&6Toggle Scoreboard" + NAME: "Toggle Scoreboard" MATERIAL: PAINTING LORE: - - "&8&m--------------------------------" - - "&7If enabled, you will be able" - - "&7to see the scoreboard." + - "--------------------------------" + - "If enabled, you will be able" + - "to see the scoreboard." - "" - - " &a&l► &7Show scoreboard." - - " &7&l► &7Hide scoreboard." - - "&8&m--------------------------------" + - " Show scoreboard." + - " Hide scoreboard." + - "--------------------------------" DISABLED: - NAME: "&6Toggle Scoreboard" + NAME: "Toggle Scoreboard" MATERIAL: PAINTING LORE: - - "&8&m--------------------------------" - - "&7If enabled, you will be able" - - "&7to see the scoreboard." + - "--------------------------------" + - "If enabled, you will be able" + - "to see the scoreboard." - "" - - " &7&l► &7Show scoreboard." - - " &c&l► &7Hide scoreboard." - - "&8&m--------------------------------" + - " Show scoreboard." + - " Hide scoreboard." + - "--------------------------------" PARTY-INVITE: ENABLED: - NAME: "&dParty Invite Requests" + NAME: "Party Invite Requests" MATERIAL: FEATHER LORE: - - "&8&m--------------------------------" - - "&7If enabled, players will be able" - - "&7to send you party invites." + - "--------------------------------" + - "If enabled, players will be able" + - "to send you party invites." - "" - - " &a&l► &7Allow party leaders to invite you." - - " &7&l► &7Don't allow party leaders to invite you." - - "&8&m--------------------------------" + - " Allow party leaders to invite you." + - " Don't allow party leaders to invite you." + - "--------------------------------" DISABLED: - NAME: "&dParty Invite Requests" + NAME: "Party Invite Requests" MATERIAL: FEATHER LORE: - - "&8&m--------------------------------" - - "&7If enabled, players will be able" - - "&7to send you party invites." + - "--------------------------------" + - "If enabled, players will be able" + - "to send you party invites." - "" - - " &7&l► &7Allow party leaders to invite you." - - " &c&l► &7Don't allow party leaders to invite you." - - "&8&m--------------------------------" + - " Allow party leaders to invite you." + - " Don't allow party leaders to invite you." + - "--------------------------------" PRIVATE-MESSAGE: ENABLED: - NAME: "&9Private Messages" + NAME: "Private Messages" MATERIAL: PAPER LORE: - - "&8&m--------------------------------" - - "&7If enabled, players will be" - - "&7able to message you." + - "--------------------------------" + - "If enabled, players will be" + - "able to message you." - "" - - " &a&l► &7Let players send messages to you." - - " &7&l► &7Don't let players send messages to you." - - "&8&m--------------------------------" + - " Let players send messages to you." + - " Don't let players send messages to you." + - "--------------------------------" DISABLED: - NAME: "&9Private Messages" + NAME: "Private Messages" MATERIAL: PAPER LORE: - - "&8&m--------------------------------" - - "&7If enabled, players will be" - - "&7able to message you." + - "--------------------------------" + - "If enabled, players will be" + - "able to message you." - "" - - " &7&l► &7Let players send messages to you." - - " &c&l► &7Don't let players send messages to you." - - "&8&m--------------------------------" + - " Let players send messages to you." + - " Don't let players send messages to you." + - "--------------------------------" HIDE-PLAYERS: ENABLED: - NAME: "&9Player Visibility" + NAME: "Player Visibility" MATERIAL: GHAST_TEAR LORE: - - "&8&m--------------------------------" - - "&7If enabled, you will be able to" - - "&7see other players in the lobby." + - "--------------------------------" + - "If enabled, you will be able to" + - "see other players in the lobby." - "" - - " &a&l► &7See players in the lobby." - - " &7&l► &7Don't see players in the lobby." - - "&8&m--------------------------------" + - " See players in the lobby." + - " Don't see players in the lobby." + - "--------------------------------" DISABLED: - NAME: "&9Player Visibility" + NAME: "Player Visibility" MATERIAL: GHAST_TEAR LORE: - - "&8&m--------------------------------" - - "&7If enabled, you will be able to" - - "&7see other players in the lobby." + - "--------------------------------" + - "If enabled, you will be able to" + - "see other players in the lobby." - "" - - " &7&l► &7See players in the lobby." - - " &c&l► &7Don't see players in the lobby." - - "&8&m--------------------------------" + - " See players in the lobby." + - " Don't see players in the lobby." + - "--------------------------------" ALLOW-SPECTATORS: ENABLED: - NAME: "&7Allow Spectators" + NAME: "Allow Spectators" MATERIAL: EMERALD LORE: - - "&8&m--------------------------------" - - "&7If enabled, players can" - - "&7spectate your matches." + - "--------------------------------" + - "If enabled, players can" + - "spectate your matches." - "" - - " &a&l► &7Let players spectate your matches." - - " &7&l► &7Don't let players spectate your matches." - - "&8&m--------------------------------" + - " Let players spectate your matches." + - " Don't let players spectate your matches." + - "--------------------------------" DISABLED: - NAME: "&7Allow Spectators" + NAME: "Allow Spectators" MATERIAL: EMERALD LORE: - - "&8&m--------------------------------" - - "&7If enabled, players can" - - "&7spectate your matches." + - "--------------------------------" + - "If enabled, players can" + - "spectate your matches." - "" - - " &7&l► &7Let players spectate your matches." - - " &c&l► &7Don't let players spectate your matches." - - "&8&m--------------------------------" + - " Let players spectate your matches." + - " Don't let players spectate your matches." + - "--------------------------------" FLYING: ENABLED: - NAME: "&7Flying" + NAME: "Flying" MATERIAL: ELYTRA LORE: - - "&8&m--------------------------------" - - "&7If enabled, you can fly in the lobby." + - "--------------------------------" + - "If enabled, you can fly in the lobby." - "" - - " &a&l► &7Enabled." - - " &7&l► &7Disabled." - - "&8&m--------------------------------" + - " Enabled." + - " Disabled." + - "--------------------------------" DISABLED: - NAME: "&7Flying" + NAME: "Flying" MATERIAL: ELYTRA LORE: - - "&8&m--------------------------------" - - "&7If enabled, you can fly in the lobby." + - "--------------------------------" + - "If enabled, you can fly in the lobby." - "" - - " &7&l► &7Enabled." - - " &c&l► &7Disabled." - - "&8&m--------------------------------" + - " Enabled." + - " Disabled." + - "--------------------------------" WORLD-TIME: - NAME: "&eWorld Time: &a%worldTime%" + NAME: "World Time: %worldTime%" MATERIAL: BLAZE_POWDER LORE: - - "&8&m--------------------------------" - - "&7Click here to change time." - - "&8&m--------------------------------" + - "--------------------------------" + - "Click here to change time." + - "--------------------------------" PREFIX-VISIBILITY: - NAME: "&dName Decorations: &f%prefixVisibility%" + NAME: "Name Decorations: %prefixVisibility%" MATERIAL: NAME_TAG LORE: - - "&8&m--------------------------------" - - "&7Choose what to show from your" - - "&7chat/tab/sidebar/nametag decorations." + - "--------------------------------" + - "Choose what to show from your" + - "chat/tab/sidebar/nametag decorations." - "" - - "&aModes: NONE, PREFIX, SUFFIX, BOTH" - - "&8&m--------------------------------" + - "Modes: NONE, PREFIX, SUFFIX, BOTH" + - "--------------------------------" PLAYER-INFORMATION: # /prac info command MAIN-PAGE: - TITLE: "&c%player%'s &8info" + TITLE: "%player%'s info" ICONS: REFRESH: - NAME: "&aRefresh Page" + NAME: "Refresh Page" MATERIAL: NETHER_STAR LORE: - - "&8&m------------------------" - - "&7Click here to refresh the page." - - "&8&m------------------------" + - "------------------------" + - "Click here to refresh the page." + - "------------------------" BASIC-INFO: - NAME: "&6Basic Informations" - ONLINE-STATUS: "&aOnline" + NAME: "Basic Informations" + ONLINE-STATUS: "Online" LORE: - - "&8&m------------------------" - - "&eName: &7%player%" - - "&eUUID: &7%uuid%" + - "------------------------" + - "Name: %player%" + - "UUID: %uuid%" - "" - - "&eFirst Played: &7%first_played%" - - "&eLast Joined: &7%last_played%" + - "First Played: %first_played%" + - "Last Joined: %last_played%" - "" - - "&eUnranked Left: &7%unranked_left%" - - "&eRanked Left: &7%ranked_left%" + - "Unranked Left: %unranked_left%" + - "Ranked Left: %ranked_left%" - "" - - "&eDivision: &7%division_fullName%" - - "&8&m------------------------" + - "Division: %division_fullName%" + - "------------------------" RANKED-BAN: - NAME: "&6%player% &7is banned from playing ranked." + NAME: "%player% is banned from playing ranked." MATERIAL: EMERALD LORE: - - "&8&m------------------------" - - "&eBanner: &7%banner%" - - "&eReason: &7%reason%" - - "&eBanned at: &7%time%" - - "&8&m------------------------" - - "&aClick here &7to &eunban &7the player." - - "&8&m------------------------" + - "------------------------" + - "Banner: %banner%" + - "Reason: %reason%" + - "Banned at: %time%" + - "------------------------" + - "Click here to unban the player." + - "------------------------" ONLINE-INFO: PLAYER-OFFLINE: - NAME: "&cPlayer is not online!" + NAME: "Player is not online!" MATERIAL: FEATHER PLAYER-ONLINE: - NAME: "&6Online Players Information's" + NAME: "Online Players Information's" MATERIAL: FEATHER LORE: - - "&8&m------------------------" - - "&eIn World: &7%world%" - - "&eGamemode: &7%gamemode%" - - "&eFlying: &7%flying%" - - "&eTablist Name: &7%tablist_name%" - - "&eHealth: &7%health%" - - "&eFood Level: &7%food%" - - "&eHit Delay: &7%hit_delay%" - - "&ePing: &7%ping%ms" - - "&8&m------------------------" + - "------------------------" + - "In World: %world%" + - "Gamemode: %gamemode%" + - "Flying: %flying%" + - "Tablist Name: %tablist_name%" + - "Health: %health%" + - "Food Level: %food%" + - "Hit Delay: %hit_delay%" + - "Ping: %ping%ms" + - "------------------------" GAME: OFFLINE: - NAME: "&cPlayer is offline" + NAME: "Player is offline" MATERIAL: REDSTONE IN-MATCH: - NAME: "&ePlayer is in a match." + NAME: "Player is in a match." MATERIAL: CLOCK LORE: - - "&8&m------------------------" - - "&eLeft-Click &7to start spectating the match." - - "&6Right-Click &7to get the player out of the match." - - "&8&m------------------------" + - "------------------------" + - "Left-Click to start spectating the match." + - "Right-Click to get the player out of the match." + - "------------------------" IN-EVENT: - NAME: "&ePlayer is in a event." + NAME: "Player is in a event." MATERIAL: CLOCK LORE: - - "&8&m------------------------" - - "&eLeft-Click &7to start spectating the event." - - "&6Right-Click &7to get the player out of the event." - - "&8&m------------------------" + - "------------------------" + - "Left-Click to start spectating the event." + - "Right-Click to get the player out of the event." + - "------------------------" IN-FFA: - NAME: "&ePlayer is in a FFA." + NAME: "Player is in a FFA." MATERIAL: CLOCK LORE: - - "&8&m------------------------" - - "&eLeft-Click &7to start spectating the FFA." - - "&6Right-Click &7to get the player out of the FFA." - - "&8&m------------------------" + - "------------------------" + - "Left-Click to start spectating the FFA." + - "Right-Click to get the player out of the FFA." + - "------------------------" SPECTATING: - NAME: "&ePlayer is spectating." + NAME: "Player is spectating." MATERIAL: CLOCK LORE: - - "&8&m------------------------" - - "&eLeft-Click &7to start spectating the same thing." - - "&6Right-Click &7to end the spectating." - - "&8&m------------------------" + - "------------------------" + - "Left-Click to start spectating the same thing." + - "Right-Click to end the spectating." + - "------------------------" NOTHING: - NAME: "&cPlayer does nothing" + NAME: "Player does nothing" MATERIAL: REDSTONE LORE: - - "&8&m------------------------" - - "&7Player does not play in a" - - "&7match or event and does not" - - "&7spectate anything." - - "&8&m------------------------" + - "------------------------" + - "Player does not play in a" + - "match or event and does not" + - "spectate anything." + - "------------------------" PARTY: IN-PARTY: - NAME: "&aPlayer is in a party." + NAME: "Player is in a party." MATERIAL: NAME_TAG NOT-IN-PARTY: - NAME: "&cPlayer is not in a party." + NAME: "Player is not in a party." MATERIAL: NAME_TAG STATISTICS: - NAME: "&cStatistics" + NAME: "Statistics" MATERIAL: FIREWORK_STAR LORE: - - "&8&m------------------------" - - "&7Click here to view the" - - "&7player's statistics." - - "&8&m------------------------" + - "------------------------" + - "Click here to view the" + - "player's statistics." + - "------------------------" LADDER-STATS: - TITLE: "&8%player% ladder stats" + TITLE: "%player% ladder stats" ICONS: BACK-TO-HUB: - NAME: "&eBack to hub" + NAME: "Back to hub" MATERIAL: ARROW REFRESH: - NAME: "&aRefresh Page" + NAME: "Refresh Page" MATERIAL: NETHER_STAR LORE: - - "&8&m------------------------" - - "&7Click here to refresh the page." - - "&8&m------------------------" + - "------------------------" + - "Click here to refresh the page." + - "------------------------" RESET-ALL-STATS: - NAME: "&cReset ALL Stats" + NAME: "Reset ALL Stats" MATERIAL: GHAST_TEAR LORE: - - "&8&m------------------------" - - "&7Click here to restart all" - - "&7the player's ladder statistics." - - "&8&m------------------------" + - "------------------------" + - "Click here to restart all" + - "the player's ladder statistics." + - "------------------------" LADDER: - NULL-STAT: "&cN/A" + NULL-STAT: "N/A" UNRANKED-LADDER-STATS: - NAME: "&e%ladder% ladder" + NAME: "%ladder% ladder" DEFAULT-MATERIAL: BEDROCK LORE: - - "&8&m------------------------" - - "&eWins: &f%wins%" - - "&eLosses: &f%losses%" + - "------------------------" + - "Wins: %wins%" + - "Losses: %losses%" - "" - - "&eCustom Kits: &f%custom_kits%" - - "&8&m------------------------" - - "&cClick here &7to reset the ladder stats." - - "&8&m------------------------" + - "Custom Kits: %custom_kits%" + - "------------------------" + - "Click here to reset the ladder stats." + - "------------------------" RANKED-LADDER-STATS: - NAME: "&e%ladder% ladder" + NAME: "%ladder% ladder" DEFAULT-MATERIAL: BEDROCK LORE: - - "&8&m------------------------" - - "&eUnranked Wins: &f%unranked_wins%" - - "&eUnranked Losses: &f%unranked_losses%" - - "&eUnranked Custom Kits: &f%unranked_custom_kits%" + - "------------------------" + - "Unranked Wins: %unranked_wins%" + - "Unranked Losses: %unranked_losses%" + - "Unranked Custom Kits: %unranked_custom_kits%" - "" - - "&eRanked Wins: &f%ranked_wins%" - - "&eRanked Losses: &f%ranked_losses%" - - "&eRanked Custom Kits: &f%ranked_custom_kits%" + - "Ranked Wins: %ranked_wins%" + - "Ranked Losses: %ranked_losses%" + - "Ranked Custom Kits: %ranked_custom_kits%" - "" - - "&eELO: &f%elo%" - - "&8&m------------------------" - - "&cClick here &7to reset the ladder stats." - - "&8&m------------------------" + - "ELO: %elo%" + - "------------------------" + - "Click here to reset the ladder stats." + - "------------------------" SELECTORS: ARENA-SELECTOR: - TITLE: "%matchType% &8- Arena" + TITLE: "%matchType% - Arena" ICONS: BACK-TO-SELECTOR: - NAME: "&eBack to kit selector" + NAME: "Back to kit selector" MATERIAL: ARROW RANDOM-ARENA: - NAME: "&6Random Arena" + NAME: "Random Arena" MATERIAL: NETHER_STAR LORE: - - "&8&m------------------------" - - "&7Click here to pick a" - - "&erandom &7arena for the match." - - "&8&m------------------------" + - "------------------------" + - "Click here to pick a" + - "random arena for the match." + - "------------------------" ARENA-ICON: NAME: "%arena%" LORE: - - "&8&m------------------------" - - "&7Click here to select" - - "&7arena %arena%&7." - - "&8&m------------------------" + - "------------------------" + - "Click here to select" + - "arena %arena%." + - "------------------------" LADDER-SELECTOR: - TITLE: "%matchType% &8- Kit" + TITLE: "%matchType% - Kit" ICONS: LADDER: NAME: "%ladder%" LORE: - - "&8&m------------------------" - - "&7Click here to select" - - "&7ladder %ladder%&7." - - "&8&m------------------------" + - "------------------------" + - "Click here to select" + - "ladder %ladder%." + - "------------------------" FILLER-ITEM: MATERIAL: GRAY_STAINED_GLASS_PANE BASE-CUSTOM-PLAYER-KIT-ICON: - NAME: "&6Custom Kit" + NAME: "Custom Kit" MATERIAL: DIAMOND_SWORD LORE: - - "&8&m------------------------" - - "&7Click here to play" - - "&7with your own custom kit." - - "&8&m------------------------" + - "------------------------" + - "Click here to play" + - "with your own custom kit." + - "------------------------" EVENT-HOST: # You can set each event icon in the game. - TITLE: "&4Host Event" + TITLE: "Host Event" BRACKETS-KIT-SELECTOR: - TITLE: "&8Brackets Kit Source" + TITLE: "Brackets Kit Source" ICONS: DEFAULT-KIT: - NAME: "&6Use Admin Preset" + NAME: "Use Admin Preset" MATERIAL: CHEST LORE: - - "&8&m------------------------" - - "&7Start Brackets with the" - - "&7configured admin event kit." + - "------------------------" + - "Start Brackets with the" + - "configured admin event kit." - "" - - "&aClick to select" - - "&8&m------------------------" + - "Click to select" + - "------------------------" CUSTOM-KIT: - NAME: "&a%kitName%" + NAME: "%kitName%" MATERIAL: BOOK LORE: - - "&8&m------------------------" - - "&7Use this custom player kit" - - "&7for the entire Brackets event." + - "------------------------" + - "Use this custom player kit" + - "for the entire Brackets event." - "" - - "&aClick to select" - - "&8&m------------------------" + - "Click to select" + - "------------------------" NO-CUSTOM-KIT: - NAME: "&cNo available custom kits" + NAME: "No available custom kits" MATERIAL: BARRIER LORE: - - "&8&m------------------------" - - "&7Enable and configure your" - - "&7custom kits in the player kit menu" - - "&7to list them here." - - "&8&m------------------------" + - "------------------------" + - "Enable and configure your" + - "custom kits in the player kit menu" + - "to list them here." + - "------------------------" LADDER-PREVIEW: - TITLE: "&8Preview of %ladder%" + TITLE: "Preview of %ladder%" ICONS: NO-EFFECT: - NAME: "&5Ladder Effects" + NAME: "Ladder Effects" MATERIAL: POTION DAMAGE: 8233 LORE: - - "&8&m------------------------" - - "&7This ladder has no effects." - - "&8&m------------------------" + - "------------------------" + - "This ladder has no effects." + - "------------------------" HAS-EFFECT: - FORMAT: "&d%name% %amplifier% &7for %time%" + FORMAT: "%name% %amplifier% for %time%" ICON: - NAME: "&5Ladder Effects" + NAME: "Ladder Effects" MATERIAL: POTION DAMAGE: 8233 LORE: - - "&8&m------------------------" - - "&eYou will get these effects," - - "&ewhen the game starts." + - "------------------------" + - "You will get these effects," + - "when the game starts." - "" - "%effects%" - - "&8&m------------------------" + - "------------------------" MATCH-STATISTICS: TITLE: - MULTIPLE-ROUND: "&8%player%'s Stat - R: %round%" - SINGLE-ROUND: "&8%player%'s Stat" + MULTIPLE-ROUND: "%player%'s Stat - R: %round%" + SINGLE-ROUND: "%player%'s Stat" ICONS: POTION: - NAME: "&cHealth Potions: &f%potion_left%" + NAME: "Health Potions: %potion_left%" MATERIAL: POTION DAMAGE: 16421 LORE: - - "&8&m--------------------" - - "&cPotions Thrown: &f%potion_thrown%" - - "&cPotions Missed: &f%potion_missed%" - - "&cPotion Accuracy: &f%potion_accuracy%" - - "&8&m--------------------" + - "--------------------" + - "Potions Thrown: %potion_thrown%" + - "Potions Missed: %potion_missed%" + - "Potion Accuracy: %potion_accuracy%" + - "--------------------" HEALTH: - NAME: "&cHealth: &f20/%end_hearth% &c♥" + NAME: "Health: 20/%end_hearth% ♥" MATERIAL: PLAYER_HEAD HUNGER: - NAME: "&cHunger: &f20/%end_hunger%" + NAME: "Hunger: 20/%end_hunger%" MATERIAL: COOKED_BEEF EFFECT: NO-EFFECT: - NAME: "&cPotion Effects" + NAME: "Potion Effects" MATERIAL: BREWING_STAND LORE: - - "&8&m------------------------" - - "&cPlayer didn't have any effects" - - "&cleft at the end of the game." - - "&8&m------------------------" + - "------------------------" + - "Player didn't have any effects" + - "left at the end of the game." + - "------------------------" HAS-EFFECT: - FORMAT: " &f✱ &c%name% %amplifier% &7- &f %time%" + FORMAT: " %name% %amplifier% - %time%" ICON: - NAME: "&cPotion Effects" + NAME: "Potion Effects" MATERIAL: POTION DAMAGE: 8233 LORE: - - "&8&m------------------------" + - "------------------------" - "%effects%" - - "&8&m------------------------" + - "------------------------" STATS: - NAME: "&cMatch Statistics" + NAME: "Match Statistics" MATERIAL: DIAMOND_SWORD LORE: - - "&8&m------------------------" - - " &f✱ &cTotal Hits: &f%total_hits%" - - " &f✱ &cTotal Hits Received: &f%total_hits_received%" + - "------------------------" + - " Total Hits: %total_hits%" + - " Total Hits Received: %total_hits_received%" - "" - - " &f✱ &cLongest Combo: &f%longest_combo%" - - " &f✱ &cAvarage CPS: &f%avarage_cps%" - - "&8&m------------------------" + - " Longest Combo: %longest_combo%" + - " Avarage CPS: %avarage_cps%" + - "------------------------" VIEW-ROUND: - NAME: "&7&lClick-here &7to view your round &c%round% &7statstics." + NAME: "Click-here to view your round %round% statstics." MATERIAL: PAPER PLAYER-INVENTORY: - TITLE: "&c%player%'s &8inventory" + TITLE: "%player%'s inventory" ICONS: FILLER-ITEM: NAME: " " MATERIAL: BLACK_STAINED_GLASS_PANE HEALTH: - NAME: "&cHealth: &f20/%health% &c♥" + NAME: "Health: 20/%health% ♥" MATERIAL: REDSTONE HUNGER: - NAME: "&cHunger: &f20/%hunger%" + NAME: "Hunger: 20/%hunger%" MATERIAL: COOKED_BEEF EFFECT: - FORMAT: " &f✱ &c%name% %amplifier% &7- &f %time%" + FORMAT: " %name% %amplifier% - %time%" ICON: - NAME: "&cPotion Effects" + NAME: "Potion Effects" MATERIAL: POTION DAMAGE: 8233 LORE: - - "&8&m------------------------" + - "------------------------" - "%effects%" - - "&8&m------------------------" + - "------------------------" UNRANKED-GUI: - LB-FORMAT: "&e%placement%# &f%player% &7» &f%score%" - TITLE: "%weight_class% Queue &8- &b%category%" + LB-FORMAT: "%placement%# %player% » %score%" + TITLE: "%weight_class% Queue - %category%" ICONS: FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE CATEGORY-SELECTOR: - NAME: "&7%category%" + NAME: "%category%" MATERIAL: BOOK LORE: - - "&8&m------------------------" - - "&7Browse ladders in this category" - - "&7Find your favorite queue faster" + - "------------------------" + - "Browse ladders in this category" + - "Find your favorite queue faster" - "" - - "&7Ladders" - - "&f%category_ladders%" + - "Ladders" + - "%category_ladders%" - "" - - "&eClick to select this category" - - "&8&m------------------------" + - "Click to select this category" + - "------------------------" SELECTED-CATEGORY-SELECTOR: - NAME: "&b%category%" + NAME: "%category%" MATERIAL: ENCHANTED_BOOK LORE: - - "&8&m------------------------" - - "&7Browse ladders in this category" - - "&7Find your favorite queue faster" + - "------------------------" + - "Browse ladders in this category" + - "Find your favorite queue faster" - "" - - "&7Ladders" - - "&f%category_ladders%" + - "Ladders" + - "%category_ladders%" - "" - - "&cAlready selected" - - "&8&m------------------------" + - "Already selected" + - "------------------------" QUICK-MATCH: - NAME: "&a&lQuick Match" + NAME: "Quick Match" MATERIAL: NETHER_STAR LORE: - - "&8&m------------------------" - - "&7Instantly pick a random kit" - - "&7from the selected category" + - "------------------------" + - "Instantly pick a random kit" + - "from the selected category" - "" - - "&eClick to queue immediately" - - "&8&m------------------------" + - "Click to queue immediately" + - "------------------------" SWITCH-TO-RANKED: - NAME: "&cSwitch to Ranked" + NAME: "Switch to Ranked" MATERIAL: IRON_SWORD LORE: - - "&8&m------------------------" - - "&7Switch to the ranked" - - "&7queue selector" + - "------------------------" + - "Switch to the ranked" + - "queue selector" - "" - - "&eClick to switch" - - "&8&m------------------------" + - "Click to switch" + - "------------------------" CUSTOM-KIT-QUEUE: - NAME: "&6&lCustom Kit Queue" + NAME: "Custom Kit Queue" MATERIAL: BOOK LORE: - - "&8&m------------------------" - - "&7Host your own custom kit" - - "&7or join someone else's" + - "------------------------" + - "Host your own custom kit" + - "or join someone else's" - "" - - "&eClick to open" - - "&8&m------------------------" + - "Click to open" + - "------------------------" LADDER: NAME: "%ladder%" LORE: # Options: %elo%, %win%, %kills%, %deaths%, %win_streak%, %best_win_streak%, %lose_streak%, %best_lose_streak% - - " &c&l» &eUnranked" - - " &fFighting: &e%in_fight%" - - " &fQueueing: &e%in_queue%" + - " » Unranked" + - " Fighting: %in_fight%" + - " Queueing: %in_queue%" - "" - - "&eWinstreak Top 3" + - "Winstreak Top 3" - "%lb_win_streak_1%" - "%lb_win_streak_2%" - "%lb_win_streak_3%" - "" - - "&eClick here to join the %weight_class% %ladder% &equeue." + - "Click here to join the %weight_class% %ladder% queue." FROZEN-LADDER-ITEM: # You can set different material and damage for this item. NAME: "%ladder%" LORE: - "" - - "&eThis ladder is &bfrozen&e." + - "This ladder is frozen." DISABLED-LADDER-ITEM: # You can set different material and damage for this item. NAME: "%ladder%" LORE: - "" - - "&eThis ladder is &cdisabled&e." + - "This ladder is disabled." RANKED-GUI: - LB-FORMAT: "&e%placement%# &f%player% &7» &f%score%" - TITLE: "%weight_class% Queue &8- &c%category%" + LB-FORMAT: "%placement%# %player% » %score%" + TITLE: "%weight_class% Queue - %category%" ICONS: FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE CATEGORY-SELECTOR: - NAME: "&7%category%" + NAME: "%category%" MATERIAL: BOOK LORE: - - "&8&m------------------------" - - "&7Browse ladders in this category" - - "&7Find your favorite queue faster" + - "------------------------" + - "Browse ladders in this category" + - "Find your favorite queue faster" - "" - - "&7Ladders" - - "&f%category_ladders%" + - "Ladders" + - "%category_ladders%" - "" - - "&eClick to select this category" - - "&8&m------------------------" + - "Click to select this category" + - "------------------------" SELECTED-CATEGORY-SELECTOR: - NAME: "&c%category%" + NAME: "%category%" MATERIAL: ENCHANTED_BOOK LORE: - - "&8&m------------------------" - - "&7Browse ladders in this category" - - "&7Find your favorite queue faster" + - "------------------------" + - "Browse ladders in this category" + - "Find your favorite queue faster" - "" - - "&7Ladders" - - "&f%category_ladders%" + - "Ladders" + - "%category_ladders%" - "" - - "&cAlready selected" - - "&8&m------------------------" + - "Already selected" + - "------------------------" QUICK-MATCH: - NAME: "&a&lQuick Match" + NAME: "Quick Match" MATERIAL: NETHER_STAR LORE: - - "&8&m------------------------" - - "&7Instantly pick a random kit" - - "&7from the selected category" + - "------------------------" + - "Instantly pick a random kit" + - "from the selected category" - "" - - "&eClick to queue immediately" - - "&8&m------------------------" + - "Click to queue immediately" + - "------------------------" SWITCH-TO-UNRANKED: - NAME: "&aSwitch to Unranked" + NAME: "Switch to Unranked" MATERIAL: WOODEN_SWORD LORE: - - "&8&m------------------------" - - "&7Switch to the unranked" - - "&7queue selector" + - "------------------------" + - "Switch to the unranked" + - "queue selector" - "" - - "&eClick to switch" - - "&8&m------------------------" + - "Click to switch" + - "------------------------" CUSTOM-KIT-QUEUE: - NAME: "&6&lCustom Kit Queue" + NAME: "Custom Kit Queue" MATERIAL: BOOK LORE: - - "&8&m------------------------" - - "&7Host your own custom kit" - - "&7or join someone else's" + - "------------------------" + - "Host your own custom kit" + - "or join someone else's" - "" - - "&eClick to open" - - "&8&m------------------------" + - "Click to open" + - "------------------------" LADDER: NAME: "%ladder%" LORE: # Options: %elo%, %win%, %kills%, %deaths%, %win_streak%, %best_win_streak%, %lose_streak%, %best_lose_streak% - - " &c&l» &cRanked" - - " &fFighting: &e%in_fight%" - - " &fQueueing: &e%in_queue%" + - " » Ranked" + - " Fighting: %in_fight%" + - " Queueing: %in_queue%" - "" - - "&eElo Top 3" + - "Elo Top 3" - "%lb_elo_1%" - "%lb_elo_2%" - "%lb_elo_3%" - "" - - "&eClick here to join the %weight_class% %ladder% &equeue." + - "Click here to join the %weight_class% %ladder% queue." FROZEN-LADDER-ITEM: # You can set different material and damage for this item. NAME: "%ladder%" LORE: - "" - - "&eThis ladder is &bfrozen&e." + - "This ladder is frozen." DISABLED-LADDER-ITEM: # You can set different material and damage for this item. NAME: "%ladder%" LORE: - "" - - "&eThis ladder is &cdisabled&e." + - "This ladder is disabled." CUSTOM-KIT-QUEUE: CHOOSE-TYPE: - TITLE: "&8Custom Kit Queue" + TITLE: "Custom Kit Queue" SIZE: 3 SLOTS: HOST-OWN: 11 @@ -1337,30 +1337,30 @@ GUIS: NAME: " " MATERIAL: BLACK_STAINED_GLASS_PANE QUEUE-OWN-KIT: - NAME: "&aQueue Your Own Kit" + NAME: "Queue Your Own Kit" MATERIAL: WRITABLE_BOOK LORE: - - "&8&m------------------------" - - "&7Select one of your saved" - - "&7custom kits and host it" + - "------------------------" + - "Select one of your saved" + - "custom kits and host it" - "" - - "&eClick to continue" - - "&8&m------------------------" + - "Click to continue" + - "------------------------" QUEUE-OTHERS-KITS: - NAME: "&eQueue Others Kits" + NAME: "Queue Others Kits" MATERIAL: BOOK LORE: - - "&8&m------------------------" - - "&7Join the first available" - - "&7hosted custom-kit queue" + - "------------------------" + - "Join the first available" + - "hosted custom-kit queue" - "" - - "&eClick to search" - - "&8&m------------------------" + - "Click to search" + - "------------------------" BACK: - NAME: "&cBack" + NAME: "Back" MATERIAL: ARROW HOST-SELECTOR: - TITLE: "&8Select Custom Kit To Host" + TITLE: "Select Custom Kit To Host" SIZE: 3 SLOTS: BACK: 22 @@ -1378,20 +1378,20 @@ GUIS: NAME: " " MATERIAL: BLACK_STAINED_GLASS_PANE NO-KITS: - NAME: "&cNo Saved Custom Kits" + NAME: "No Saved Custom Kits" MATERIAL: BARRIER LORE: - - "&8&m------------------------" - - "&7Create and enable a custom kit" - - "&7first, then come back here." + - "------------------------" + - "Create and enable a custom kit" + - "first, then come back here." - "" - - "&eUse custom kit editor" - - "&8&m------------------------" + - "Use custom kit editor" + - "------------------------" BACK: - NAME: "&cBack" + NAME: "Back" MATERIAL: ARROW QUEUE-OTHERS: - TITLE: "&8Join Custom Kit Queue" + TITLE: "Join Custom Kit Queue" SIZE: 3 SLOTS: NO-HOSTED: 13 @@ -1401,29 +1401,29 @@ GUIS: NAME: " " MATERIAL: BLACK_STAINED_GLASS_PANE NO-HOSTED: - NAME: "&cNo One Hosting" + NAME: "No One Hosting" MATERIAL: BARRIER LORE: - - "&8&m------------------------" - - "&7There are no custom kit" - - "&7queues available at the moment." + - "------------------------" + - "There are no custom kit" + - "queues available at the moment." - "" - - "&eWait for others to host" - - "&8&m------------------------" + - "Wait for others to host" + - "------------------------" BACK: - NAME: "&cBack" + NAME: "Back" MATERIAL: ARROW SPECTATOR-MENU: - TITLE: "&8Spectator Menu - Page %page%" + TITLE: "Spectator Menu - Page %page%" ICONS: PAGE-LEFT: - NAME: "&6Go to Page %page%" + NAME: "Go to Page %page%" MATERIAL: ARROW CLOSE: - NAME: "&cClose Spectator Menu" + NAME: "Close Spectator Menu" MATERIAL: ARROW PAGE-RIGHT: - NAME: "&6Go to Page %page%" + NAME: "Go to Page %page%" MATERIAL: ARROW FILLER-ITEM: NAME: " " @@ -1431,1704 +1431,1720 @@ GUIS: MATCH-ICON: NAME: "%match_type%" LORE: - - "&8#%match_id%" + - "#%match_id%" - "%weight_class%" - "" - - "&eMatch Type: &f%match_type%" - - "&eKit: &f%ladder%" - - "&eArena: &f%arena%" - - "&eRound: &f%round%" - - "&eDuration: &f%roundDuration%" - - "&eSpectators: &f%spectators%" + - "Match Type: %match_type%" + - "Kit: %ladder%" + - "Arena: %arena%" + - "Round: %round%" + - "Duration: %roundDuration%" + - "Spectators: %spectators%" - "" - - "&a» Click to spectate «" + - "» Click to spectate «" EVENT-ICON: - NAME: "&e%event_type%" + NAME: "%event_type%" LORE: - - "&eDuration: &f%event_duration%" - - "&ePlayers: &f%players%" - - "&eSpectators: &f%spectators%" + - "Duration: %event_duration%" + - "Players: %players%" + - "Spectators: %spectators%" - "" - - "&a» Click to spectate «" + - "» Click to spectate «" FFA-ICON: BUILD-STATUS: - ENABLED: "&aEnabled" - DISABLED: "&cDisabled" - NAME: "&6FFA" + ENABLED: "Enabled" + DISABLED: "Disabled" + NAME: "FFA" LORE: - - "&eBuild: &f%build_status%" - - "&eArena: &f%arena%" - - "&ePlayers: &f%players%" - - "&eSpectators: &f%spectators%" + - "Build: %build_status%" + - "Arena: %arena%" + - "Players: %players%" + - "Spectators: %spectators%" - "" - - "&a» Click to spectate «" + - "» Click to spectate «" SETUP: HUB: - TITLE: "&cServer Manager" + TITLE: "Server Manager" ICONS: GENERAL-FILLER-ITEM: NAME: " " MATERIAL: ORANGE_STAINED_GLASS_PANE ARENA-MANAGER: - NAME: "&6Arena Manager" + NAME: "Arena Manager" MATERIAL: NETHER_STAR LADDER-MANAGER: - NAME: "&eLadder Manager" + NAME: "Ladder Manager" MATERIAL: GOLDEN_SWORD HOLOGRAM-MANAGER: - NAME: "&bHologram Manager" + NAME: "Hologram Manager" MATERIAL: PAPER EVENT-MANAGER: - NAME: "&2Event Manager" + NAME: "Event Manager" MATERIAL: IRON_HELMET SERVER-MANAGER: - NAME: "&cServer Manager" + NAME: "Server Manager" MATERIAL: NAME_TAG FFA-ARENA: MAIN: - TITLE: "&9%arenaName% &8- Arena" + TITLE: "%arenaName% - Arena" ICONS: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW DELETE: - NAME: "&cDelete Arena" + NAME: "Delete Arena" MATERIAL: RED_DYE ARENA-NAME: - NAME: "&6%arenaDisplayName%" + NAME: "%arenaDisplayName%" MATERIAL: BEDROCK LORE: - "" - - "&eArena Type: &b%arenaType%" + - "Arena Type: %arenaType%" - "" - - "&e&lLeft-Click here &7to get detailed information." - - "&6&lRight-Click here &7to get a setup item for the arena." + - "Left-Click here to get detailed information." + - "Right-Click here to get a setup item for the arena." - "" - - "&7You can set the arenas icon by using the" - - "&7&l/arena set icon %arenaName% &7command." + - "You can set the arenas icon by using the" + - "/arena set icon %arenaName% command." - "" - - "&c&lNote: &7You have to hold the item in your hand" - - "&7and name it first with the &7&l/prac rename &7command." + - "Note: You have to hold the item in your hand" + - "and name it first with the /prac rename command." SETTINGS: - NAME: "&5Settings" + NAME: "Settings" MATERIAL: REDSTONE LORE: - "" - - "&e&lClick here &7to open the settings gui." + - "Click here to open the settings gui." - "" - - "&c&lNote: &7You can change the build setting," - - "&7re-kit after kill, health reset on kill" - - "&7and the lobby after death setting." + - "Note: You can change the build setting," + - "re-kit after kill, health reset on kill" + - "and the lobby after death setting." STATUS: ENABLED: - NAME: "&7Status: &aEnabled" + NAME: "Status: Enabled" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &cdisable &7the arena." + - "Click here to disable the arena." - "" - - "&c&lNote: &7This will remove all the" - - "&7players from the arena." + - "Note: This will remove all the" + - "players from the arena." DISABLED: - NAME: "&7Status: &cDisabled" + NAME: "Status: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &aenable &7the arena." + - "Click here to enable the arena." - "" - - "&c&lNote: &7The arena has to meet some" - - "&7requirements to be enable:" - - " &8» &eMark all the corners." - - " &8» &eAdd spawn positions." - - " &8» &eSet an icon." + - "Note: The arena has to meet some" + - "requirements to be enable:" + - " » Mark all the corners." + - " » Add spawn positions." + - " » Set an icon." LOCATION: - NAME: "&5Locations" + NAME: "Locations" MATERIAL: COMPASS LORE: - "" - - "&5&lCurrently Marked:" - - " &5» &dCorner 1: &7%corner1%" - - " &5» &dCorner 2: &7%corner2%" + - "Currently Marked:" + - " » Corner 1: %corner1%" + - " » Corner 2: %corner2%" - "" - - " &5» &dSpawn Positions: &7%ffa_pos_num%" + - " » Spawn Positions: %ffa_pos_num%" LADDER: - NAME: "&cLadder Types" + NAME: "Ladder Types" MATERIAL: GOLDEN_SWORD LORE: - "" - - "&e&lClick here &7to open the ladder assign gui." + - "Click here to open the ladder assign gui." - "" - - "&c&lNote: &7You can only assign basic or build" - - "&7ladders to your FFA arena depending on the arenas" - - "&7build setting." + - "Note: You can only assign basic or build" + - "ladders to your FFA arena depending on the arenas" + - "build setting." - "" - - "&c&lNote: &7You have to assign at least" - - "&7one ladder before enabling." + - "Note: You have to assign at least" + - "one ladder before enabling." OPEN-STATUS: OPEN: - NAME: "&7The &eFFA &7is currently &aopen" + NAME: "The FFA is currently open" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&7This means that players can join" - - "&7and play in the arena." + - "This means that players can join" + - "and play in the arena." - "" - - "&e&lClick here &7to &cCLOSE &7the arena." + - "Click here to CLOSE the arena." - "" - - "&c&lNote: &7This will remove all the" - - "&7players from the arena." + - "Note: This will remove all the" + - "players from the arena." CLOSE: - NAME: "&7The &eFFA &7is currently &cclosed" + NAME: "The FFA is currently closed" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &aOPEN &7the arena." + - "Click here to OPEN the arena." - "" - - "&c&lNote: &7The arena has to be enabled." + - "Note: The arena has to be enabled." SETTINGS: - TITLE: "&4%arenaName% &8- Settings" + TITLE: "%arenaName% - Settings" ICONS: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW FILLER: MATERIAL: BLACK_STAINED_GLASS_PANE BUILD: ENABLED: - NAME: "&7Build: &aEnabled" + NAME: "Build: Enabled" MATERIAL: IRON_PICKAXE LORE: - "" - - "&e&lClick here &7to &cdisable &7the" - - "&2building &7in the arena." + - "Click here to disable the" + - "building in the arena." - "" - - "&c&lNote: &7This will remove all the" - - "&7assigned ladders from the arena." + - "Note: This will remove all the" + - "assigned ladders from the arena." DISABLED: - NAME: "&7Build: &cDisabled" + NAME: "Build: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &aenable &7the" - - "&2building &7in the arena." + - "Click here to enable the" + - "building in the arena." - "" - - "&c&lNote: &7This will remove all the" - - "&7assigned ladders from the arena." + - "Note: This will remove all the" + - "assigned ladders from the arena." RE-KIT-AFTER-KILL: ENABLED: - NAME: "&7Re-Kit After Kill: &aEnabled" + NAME: "Re-Kit After Kill: Enabled" MATERIAL: DIAMOND_SWORD LORE: - "" - - "&eAfter a player kills somebody" - - "ðey get a new kit." + - "After a player kills somebody" + - "they get a new kit." - "" - - "&e&lClick here &7to &cdisable &7the" - - "&2re-kit after kill &7in the arena." + - "Click here to disable the" + - "re-kit after kill in the arena." DISABLED: - NAME: "&7Re-Kit After Kill: &cDisabled" + NAME: "Re-Kit After Kill: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&eAfter a player kills somebody" - - "ðey get a new kit." + - "After a player kills somebody" + - "they get a new kit." - "" - - "&e&lClick here &7to &aenable &7the" - - "&2re-kit after kill &7in the arena." + - "Click here to enable the" + - "re-kit after kill in the arena." HEALTH-RESET-ON-KILL: ENABLED: - NAME: "&7Health Reset On Kill: &aEnabled" + NAME: "Health Reset On Kill: Enabled" MATERIAL: GOLDEN_APPLE LORE: - "" - - "&eAfter a player kills somebody" - - "ðey are fully healed." + - "After a player kills somebody" + - "they are fully healed." - "" - - "&e&lClick here &7to &cdisable &7the" - - "&2health reset on kill &7in the arena." + - "Click here to disable the" + - "health reset on kill in the arena." DISABLED: - NAME: "&7Health Reset On Kill: &cDisabled" + NAME: "Health Reset On Kill: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&eAfter a player kills somebody" - - "ðey are fully healed." + - "After a player kills somebody" + - "they are fully healed." - "" - - "&e&lClick here &7to &aenable &7the" - - "&2health reset on kill &7in the arena." + - "Click here to enable the" + - "health reset on kill in the arena." HEALTH-BELOW-NAME: ENABLED: - NAME: "&7Health Below Name: &aEnabled" + NAME: "Health Below Name: Enabled" MATERIAL: PLAYER_HEAD LORE: - "" - - "&eShows players' health under" - - "ðeir name tags in this FFA." + - "Shows players' health under" + - "their name tags in this FFA." - "" - - "&e&lClick here &7to &cdisable &7this setting." + - "Click here to disable this setting." DISABLED: - NAME: "&7Health Below Name: &cDisabled" + NAME: "Health Below Name: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&eShows players' health under" - - "ðeir name tags in this FFA." + - "Shows players' health under" + - "their name tags in this FFA." - "" - - "&e&lClick here &7to &aenable &7this setting." + - "Click here to enable this setting." LOBBY-AFTER-DEATH: ENABLED: - NAME: "&7Lobby After Death: &aEnabled" + NAME: "Lobby After Death: Enabled" MATERIAL: DIAMOND_SWORD LORE: - "" - - "&eAfter a player dies they get" - - "&eteleported back to the arena." + - "After a player dies they get" + - "teleported back to the arena." - "" - - "&e&lClick here &7to &cdisable &7the" - - "&2lobby after death &7setting in the arena." + - "Click here to disable the" + - "lobby after death setting in the arena." DISABLED: - NAME: "&7Lobby After Death: &cDisabled" + NAME: "Lobby After Death: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&eAfter a player dies they get" - - "&eteleported back to the arena." + - "After a player dies they get" + - "teleported back to the arena." - "" - - "&e&lClick here &7to &aenable &7the" - - "&2lobby after death &7setting in the arena." + - "Click here to enable the" + - "lobby after death setting in the arena." ARENA-LADDERS-SINGLE: - TITLE: "&4%arenaName% &8- Ladders" + TITLE: "%arenaName% - Ladders" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW LADDER-ICONS: ASSIGNED: - NAME: "&a%ladderDisplayName%" + NAME: "%ladderDisplayName%" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder is &aassigned&7 for the arena." + - "This ladder is assigned for the arena." - "" - - "&eClick here &7to &cunassign&7." + - "Click here to unassign." NOT-ASSIGNED: - NAME: "&c%ladderDisplayName%" + NAME: "%ladderDisplayName%" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder is &cunassigned&7 for the arena." + - "This ladder is unassigned for the arena." - "" - - "&eClick here &7to &aassign&7." + - "Click here to assign." DISABLED: - NAME: "&7%ladderDisplayName%" + NAME: "%ladderDisplayName%" MATERIAL: GRAY_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder or it's ladder type" - - "&7is currently &cdisabled&7." + - "This ladder or it's ladder type" + - "is currently disabled." ARENA: ARENA-MANAGER: - TITLE: "&8Arena Manager - Page %page%" + TITLE: "Arena Manager - Page %page%" ICONS: PAGE-LEFT: - NAME: "&6Go to Page %page%" + NAME: "Go to Page %page%" MATERIAL: ARROW BACK-TO: - NAME: "&cBack to Server Manager" + NAME: "Back to Server Manager" MATERIAL: ARROW PAGE-RIGHT: - NAME: "&6Go to Page %page%" + NAME: "Go to Page %page%" MATERIAL: ARROW ARENA-ICON: STATUS-NAMES: - ENABLED: "&aEnabled" - DISABLED: "&cDisabled" + ENABLED: "Enabled" + DISABLED: "Disabled" BUILD: - NAME: "&6%arenaName%" + NAME: "%arenaName%" MATERIAL: BEDROCK LORE: - "" - - "&6Arena Information:" - - " &7» &eType: &b%type%" - - " &7» &eState: &b%state%" - - " &7» &eCopies: &7%copies%/64" - - " &7» &eLadders: &7%assigned_ladders%/%assignable_ladders%" + - "Arena Information:" + - " » Type: %type%" + - " » State: %state%" + - " » Copies: %copies%/64" + - " » Ladders: %assigned_ladders%/%assignable_ladders%" - "" - - "&a&lLeft-Click &ato open arena settings." - - "&b&lRight-Click &bto to teleport to arena." + - "Left-Click to open arena settings." + - "Right-Click to to teleport to arena." NON-BUILD: - NAME: "&6%arenaName%" + NAME: "%arenaName%" MATERIAL: BEDROCK LORE: - "" - - "&6Arena Information:" - - " &7» &eType: &b%type%" - - " &7» &eState: &b%state%" - - " &7» &eLadders: &7%assigned_ladders%/%assignable_ladders%" + - "Arena Information:" + - " » Type: %type%" + - " » State: %state%" + - " » Ladders: %assigned_ladders%/%assignable_ladders%" - "" - - "&a&lLeft-Click &ato open arena settings." - - "&b&lRight-Click &bto to teleport to arena." + - "Left-Click to open arena settings." + - "Right-Click to to teleport to arena." FFA: - NAME: "&6%arenaName%" + NAME: "%arenaName%" MATERIAL: BEDROCK LORE: - "" - - "&6Arena Information:" - - " &7» &eType: &bFFA" - - " &7» &eState: &b%state%" - - " &7» &eBuild: &b%build%" + - "Arena Information:" + - " » Type: FFA" + - " » State: %state%" + - " » Build: %build%" - "" - - "&a&lLeft-Click &ato open arena settings." - - "&b&lRight-Click &bto to teleport to arena." + - "Left-Click to open arena settings." + - "Right-Click to to teleport to arena." ARENA-MAIN: - TITLE: "&4%arenaName% &8- Arena" + TITLE: "%arenaName% - Arena" ICONS: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW DELETE: - NAME: "&cDelete Arena" + NAME: "Delete Arena" MATERIAL: RED_DYE ARENA-NAME: - NAME: "&6%arenaDisplayName%" + NAME: "%arenaDisplayName%" MATERIAL: BEDROCK LORE: - "" - - "&eArena Type: &b%arenaType%" + - "Arena Type: %arenaType%" - "" - - "&e&lLeft-Click here &7to get detailed information." - - "&6&lRight-Click here &7to get a setup item for the arena." + - "Left-Click here to get detailed information." + - "Right-Click here to get a setup item for the arena." - "" - - "&7You can set the arenas icon by using the" - - "&7&l/arena set icon %arenaName% &7command." + - "You can set the arenas icon by using the" + - "/arena set icon %arenaName% command." - "" - - "&c&lNote: &7You have to hold the item in your hand" - - "&7and name it first with the &7&l/prac rename &7command." + - "Note: You have to hold the item in your hand" + - "and name it first with the /prac rename command." STATUS: ENABLED: - NAME: "&7Status: &aEnabled" + NAME: "Status: Enabled" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &cdisable &7the arena." + - "Click here to disable the arena." DISABLED: - NAME: "&7Status: &cDisabled" + NAME: "Status: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &aenable &7the arena." + - "Click here to enable the arena." - "" - - "&c&lNote: &7The arena has to meet some" - - "&7requirements to be enable:" - - " &8» &eMark all the corners." - - " &8» &eSet all the positions." - - " &8» &eSet an icon." + - "Note: The arena has to meet some" + - "requirements to be enable:" + - " » Mark all the corners." + - " » Set all the positions." + - " » Set an icon." LOCATION: BUILD: - NAME: "&5Locations" + NAME: "Locations" MATERIAL: COMPASS LORE: - "" - - "&5&lCurrently Marked:" - - " &5» &dCorner 1: &7%corner1%" - - " &5» &dCorner 2: &7%corner2%" + - "Currently Marked:" + - " » Corner 1: %corner1%" + - " » Corner 2: %corner2%" - "" - - " &5» &dSide Build Limit: &7%sideBuildLimit%" - - " &5» &dBuild Max Y: &7%buildMaxY%" - - " &5» &dDeath Zone Y: &7%deathZoneY%" + - " » Side Build Limit: %sideBuildLimit%" + - " » Build Max Y: %buildMaxY%" + - " » Death Zone Y: %deathZoneY%" - "" - - " &5» &dPlayer 1 Position: &7%position1%" - - " &5» &dPlayer 2 Position: &7%position2%" + - " » Player 1 Position: %position1%" + - " » Player 2 Position: %position2%" - "" - - " &5» &dBed 1: &7%bed1%" - - " &5» &dBed 2: &7%bed2%" - - " &5» &dPortal 1: &7%portal1%" - - " &5» &dPortal 2: &7%portal2%" + - " » Bed 1: %bed1%" + - " » Bed 2: %bed2%" + - " » Portal 1: %portal1%" + - " » Portal 2: %portal2%" NOT-BUILD: - NAME: "&5Locations" + NAME: "Locations" MATERIAL: COMPASS LORE: - "" - - "&5&lCurrently Marked:" - - " &5» &dCorner 1: &7%corner1%" - - " &5» &dCorner 2: &7%corner2%" + - "Currently Marked:" + - " » Corner 1: %corner1%" + - " » Corner 2: %corner2%" - "" - - " &5» &dDeath Zone Y: &7%deathZoneY%" + - " » Death Zone Y: %deathZoneY%" - "" - - " &5» &dPlayer 1 Position: &7%position1%" - - " &5» &dPlayer 2 Position: &7%position2%" + - " » Player 1 Position: %position1%" + - " » Player 2 Position: %position2%" LADDER: - NAME: "&cLadder Types" + NAME: "Ladder Types" MATERIAL: GOLDEN_SWORD LORE: - "" - - "&e&lClick here &7to open the ladder type setup gui." + - "Click here to open the ladder type setup gui." - "" - - "&c&lNote: &7You won't be able to enable" - - "&7non-build ladders for build arenas and vice versa." + - "Note: You won't be able to enable" + - "non-build ladders for build arenas and vice versa." - "" - - "&c&lNote: &7You have to add at least" - - "&7one ladder before enabling." + - "Note: You have to add at least" + - "one ladder before enabling." COPIES: - NAME: "&eArena Copies" + NAME: "Arena Copies" MATERIAL: HOPPER LORE: - "" - - "&e&lClick here &7to complete the following" - - "&7tasks with the arena copies:" - - " &8» &7Create" - - " &8» &7Delete" - - " &8» &7Look through" - - " &8» &7Teleport" + - "Click here to complete the following" + - "tasks with the arena copies:" + - " » Create" + - " » Delete" + - " » Look through" + - " » Teleport" FREEZE: FROZEN: - NAME: "&eThe arena is &bfrozen&e." + NAME: "The arena is frozen." MATERIAL: SNOWBALL LORE: - "" - - "&7Click here to &adefrost&7." + - "Click here to defrost." - "" - - "&7The players will be able to" - - "&7play in this arena again." + - "The players will be able to" + - "play in this arena again." NOT-FROZEN: - NAME: "&eThe arena is &anot frozen&e." + NAME: "The arena is not frozen." MATERIAL: SUNFLOWER LORE: - "" - - "&eClick here to &bfreeze &eit." + - "Click here to freeze it." - "" - - "&7This means that the players won't be" - - "&7able to start a new match in this arena." + - "This means that the players won't be" + - "able to start a new match in this arena." ARENA-COPY: - TITLE: "&4%arenaName% &8- Copies, Page %page%" + TITLE: "%arenaName% - Copies, Page %page%" ICONS: NAV-MAIN: - NAME: "&c%arenaDisplayName% &7Arena Copies Manager" + NAME: "%arenaDisplayName% Arena Copies Manager" MATERIAL: REDSTONE LORE: - "" - - "&7Copies: &e%copies%&7/64" + - "Copies: %copies%/64" - "" - - "&cNote: &7You can't change anything in the" - - "&7copies, nor the arena, if it has copies." + - "Note: You can't change anything in the" + - "copies, nor the arena, if it has copies." COPY-ARENA: - NAME: "&c%arenaDisplayName% &7(&e%copyNumber%&7)" + NAME: "%arenaDisplayName% (%copyNumber%)" MATERIAL: HOPPER LORE: - "" - - "&e&lClick here &7to teleport to the copy arena." + - "Click here to teleport to the copy arena." PAGE-LEFT: - NAME: "&6Go to Page %page%" + NAME: "Go to Page %page%" MATERIAL: ARROW BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW PAGE-RIGHT: - NAME: "&6Go to Page %page%" + NAME: "Go to Page %page%" MATERIAL: ARROW DELETE: - NAME: "&eClick here to &cdelete ðe &6last &ecopy." + NAME: "Click here to delete the last copy." MATERIAL: ARROW GENERATE: - NAME: "&eClick here to &agenerate &ea &6new &ecopy." + NAME: "Click here to generate a new copy." MATERIAL: ARROW ARENA-LADDERS-TYPE: - TITLE: "&4%arenaName% &8- Ladders" + TITLE: "%arenaName% - Ladders" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW GO-TO-LADDERS: - NAME: "&cLadders" + NAME: "Ladders" MATERIAL: GOLDEN_CARROT LORE: - "" - - "&e&lClick here &7to open the ladder setup gui." + - "Click here to open the ladder setup gui." - "" - - "&c&lNote: &7The plugin automatically assign" - - "&7every ladder of which type is enabled." + - "Note: The plugin automatically assign" + - "every ladder of which type is enabled." LADDER-TYPE-ICONS: ENABLED: - NAME: "&a%ladderTypeName%" + NAME: "%ladderTypeName%" LORE: - "" - - "&7Ladder type is &aenabled&7." + - "Ladder type is enabled." - "" - - "&eClick here &7to &cdisable &7it." + - "Click here to disable it." DISABLED: - NAME: "&c%ladderTypeName%" + NAME: "%ladderTypeName%" LORE: - "" - - "&7Ladder type is &cdisabled&7." + - "Ladder type is disabled." - "" - - "&eClick here &7to &aenable &7it." + - "Click here to enable it." CUSTOM-KIT-ICONS: ICON: - NAME: "&eCustom Kit: %status%" + NAME: "Custom Kit: %status%" MATERIAL: ARROW LORE: - "" - - "&7This setting decides if the players" - - "&7can use their custom kits in this arena." + - "This setting decides if the players" + - "can use their custom kits in this arena." ARENA-LADDERS-SINGLE: - TITLE: "&4%arenaName% &8- Ladders" + TITLE: "%arenaName% - Ladders" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW LADDER-ICONS: ASSIGNED: - NAME: "&a%ladderDisplayName%" + NAME: "%ladderDisplayName%" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder is &aassigned&7 for the arena." + - "This ladder is assigned for the arena." - "" - - "&eClick here &7to &cunassign&7." + - "Click here to unassign." NOT-ASSIGNED: - NAME: "&c%ladderDisplayName%" + NAME: "%ladderDisplayName%" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder is &cunassigned&7 for the arena." + - "This ladder is unassigned for the arena." - "" - - "&eClick here &7to &aassign&7." + - "Click here to assign." DISABLED: - NAME: "&7%ladderDisplayName%" + NAME: "%ladderDisplayName%" MATERIAL: GRAY_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder or it's ladder type" - - "&7is currently &cdisabled&7." + - "This ladder or it's ladder type" + - "is currently disabled." NOT-COMPATIBLE: - NAME: "&7%ladderDisplayName%" + NAME: "%ladderDisplayName%" MATERIAL: GRAY_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder is &cnot compatible" - - "&7with the arena because of the" - - "&7build status." + - "This ladder is not compatible" + - "with the arena because of the" + - "build status." LADDER: LADDER-MANAGER: - TITLE: "&8Ladder Manager" + TITLE: "Ladder Manager" ICONS: + PAGE-LEFT: + NAME: "Go to Page %page%" + MATERIAL: ARROW BACK-TO: - NAME: "&cBack to Server Manager" + NAME: "Back to Server Manager" + MATERIAL: ARROW + PAGE-RIGHT: + NAME: "Go to Page %page%" MATERIAL: ARROW LADDER-ICON: STATUS-NAMES: - ENABLED: "&aEnabled" - DISABLED: "&cDisabled" - NAME: "&6%ladder%" + ENABLED: "Enabled" + DISABLED: "Disabled" + NAME: "%ladder%" MATERIAL: BEDROCK LORE: - "" - - "&6Ladder Information:" - - " &7» &eType: &b%type%" - - " &7» &eState: %ladderState%" - - " &7» &eRanked: %rankedState%" - - " &7» &eFreeze: %freezeState%" + - "Ladder Information:" + - " » Type: %type%" + - " » State: %ladderState%" + - " » Ranked: %rankedState%" + - " » Freeze: %freezeState%" - "" - - "&b&lClick here &bto open ladder settings." + - "Click here to open ladder settings." LADDER-MAIN: - TITLE: "&1%ladder% &8- Ladder" + TITLE: "%ladder% - Ladder" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW LADDER-NAME: - NAME: "&6%ladder%" + NAME: "%ladder%" MATERIAL: BEDROCK LORE: - "" - - "&eLadder Type: &b%type%" + - "Ladder Type: %type%" - "" - - "&7You can set the ladders icon by using the" - - "&7&l/ladder set icon %ladder% &7command." + - "You can set the ladders icon by using the" + - "/ladder set icon %ladder% command." - "" - - "&b&lNote: &7You have to hold the item in your hand and" - - "&7you have to name it first with the &l/prac rename &7command." + - "Note: You have to hold the item in your hand and" + - "you have to name it first with the /prac rename command." STATUS: ENABLED: - NAME: "&7Status: &aEnabled" + NAME: "Status: Enabled" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &cdisable &7the ladder." + - "Click here to disable the ladder." - "" - - "&c&lNote: &cThis will delete all the players" - - "&ccustom kits with this ladder." - - "&c&lYou won't be able to reverse this action." + - "Note: This will delete all the players" + - "custom kits with this ladder." + - "You won't be able to reverse this action." DISABLED: - NAME: "&7Status: &cDisabled" + NAME: "Status: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &aenable &7the ladder." + - "Click here to enable the ladder." - "" - - "&c&lNote: &7The ladder has to meet some" - - "&7requirements to be enable:" - - " &8» &eSet an icon." - - " &8» &eSet the inventory." + - "Note: The ladder has to meet some" + - "requirements to be enable:" + - " » Set an icon." + - " » Set the inventory." FREEZE: FROZEN: - NAME: "&eThe ladder is &bfrozen&e." + NAME: "The ladder is frozen." MATERIAL: SNOWBALL LORE: - "" - - "&7Click here to &adefrost&7." + - "Click here to defrost." - "" - - "&7The players will be able to edit" - - "&7and play with this ladder again." + - "The players will be able to edit" + - "and play with this ladder again." NOT-FROZEN: - NAME: "&eThe ladder is &anot frozen&e." + NAME: "The ladder is not frozen." MATERIAL: SUNFLOWER LORE: - "" - - "&eClick here to &bfreeze &eit." + - "Click here to freeze it." - "" - - "&7This means that the players" - - "&7won't be able to start a new match" - - "&7and edit this ladder." + - "This means that the players" + - "won't be able to start a new match" + - "and edit this ladder." INVENTORY: - NAME: "&3Inventory & Armor" + NAME: "Inventory & Armor" MATERIAL: DIAMOND_CHESTPLATE LORE: - "" - - "&b&lClick here &7to edit the inventory" - - "&7and armor content of the ladder." - - "&7You can also view the added effects as well." + - "Click here to edit the inventory" + - "and armor content of the ladder." + - "You can also view the added effects as well." DESTROYABLE-BLOCKS: - NAME: "&cDestroyable Blocks" + NAME: "Destroyable Blocks" MATERIAL: END_STONE LORE: - "" - - "&c&lClick here &7to edit the blocks" - - "&7that can be destroyed during the game" - - "&7and are already placed in the arena." + - "Click here to edit the blocks" + - "that can be destroyed during the game" + - "and are already placed in the arena." SETTINGS: - NAME: "&4Settings" + NAME: "Settings" MATERIAL: REDSTONE LORE: - "" - - "&e&lClick here &7to adjust the ladders" - - "&7other settings, such as:" - - " &8» &cRounds" - - " &8» &cRanked" - - " &8» &cPlayer Regeneration" - - " &8» &cPlayer Hunger" - - " &cetc..." + - "Click here to adjust the ladders" + - "other settings, such as:" + - " » Rounds" + - " » Ranked" + - " » Player Regeneration" + - " » Player Hunger" + - " etc..." MATCH-TYPE: - NAME: "&6Match Types" + NAME: "Match Types" MATERIAL: BOOK LORE: - "" - - "&6&lClick here &7to set which" - - "&7match types should be available" - - "&7for the ladder." + - "Click here to set which" + - "match types should be available" + - "for the ladder." DELETE: - NAME: "&cDelete Ladder" + NAME: "Delete Ladder" MATERIAL: RED_DYE SETTINGS: - TITLE: "&1%ladder% &8- Settings" + TITLE: "%ladder% - Settings" ICONS: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW REGENERATION: ENABLED: - NAME: "&7Regeneration: &aEnabled" + NAME: "Regeneration: Enabled" MATERIAL: GLOWSTONE_DUST LORE: - "" - - "&7Players health is automatically regenerate (normally)." + - "Players health is automatically regenerate (normally)." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Regeneration: &cDisabled" + NAME: "Regeneration: Disabled" MATERIAL: GLOWSTONE_DUST LORE: - "" - - "&7Players health is not regenerate." + - "Players health is not regenerate." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." HUNGER: ENABLED: - NAME: "&7Hunger: &aEnabled" + NAME: "Hunger: Enabled" MATERIAL: COOKED_BEEF LORE: - "" - - "&7Players starve during the game." + - "Players starve during the game." - "" - - "&e&lClick here &7to &cdisable &7." + - "Click here to disable ." DISABLED: - NAME: "&7Hunger: &cDisabled" + NAME: "Hunger: Disabled" MATERIAL: COOKED_BEEF LORE: - "" - - "&7Players don't starve." + - "Players don't starve." - "" - - "&e&lClick here &7to &aenable &7." + - "Click here to enable ." ROUNDS: - NAME: "&7Rounds: &6%rounds%" + NAME: "Rounds: %rounds%" MATERIAL: FIREWORK_STAR LORE: - "" - - "&7The first player/team to reach" - - "&7the, winning rounds wins." + - "The first player/team to reach" + - "the, winning rounds wins." + - "" + - "LEFT-CLICK to reduce the rounds." + - "RIGHT-CLICK to increase the rounds." + HEARTS: + NAME: "Hearts: %hearts%" + MATERIAL: RED_DYE + LORE: + - "" + - "Sets the maximum hearts players" + - "can have in this ladder." - "" - - "&a&lLEFT-CLICK &ato reduce the rounds." - - "&b&lRIGHT-CLICK &bto increase the rounds." + - "LEFT-CLICK to reduce hearts." + - "RIGHT-CLICK to increase hearts." KNOCKBACK: - NAME: "&eKnockback Modifier" + NAME: "Knockback Modifier" MATERIAL: STICK LORE: - "" - "%knockbackTypes%" - "" - - "&c&lNote: &7Default won't change the knockback." - - "&7You can change the normal and combo knockbacks" - - "&7in the config file." + - "Note: Default won't change the knockback." + - "You can change the normal and combo knockbacks" + - "in the config file." ATTACKCOOLDOWN: - NAME: "&7Attack Cooldown: &6%attackcooldown%x" + NAME: "Attack Cooldown: %attackcooldown%x" MATERIAL: DIAMOND_SWORD LORE: - "" - - "&7Adjust the speed at which the" - - "&7attack strength bar recharges." + - "Adjust the speed at which the" + - "attack strength bar recharges." - "" - - "&eCurrent Multiplier: &f%attackcooldown%x" - - "&7(Lower = Faster swinging)" + - "Current Multiplier: %attackcooldown%x" + - "(Lower = Faster swinging)" - "" - - "&a&lLEFT-CLICK &7to decrease by &c0.1" - - "&b&lRIGHT-CLICK &7to increase by &b0.1" + - "LEFT-CLICK to decrease by 0.1" + - "RIGHT-CLICK to increase by 0.1" MAX-DURATION: - NAME: "&7Max Duration: &6%maxDuration% sec" + NAME: "Max Duration: %maxDuration% sec" MATERIAL: CLOCK LORE: - "" - - "&7The maximum time the match can last." + - "The maximum time the match can last." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." TNT-FUSE-TIME: - NAME: "&7TNT Fuse Time: &6%tntFuseTime% sec" + NAME: "TNT Fuse Time: %tntFuseTime% sec" MATERIAL: TNT LORE: - "" - - "&7The time until the tnt explodes." + - "The time until the tnt explodes." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." EDITABLE: ENABLED: - NAME: "&7Editable: &aEnabled" + NAME: "Editable: Enabled" MATERIAL: BOOK LORE: - "" - - "&7Players can customize the ladder." + - "Players can customize the ladder." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Editable: &cDisabled" + NAME: "Editable: Disabled" MATERIAL: BOOK LORE: - "" - - "&7Players can't customize the ladder." + - "Players can't customize the ladder." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." WEIGHT-CLASS: - NAME: "&eWeight Class Selector" + NAME: "Weight Class Selector" MATERIAL: SUNFLOWER LORE: - "" - "%weightClassTypes%" START-COUNTDOWN: - NAME: "&7Start Countdown: &6%startCountdown%" + NAME: "Start Countdown: %startCountdown%" MATERIAL: CLOCK LORE: - "" - - "&7When the match/round starts the server" - - "&7counts down this amount of time." + - "When the match/round starts the server" + - "counts down this amount of time." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." START-MOVING: ENABLED: - NAME: "&7Start moving: &aEnabled" + NAME: "Start moving: Enabled" MATERIAL: DIRT LORE: - "" - - "&7Players can move during" - - "&7round start countdown." + - "Players can move during" + - "round start countdown." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Start moving: &cDisabled" + NAME: "Start moving: Disabled" MATERIAL: DIRT LORE: - "" - - "&7Players can't move during" - - "&7round start countdown." + - "Players can't move during" + - "round start countdown." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." HEALTH-BELOW-NAME: ENABLED: - NAME: "&7Health Below Name: &aEnabled" + NAME: "Health Below Name: Enabled" MATERIAL: RED_DYE LORE: - "" - - "&7Players will display their hearts" - - "&7during the match." + - "Players will display their hearts" + - "during the match." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Health Below Name: &cDisabled" + NAME: "Health Below Name: Disabled" MATERIAL: RED_DYE LORE: - "" - - "&7Players will display their hearts" - - "&7during the match." + - "Players will display their hearts" + - "during the match." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." RESET-BUILD-AFTER-ROUND: ENABLED: - NAME: "&7Reset Build After Round: &aEnabled" + NAME: "Reset Build After Round: Enabled" MATERIAL: GRASS_BLOCK LORE: - "" - - "&7The arena will be reset after each" - - "&7round, before the next one starts." + - "The arena will be reset after each" + - "round, before the next one starts." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Reset Build After Round: &cDisabled" + NAME: "Reset Build After Round: Disabled" MATERIAL: GRASS_BLOCK LORE: - "" - - "&7The arena will not be reset between" - - "&7rounds. Placed blocks persist." + - "The arena will not be reset between" + - "rounds. Placed blocks persist." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." BREAK-ALL-BLOCKS: ENABLED: - NAME: "&7Break All Blocks: &aEnabled" + NAME: "Break All Blocks: Enabled" MATERIAL: DIAMOND_PICKAXE LORE: - "" - - "&7Players can break any block in the arena," - - "&7not just blocks they placed themselves." + - "Players can break any block in the arena," + - "not just blocks they placed themselves." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Break All Blocks: &cDisabled" + NAME: "Break All Blocks: Disabled" MATERIAL: WOODEN_PICKAXE LORE: - "" - - "&7Players can only break blocks they" - - "&7placed during the match." + - "Players can only break blocks they" + - "placed during the match." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." FIREBALL-BLOCK-DESTROY: ENABLED: - NAME: "&7Fireball Block Destroy: &aEnabled" + NAME: "Fireball Block Destroy: Enabled" MATERIAL: FIRE_CHARGE LORE: - "" - - "&7Fireball explosions will destroy" - - "&7blocks placed by players." - - "&8(Arena blocks are not affected)" + - "Fireball explosions will destroy" + - "blocks placed by players." + - "(Arena blocks are not affected)" - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Fireball Block Destroy: &cDisabled" + NAME: "Fireball Block Destroy: Disabled" MATERIAL: FIRE_CHARGE LORE: - "" - - "&7Fireball explosions will not" - - "&7destroy any blocks." + - "Fireball explosions will not" + - "destroy any blocks." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." SPLEEF-SNOWBALL-MODE: ENABLED: - NAME: "&7Snowball Mode: &aEnabled" + NAME: "Snowball Mode: Enabled" MATERIAL: SNOWBALL LORE: - "" - - "&7Breaking a snow block gives a snowball." - - "&7Throw snowballs to destroy snow blocks" - - "&7beneath other players." + - "Breaking a snow block gives a snowball." + - "Throw snowballs to destroy snow blocks" + - "beneath other players." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Snowball Mode: &cDisabled" + NAME: "Snowball Mode: Disabled" MATERIAL: SNOWBALL LORE: - "" - - "&7Enable to let players collect and throw" - - "&7snowballs that destroy snow blocks." + - "Enable to let players collect and throw" + - "snowballs that destroy snow blocks." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." ENDERPEARL-COOLDOWN: - NAME: "&7EnderPearl Cooldown: &6%epCooldown% sec" + NAME: "EnderPearl Cooldown: %epCooldown% sec" MATERIAL: ENDER_PEARL LORE: - "" - - "&7Players must wait this long before" - - "&7they can throw the next enderpearl." + - "Players must wait this long before" + - "they can throw the next enderpearl." - "" - - "&a&lLEFT-CLICK &ato reduce the cooldown." - - "&b&lRIGHT-CLICK &bto increase the cooldown." + - "LEFT-CLICK to reduce the cooldown." + - "RIGHT-CLICK to increase the cooldown." GOLDENAPPLE-COOLDOWN: - NAME: "&7Golden Apple Cooldown: &6%golden_apple_cooldown%" + NAME: "Golden Apple Cooldown: %golden_apple_cooldown%" MATERIAL: GOLDEN_APPLE LORE: - "" - - "&7Players must wait this long before" - - "&7they can consume the next golden apple." + - "Players must wait this long before" + - "they can consume the next golden apple." - "" - - "&7This setting includes both enchanted" - - "&7and non-enchanted golden apples." + - "This setting includes both enchanted" + - "and non-enchanted golden apples." - "" - - "&a&lLEFT-CLICK &ato reduce the cooldown." - - "&b&lRIGHT-CLICK &bto increase the cooldown." + - "LEFT-CLICK to reduce the cooldown." + - "RIGHT-CLICK to increase the cooldown." WIND-CHARGE-COOLDOWN: - NAME: "&7Wind Charge Cooldown: &6%windChargeCooldown% sec" + NAME: "Wind Charge Cooldown: %windChargeCooldown% sec" MATERIAL: WIND_CHARGE LORE: - "" - - "&7Players must wait this long before" - - "&7they can launch the next wind charge." + - "Players must wait this long before" + - "they can launch the next wind charge." - "" - - "&a&lLEFT-CLICK &ato reduce the cooldown." - - "&b&lRIGHT-CLICK &bto increase the cooldown." + - "LEFT-CLICK to reduce the cooldown." + - "RIGHT-CLICK to increase the cooldown." DROP-INVENTORY-PARTY-GAMES: ENABLED: - NAME: "&7Drop Inventory: &aEnabled" + NAME: "Drop Inventory: Enabled" MATERIAL: GHAST_TEAR LORE: - "" - - "&7When several players are playing a" - - "&7party match and someone dies, should" - - "&7the inventory be dropped out or not." + - "When several players are playing a" + - "party match and someone dies, should" + - "the inventory be dropped out or not." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Drop Inventory: &cDisabled" + NAME: "Drop Inventory: Disabled" MATERIAL: GHAST_TEAR LORE: - "" - - "&7When several players are playing a" - - "&7party match and someone dies, should" - - "&7the inventory be dropped out or not." + - "When several players are playing a" + - "party match and someone dies, should" + - "the inventory be dropped out or not." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." MULTI-ROUND-START-COUNTDOWN: ENABLED: - NAME: "&7Multi Round Start Countdown: &aEnabled" + NAME: "Multi Round Start Countdown: Enabled" MATERIAL: NETHER_WART LORE: - "" - - "&7If a ladder has several rounds," - - "&7you have the option to turn off" - - "&7the start counter before the" - - "&7round with this setting." + - "If a ladder has several rounds," + - "you have the option to turn off" + - "the start counter before the" + - "round with this setting." - "" - - "&c&lNote: &7At the start of the match," - - "&7the counter will work the same way." + - "Note: At the start of the match," + - "the counter will work the same way." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Multi Round Start Countdown: &cDisabled" + NAME: "Multi Round Start Countdown: Disabled" MATERIAL: NETHER_WART LORE: - "" - - "&7If a ladder has several rounds," - - "&7you have the option to turn off" - - "&7the start counter before the" - - "&7round with this setting." + - "If a ladder has several rounds," + - "you have the option to turn off" + - "the start counter before the" + - "round with this setting." - "" - - "&c&lNote: &7At the start of the match," - - "&7the counter will work the same way." + - "Note: At the start of the match," + - "the counter will work the same way." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." SKYWARS: - NAME: "&6SkyWars Chest Loot" + NAME: "SkyWars Chest Loot" MATERIAL: CHEST LORE: - "" - - "&e&lClick here &7to edit the" - - "&7loot which the players get when" - - "&7they open chests during the game." + - "Click here to edit the" + - "loot which the players get when" + - "they open chests during the game." BLOCK-RETURN-DELAY: - NAME: "&7%blockReturnDelayTarget% Return Delay: &6%blockReturnDelay%" + NAME: "%blockReturnDelayTarget% Return Delay: %blockReturnDelay%" MATERIAL: BLUE_TERRACOTTA LORE: - "" - - "&7This controls the %blockReturnDelayTarget%" - - "&7return delay after placement." - - "&7Set to &e-1 &7to disable auto return." + - "This controls the %blockReturnDelayTarget%" + - "return delay after placement." + - "Set to -1 to disable auto return." - "" - - "&a&lLEFT-CLICK &ato reduce the delay." - - "&b&lRIGHT-CLICK &bto increase the delay." + - "LEFT-CLICK to reduce the delay." + - "RIGHT-CLICK to increase the delay." TEMP-BUILD-RETURN-DELAY: - NAME: "&7Temporary Block Return Delay: &6%tempBuildReturnDelay%" + NAME: "Temporary Block Return Delay: %tempBuildReturnDelay%" MATERIAL: RED_TERRACOTTA LORE: - "" - - "&7This controls how long placed" - - "&7temporary blocks stay before" - - "&7they automatically disappear." - - "&7Set to &e-1 &7to disable auto return." + - "This controls how long placed" + - "temporary blocks stay before" + - "they automatically disappear." + - "Set to -1 to disable auto return." - "" - - "&a&lLEFT-CLICK &ato reduce the delay." - - "&b&lRIGHT-CLICK &bto increase the delay." + - "LEFT-CLICK to reduce the delay." + - "RIGHT-CLICK to increase the delay." ROUND-END-DELAY: - NAME: "&7Round End Delay: &6%roundEndDelay% sec" + NAME: "Round End Delay: %roundEndDelay% sec" MATERIAL: CLOCK LORE: - "" - - "&7Time to wait after a round ends before" - - "&7starting the next transition. Allows" - - "&7death effects to complete." + - "Time to wait after a round ends before" + - "starting the next transition. Allows" + - "death effects to complete." - "" - - "&a&lLEFT-CLICK &ato reduce the delay." - - "&b&lRIGHT-CLICK &bto increase the delay." + - "LEFT-CLICK to reduce the delay." + - "RIGHT-CLICK to increase the delay." ROUND-STATUS-TITLES: ENABLED: - NAME: "&7Round Status Titles: &aEnabled" + NAME: "Round Status Titles: Enabled" MATERIAL: WRITTEN_BOOK LORE: - "" - - "&7Shows green &aVICTORY! &7and red" - - "&cDEFEAT &7titles when a round ends." + - "Shows green VICTORY! and red" + - "DEFEAT titles when a round ends." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Round Status Titles: &cDisabled" + NAME: "Round Status Titles: Disabled" MATERIAL: WRITTEN_BOOK LORE: - "" - - "&7Shows green &aVICTORY! &7and red" - - "&cDEFEAT &7titles when a round ends." + - "Shows green VICTORY! and red" + - "DEFEAT titles when a round ends." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." COUNTDOWN-TITLES: ENABLED: - NAME: "&7Countdown Titles: &aEnabled" + NAME: "Countdown Titles: Enabled" MATERIAL: CLOCK LORE: - "" - - "&7Displays &63, 2, 1, FIGHT! &7titles" - - "&7during the round start countdown." + - "Displays 3, 2, 1, FIGHT! titles" + - "during the round start countdown." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Countdown Titles: &cDisabled" + NAME: "Countdown Titles: Disabled" MATERIAL: CLOCK LORE: - "" - - "&7Displays &63, 2, 1, FIGHT! &7titles" - - "&7during the round start countdown." + - "Displays 3, 2, 1, FIGHT! titles" + - "during the round start countdown." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." BOXING: - NAME: "&7Boxing Strokes to Win: &6%boxingWinHits%" + NAME: "Boxing Strokes to Win: %boxingWinHits%" MATERIAL: LEVER LORE: - "" - - "&7A player or team wins if they have" - - "&7gained that many strokes." - - "&7In a team match, player's" - - "&7strokes are added together." + - "A player or team wins if they have" + - "gained that many strokes." + - "In a team match, player's" + - "strokes are added together." - "" - - "&a&lLEFT-CLICK &ato reduce the strokes." - - "&b&lRIGHT-CLICK &bto increase the strokes." + - "LEFT-CLICK to reduce the strokes." + - "RIGHT-CLICK to increase the strokes." RESPAWN: - NAME: "&7Respawn Time: &6%respawnTime%" + NAME: "Respawn Time: %respawnTime%" MATERIAL: RED_BED LORE: - "" - - "&7That's how long it takes" - - "&7for a player to come back to life" - - "&7when he dies without his bed being broken" - - "&7or when the ladder type is battle rush / bridges." + - "That's how long it takes" + - "for a player to come back to life" + - "when he dies without his bed being broken" + - "or when the ladder type is battle rush / bridges." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." FIREBALL-COOLDOWN: - NAME: "&7Fireball Cooldown: &6%cooldown% sec" + NAME: "Fireball Cooldown: %cooldown% sec" MATERIAL: FIRE_CHARGE LORE: - "" - - "&7Players must wait this long before" - - "&7they throw another fireball." + - "Players must wait this long before" + - "they throw another fireball." - "" - - "&a&lLEFT-CLICK &ato reduce the cooldown." - - "&b&lRIGHT-CLICK &bto increase the cooldown." + - "LEFT-CLICK to reduce the cooldown." + - "RIGHT-CLICK to increase the cooldown." INVENTORY: - TITLE: "&1%ladder% &8- Inventory" + TITLE: "%ladder% - Inventory" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW CUSTOM-KIT-EDITOR: EDITABLE: - NAME: "&6Custom Kit &7Editor" + NAME: "Custom Kit Editor" MATERIAL: BOOK LORE: - "" - - "&6&lClick here &7to customize" - - "&7what extra items the players" - - "&7can add to the custom kit." + - "Click here to customize" + - "what extra items the players" + - "can add to the custom kit." NOT-EDITABLE: - NAME: "&6Custom Kit &7Editor" + NAME: "Custom Kit Editor" MATERIAL: BOOK LORE: - "" - - "&cThis ladder is not editable" - - "&cby the players." + - "This ladder is not editable" + - "by the players." EFFECTS: HAS-EFFECT: - EFFECT-FORMAT: "&d%name% %amplifier% &7for %time%" - NAME: "&5Effects" + EFFECT-FORMAT: "%name% %amplifier% for %time%" + NAME: "Effects" MATERIAL: POTION DAMAGE: 8233 LORE: - - "&8&m------------------------" - - "&c&lNote: &7You can set the effects by using" - - "&7the &7&l/ladder seteffects %ladder% &7command." + - "------------------------" + - "Note: You can set the effects by using" + - "the /ladder seteffects %ladder% command." - "" - - "&aCurrently set effects:" + - "Currently set effects:" - "%effects%" - - "&8&m------------------------" + - "------------------------" NO-EFFECT: - NAME: "&5Effects" + NAME: "Effects" MATERIAL: POTION DAMAGE: 8233 LORE: - - "&8&m------------------------" - - "&7This ladder has no effects." - - "&8&m------------------------" + - "------------------------" + - "This ladder has no effects." + - "------------------------" DESTROYABLE-BLOCKS: - TITLE: "&1%ladder% &8- D-Blocks" + TITLE: "%ladder% - D-Blocks" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW CUSTOM-KIT: - TITLE: "&1%ladder% &8- Custom Kit" + TITLE: "%ladder% - Custom Kit" ICONS: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW SAVE: - NAME: "&a&lSave" + NAME: "Save" MATERIAL: LIME_WOOL LORE: - "" - - "&cThis is just a showcase item, which" - - "&ccurrently has no functionality, but" - - "&cit demonstrates how the kit editor will look like." + - "This is just a showcase item, which" + - "currently has no functionality, but" + - "it demonstrates how the kit editor will look like." LOAD: - NAME: "&e&lLoad default kit" + NAME: "Load default kit" MATERIAL: YELLOW_WOOL LORE: - "" - - "&cThis is just a showcase item, which" - - "&ccurrently has no functionality, but" - - "&cit demonstrates how the kit editor will look like." + - "This is just a showcase item, which" + - "currently has no functionality, but" + - "it demonstrates how the kit editor will look like." CANCEL: - NAME: "&c&lCancel" + NAME: "Cancel" MATERIAL: RED_WOOL LORE: - "" - - "&cThis is just a showcase item, which" - - "&ccurrently has no functionality, but" - - "&cit demonstrates how the kit editor will look like." + - "This is just a showcase item, which" + - "currently has no functionality, but" + - "it demonstrates how the kit editor will look like." SWITCH-WEIGHTCLASS: ONLY-UNRANKED: - NAME: "&cThis ladder is only %weightClass%." + NAME: "This ladder is only %weightClass%." MATERIAL: REDSTONE ONLY-RANKED: - NAME: "&cThis ladder is only %weightClass%." + NAME: "This ladder is only %weightClass%." MATERIAL: REDSTONE SWITCH-TO-UNRANKED: - NAME: "&aSwitch to %weightClass%" + NAME: "Switch to %weightClass%" MATERIAL: WOODEN_SWORD SWITCH-TO-RANKED: - NAME: "&aSwitch to %weightClass%" + NAME: "Switch to %weightClass%" MATERIAL: IRON_SWORD MATCH-TYPE: - TITLE: "&1%ladder% &8- Match Types" + TITLE: "%ladder% - Match Types" ICONS: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW ENABLED: NAME: "%matchType%" MATERIAL: LIME_DYE LORE: - "" - - "&eClick here &7to &cdisable %matchType%" - - "&7match type for the ladder." + - "Click here to disable %matchType%" + - "match type for the ladder." DISABLED: NAME: "%matchType%" MATERIAL: GRAY_DYE LORE: - "" - - "&eClick here &7to &aenable %matchType%" - - "&7match type for the ladder." + - "Click here to enable %matchType%" + - "match type for the ladder." SKYWARS-LOOT: - TITLE: "&1%ladder% &8- SkyWars loot" + TITLE: "%ladder% - SkyWars loot" ICONS: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW EVENT: EVENT-MANAGER: - TITLE: "&8Event Manager" + TITLE: "Event Manager" ICONS: BACK-TO: - NAME: "&cBack to Server Manager" + NAME: "Back to Server Manager" MATERIAL: ARROW EVENT-ICON: STATUS-NAMES: - ENABLED: "&aEnabled" - DISABLED: "&cDisabled" - NAME: "&e%eventName%" + ENABLED: "Enabled" + DISABLED: "Disabled" + NAME: "%eventName%" LORE: - "" - - "&6Event Information:" - - " &7» &eState: %state%" + - "Event Information:" + - " » State: %state%" - "" - - "&b&lLEFT-CLICK &bto open event settings." - - "&a&lRIGHT-CLICK &ato teleport to the event." + - "LEFT-CLICK to open event settings." + - "RIGHT-CLICK to teleport to the event." EVENT-MAIN: - TITLE: "%eventName% &8- Event" + TITLE: "%eventName% - Event" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW EVENT-NAME: - NAME: "&e%eventName%" + NAME: "%eventName%" LORE: - "" - - "&7&lIcon Customization:" - - "&b» LEFT-CLICK &7with an item to set as icon" + - "Icon Customization:" + - "» LEFT-CLICK with an item to set as icon" - "" - - "&7&lQuick Teleport:" - - "&b» RIGHT-CLICK &7to teleport to event arena" + - "Quick Teleport:" + - "» RIGHT-CLICK to teleport to event arena" - "" - - "&7Change the visual icon shown in the" - - "&7Event Host GUI by clicking with any item." + - "Change the visual icon shown in the" + - "Event Host GUI by clicking with any item." SETTINGS: - NAME: "&4Settings" + NAME: "Settings" MATERIAL: REDSTONE LORE: - "" - - "&e&lCLICK &7to configure event settings:" + - "CLICK to configure event settings:" - "" - - " &8» &cBroadcast Interval &7(chat announcements)" - - " &8» &cQueue Wait Time &7(before start)" - - " &8» &cMax Queue Time &7(before cancel)" - - " &8» &cGame Duration &7(match length)" - - " &8» &cStart Countdown &7(game start delay)" - - " &8» &cMin/Max Players &7(requirements)" + - " » Broadcast Interval (chat announcements)" + - " » Queue Wait Time (before start)" + - " » Max Queue Time (before cancel)" + - " » Game Duration (match length)" + - " » Start Countdown (game start delay)" + - " » Min/Max Players (requirements)" - "" - - "&7Fine-tune event behavior and timings." + - "Fine-tune event behavior and timings." STATUS: ENABLED: - NAME: "&7Status: &aEnabled" + NAME: "Status: Enabled" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &cdisable &7the event." + - "Click here to disable the event." - "" - - "&eYou can only edit the event if its disabled." + - "You can only edit the event if its disabled." DISABLED: - NAME: "&7Status: &cDisabled" + NAME: "Status: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&e&lCLICK &7to &aenable &7the event." + - "CLICK to enable the event." - "" - - "&c&lRequirements to Enable:" - - " &8» &eEvent region (2 corners) must be set" - - " &8» &eAt least 2 spawn points must be set" - - " &8» &eAll settings must be configured" + - "Requirements to Enable:" + - " » Event region (2 corners) must be set" + - " » At least 2 spawn points must be set" + - " » All settings must be configured" - "" - - "&7&oUse the LOCATION button to set these up!" + - "Use the LOCATION button to set these up!" LOCATION: - NAME: "&5Locations" + NAME: "Locations" MATERIAL: COMPASS LORE: - "" - - "&d&lLEFT-CLICK &7to start interactive setup mode." + - "LEFT-CLICK to start interactive setup mode." - "" - - "&5&lSetup Process:" - - "&71. &dReceive Event Wand &7to configure locations" - - "&72. &dSet Corners: &7Left/Right click to mark region" - - "&73. &dAdd Spawns: &7Right click blocks to add spawn points" - - "&74. &dCycle Modes: &7Shift + Left/Right click" - - "&75. &dExit Setup: &7Drop (Q) the wand" + - "Setup Process:" + - "1. Receive Event Wand to configure locations" + - "2. Set Corners: Left/Right click to mark region" + - "3. Add Spawns: Right click blocks to add spawn points" + - "4. Cycle Modes: Shift + Left/Right click" + - "5. Exit Setup: Drop (Q) the wand" - "" - - "&5&lCurrently Configured:" - - " &5» &dCorner 1: &7%corner1%" - - " &5» &dCorner 2: &7%corner2%" - - " &5» &dSpawn Points: &7%spawnPositions% set" + - "Currently Configured:" + - " » Corner 1: %corner1%" + - " » Corner 2: %corner2%" + - " » Spawn Points: %spawnPositions% set" - "" - - "&7&oNo commands needed - use the wand!" + - "No commands needed - use the wand!" EVENT-SETTINGS: - TITLE: "&1%eventName% &8- Settings" + TITLE: "%eventName% - Settings" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW BROADCAST-INTERVAL: - NAME: "&7Broadcast Interval: &6%broadcastInterval% &7sec" + NAME: "Broadcast Interval: %broadcastInterval% sec" MATERIAL: CLOCK LORE: - "" - - "&7The event will be announced" - - "&7every so often on the chat." + - "The event will be announced" + - "every so often on the chat." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." WAIT-BEFORE-START: - NAME: "&7Wait before event start: &6%waitBeforeStart% &7sec" + NAME: "Wait before event start: %waitBeforeStart% sec" MATERIAL: ANVIL LORE: - "" - - "&7The event waits up to this number" - - "&7of seconds before starts the game" - - "&7if it reaches the minimum number of players." + - "The event waits up to this number" + - "of seconds before starts the game" + - "if it reaches the minimum number of players." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." MAX-QUEUE-TIME: - NAME: "&7Maximum Queue Time: &6%queueTime% &7min" + NAME: "Maximum Queue Time: %queueTime% min" MATERIAL: BOOK LORE: - "" - - "&7The event waits up to this number" - - "&7of minutes before it stops the" - - "&7queue if the game does not start." + - "The event waits up to this number" + - "of minutes before it stops the" + - "queue if the game does not start." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." DURATION: TNTTAG: - NAME: "&7Tnt Explode Time: &6%explodeTime% &7sec" + NAME: "Tnt Explode Time: %explodeTime% sec" MATERIAL: TNT LORE: - "" - - "&7After all this time, the tnt explodes." + - "After all this time, the tnt explodes." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." SUMO&BRACKETS: - NAME: "&7Duel Duration: &6%roundDuration% &7min" + NAME: "Duel Duration: %roundDuration% min" MATERIAL: BLAZE_ROD LORE: - "" - - "&7This is how long 1 game session lasts." + - "This is how long 1 game session lasts." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." OTHER: - NAME: "&7Game Duration: &6%duration% &7min" + NAME: "Game Duration: %duration% min" MATERIAL: BLAZE_ROD LORE: - "" - - "&7That's how long the game lasts." + - "That's how long the game lasts." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." START-TIME: - NAME: "&7Start Countdown: &6%startTime% &7sec" + NAME: "Start Countdown: %startTime% sec" MATERIAL: FEATHER LORE: - "" - - "&7The game starts after this time." + - "The game starts after this time." - "" - - "&a&lLEFT-CLICK &ato reduce the time." - - "&b&lRIGHT-CLICK &bto increase the time." + - "LEFT-CLICK to reduce the time." + - "RIGHT-CLICK to increase the time." MIN-PLAYER: - NAME: "&7Min Player: &6%minPlayer%" + NAME: "Min Player: %minPlayer%" MATERIAL: SNOWBALL LORE: - "" - - "&7At least this many players must" - - "&7join the event for it to start." + - "At least this many players must" + - "join the event for it to start." - "" - - "&a&lLEFT-CLICK &ato reduce the amount." - - "&b&lRIGHT-CLICK &bto increase the amount." + - "LEFT-CLICK to reduce the amount." + - "RIGHT-CLICK to increase the amount." MAX-PLAYER: - NAME: "&7Max Player: &6%maxPlayer%" + NAME: "Max Player: %maxPlayer%" MATERIAL: GHAST_TEAR LORE: - "" - - "&7Maximum number of players" - - "&7allowed to join the event." + - "Maximum number of players" + - "allowed to join the event." - "" - - "&a&lLEFT-CLICK &ato reduce the amount." - - "&b&lRIGHT-CLICK &bto increase the amount." + - "LEFT-CLICK to reduce the amount." + - "RIGHT-CLICK to increase the amount." HOLOGRAM: HOLOGRAM-MANAGER: - TITLE: "&8Hologram Manager" + TITLE: "Hologram Manager" ICONS: BACK-TO: - NAME: "&cBack to Server Manager" + NAME: "Back to Server Manager" MATERIAL: ARROW HOLOGRAM-ICON: STATUS-NAMES: - ENABLED: "&aEnabled" - DISABLED: "&cDisabled" - TYPE-NULL: "&cN/A" - NAME: "&6%hologramName%" + ENABLED: "Enabled" + DISABLED: "Disabled" + TYPE-NULL: "N/A" + NAME: "%hologramName%" MATERIAL: PAPER LORE: - "" - - "&6Hologram Information:" - - " &7» &eState: %state%" - - " &7» &eType: &f%type%" - - " &7» &eStats Show: &f%statsShow%" + - "Hologram Information:" + - " » State: %state%" + - " » Type: %type%" + - " » Stats Show: %statsShow%" - "" - - "&b&lLEFT-CLICK &bto open hologram settings." - - "&a&lRIGHT-CLICK &ato teleport to the hologram." + - "LEFT-CLICK to open hologram settings." + - "RIGHT-CLICK to teleport to the hologram." HOLOGRAM-MAIN: - TITLE: "&1%hologram% &8- Hologram" + TITLE: "%hologram% - Hologram" ICONS: BACK-TO: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW DELETE: - NAME: "&cDelete Hologram" + NAME: "Delete Hologram" MATERIAL: RED_DYE EVENT-TYPE: - NAME: "&6Hologram Type" + NAME: "Hologram Type" MATERIAL: NETHER_STAR LORE: - "" - "%eventTypes%" - "" - - "&b&lClick here &bto change the hologram's type." + - "Click here to change the hologram's type." LADDER: NO-LADDER-SETTINGS: - NAME: "&cThis hologram type has no ladder settings!" + NAME: "This hologram type has no ladder settings!" MATERIAL: RED_STAINED_GLASS_PANE HAS-LADDER-SETTINGS: - NAME: "&3Ladder Settings" + NAME: "Ladder Settings" MATERIAL: GOLDEN_SWORD LORE: - "" - - "&b&lClick here &bto open the hologram's" - - "&bladder settings." + - "Click here to open the hologram's" + - "ladder settings." SHOW-STATS: - NAME: "&cShow Statistics: &f%showStats%" + NAME: "Show Statistics: %showStats%" MATERIAL: PLAYER_HEAD LORE: - "" - - "&7The hologram will show the" - - "&7first this many statistics." + - "The hologram will show the" + - "first this many statistics." - "" - - "&a&lLEFT-CLICK &ato decrease the number." - - "&b&lRIGHT-CLICK &bto increase the number." + - "LEFT-CLICK to decrease the number." + - "RIGHT-CLICK to increase the number." STATUS: ENABLED: - NAME: "&7Status: &aEnabled" + NAME: "Status: Enabled" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &cdisable &7the hologram." + - "Click here to disable the hologram." DISABLED: - NAME: "&7Status: &cDisabled" + NAME: "Status: Disabled" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&e&lClick here &7to &aenable &7the hologram." + - "Click here to enable the hologram." - "" - - "&c&lNote: &7The hologram has to meet some" - - "&7requirements to be enabled:" - - " &8» &eSet a type." - - " &8» &eSet the ladder(s) if necessary." + - "Note: The hologram has to meet some" + - "requirements to be enabled:" + - " » Set a type." + - " » Set the ladder(s) if necessary." HOLOGRAM-LADDERS: - TITLE: "&1%hologram% &8- Ladders" + TITLE: "%hologram% - Ladders" ICONS: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW ENABLED-LADDER: - NAME: "&a%ladder%" + NAME: "%ladder%" MATERIAL: LIME_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder is &aenabled&7." + - "This ladder is enabled." - "" - - "&eClick here &7to &cdisable&7." + - "Click here to disable." DISABLED-LADDER: - NAME: "&c%ladder%" + NAME: "%ladder%" MATERIAL: RED_STAINED_GLASS_PANE LORE: - "" - - "&7This ladder is &cdisabled&7." + - "This ladder is disabled." - "" - - "&eClick here &7to &aenable&7." + - "Click here to enable." SERVER: SERVER-MANAGER: - TITLE: "&8Server Manager" + TITLE: "Server Manager" ICONS: BACK-TO: - NAME: "&eBack to hub" + NAME: "Back to hub" MATERIAL: ARROW INFORMATIONS: STATUS-NAMES: - SET: "&aSet" - UNSET: "&cNot-Set" - NAME: "&eInformations" + SET: "Set" + UNSET: "Not-Set" + NAME: "Informations" MATERIAL: BOOK LORE: - - "&8&m------------------------" - - "&7Online players: &e%onlinePlayers%" - - "&7Online staff: &e%onlineStaffs%" + - "------------------------" + - "Online players: %onlinePlayers%" + - "Online staff: %onlineStaffs%" - "" - - "&7Required unranked for ranked matches: &e%requiredDivision%" + - "Required unranked for ranked matches: %requiredDivision%" - "" - - "&7Lobby status: %lobbyStatus%" + - "Lobby status: %lobbyStatus%" - "" - - "&7Enabled arenas: &e%enabledArena%" - - "&7Enabled ladders: &e%enabledLadder%" - - "&7Enabled events: &e%enabledEvents%" - - "&8&m------------------------" + - "Enabled arenas: %enabledArena%" + - "Enabled ladders: %enabledLadder%" + - "Enabled events: %enabledEvents%" + - "------------------------" LOBBY-ARMORS: - NAME: "&eLobby Armors" + NAME: "Lobby Armors" MATERIAL: DIAMOND_CHESTPLATE LORE: - - "&8&m------------------------" - - "&7Click here to edit the lobby armors." - - "&8&m------------------------" + - "------------------------" + - "Click here to edit the lobby armors." + - "------------------------" SAVE: - NAME: "&eSave Data" + NAME: "Save Data" MATERIAL: SUGAR LORE: - - "&8&m------------------------" - - "&aLeft Click &7to open a GUI" - - "&7where you can save your" - - "&7server data in sections." + - "------------------------" + - "Left Click to open a GUI" + - "where you can save your" + - "server data in sections." - "" - - "&bRight Click &7to save all" - - "&7the server data manually." - - "&8&m------------------------" + - "Right Click to save all" + - "the server data manually." + - "------------------------" MATCHES: - NAME: "&eLive Matches" + NAME: "Live Matches" MATERIAL: IRON_SWORD LORE: - - "&8&m------------------------" - - "&7Click here to view the" - - "&7live matches." + - "------------------------" + - "Click here to view the" + - "live matches." - "" - - "&7Live matches: &e%liveMatches%" - - "&8&m------------------------" + - "Live matches: %liveMatches%" + - "------------------------" EVENTS: - NAME: "&eLive Events" + NAME: "Live Events" MATERIAL: BOW LORE: - - "&8&m------------------------" - - "&7Click here to view the" - - "&7live events." + - "------------------------" + - "Click here to view the" + - "live events." - "" - - "&7Live events: &e%liveEvents%" - - "&8&m------------------------" + - "Live events: %liveEvents%" + - "------------------------" LOBBY-ARMORS: - TITLE: "&8Lobby Armors" + TITLE: "Lobby Armors" ICONS: BACK-TO: - NAME: "&cBack to Server Manager" + NAME: "Back to Server Manager" MATERIAL: ARROW FILLER-ITEM: MATERIAL: BLACK_STAINED_GLASS_PANE FILLER-ITEM2: MATERIAL: ORANGE_STAINED_GLASS_PANE NAME-ITEM: - NAME: "&e%inventoryName%" + NAME: "%inventoryName%" MATERIAL: NAME_TAG EVENTS: - TITLE: "&8Events" + TITLE: "Events" ICONS: BACK-TO: - NAME: "&cBack to Server Manager" + NAME: "Back to Server Manager" MATERIAL: ARROW REFRESH-PAGE: - NAME: "&aRefresh Page" + NAME: "Refresh Page" MATERIAL: NETHER_STAR LORE: - - "&8&m------------------------" - - "&7Click here to refresh the page." - - "&8&m------------------------" + - "------------------------" + - "Click here to refresh the page." + - "------------------------" EVENT-ITEM: NAME: "%eventName%" LORE: - - "&8&m------------------------" - - "&eEvent Type: &f%type%" + - "------------------------" + - "Event Type: %type%" - "" - - "&ePlayers: &f%players%" - - "&eSpectators: &f%spectators%" + - "Players: %players%" + - "Spectators: %spectators%" - "" - - "&aLeft Click &7to spectate the event." - - "&bRight Click &7to &cend &7the event." - - "&8&m------------------------" + - "Left Click to spectate the event." + - "Right Click to end the event." + - "------------------------" MATCHES: - TITLE: "&8Matches - Page %page%" + TITLE: "Matches - Page %page%" ICONS: BACK-TO: - NAME: "&cBack to Server Manager" + NAME: "Back to Server Manager" MATERIAL: ARROW GO-PAGE-LEFT: - NAME: "&6Go to Page %page%" + NAME: "Go to Page %page%" MATERIAL: ARROW GO-PAGE-RIGHT: - NAME: "&6Go to Page %page%" + NAME: "Go to Page %page%" MATERIAL: ARROW REFRESH: - NAME: "&aRefresh Pages" + NAME: "Refresh Pages" MATERIAL: NETHER_STAR LORE: - - "&8&m------------------------" - - "&7Click here to refresh the pages." - - "&8&m------------------------" + - "------------------------" + - "Click here to refresh the pages." + - "------------------------" MATCH-ICON: NAME: "%matchType%" LORE: - - "&8&m------------------------" - - "&8#%matchId%" + - "------------------------" + - "#%matchId%" - "%weightClass%" - "" - - "&eMatch Type: &f%matchType%" - - "&eKit: &f%ladder%" - - "&eArena: &f%arena%" - - "&eDuration: &f%roundDuration%" - - "&eSpectators: &f%spectators%" + - "Match Type: %matchType%" + - "Kit: %ladder%" + - "Arena: %arena%" + - "Duration: %roundDuration%" + - "Spectators: %spectators%" - "" - - "&aLeft Click &7to spectate the match." - - "&bRight Click &7to &cend &7the match." - - "&8&m------------------------" + - "Left Click to spectate the match." + - "Right Click to end the match." + - "------------------------" FILE-SAVE: - TITLE: "&8Data Saver" + TITLE: "Data Saver" ICONS: BACK-TO: - NAME: "&cBack to Server Manager" + NAME: "Back to Server Manager" MATERIAL: ARROW DATA-SAVE: - NAME: "&e%data% Data Save" + NAME: "%data% Data Save" MATERIAL: PAPER LORE: - - "&8&m------------------------" - - "&7Click here to manually" - - "&7save the %data% data." - - "&8&m------------------------" + - "------------------------" + - "Click here to manually" + - "save the %data% data." + - "------------------------" COSMETICS: - MAIN-TITLE: "&8Armor Cosmetics" + MAIN-TITLE: "Armor Cosmetics" # Error messages for permission denied PERMISSION-DENIED-MESSAGE: "You do not have permission for the selected armor tier." TIER-PERMISSION-DENIED-MESSAGE: "You do not have permission for this armor tier." @@ -3171,91 +3187,91 @@ GUIS: BOOTS-MATERIAL: NETHERITE_BOOTS ICONS: HELMET-ICON: - NAME: "&eHelmet" + NAME: "Helmet" MATERIAL: LEATHER_HELMET LORE: - "" - - "&7Click here to customize" - - "&7armor trim patterns and materials" - - "&7for your helmet." + - "Click here to customize" + - "armor trim patterns and materials" + - "for your helmet." - "" CHESTPLATE-ICON: - NAME: "&eChestplate" + NAME: "Chestplate" MATERIAL: LEATHER_CHESTPLATE LORE: - "" - - "&7Click here to customize" - - "&7armor trim patterns and materials" - - "&7for your chestplate." + - "Click here to customize" + - "armor trim patterns and materials" + - "for your chestplate." - "" LEGGINGS-ICON: - NAME: "&eLeggings" + NAME: "Leggings" MATERIAL: LEATHER_LEGGINGS LORE: - "" - - "&7Click here to customize" - - "&7armor trim patterns and materials" - - "&7for your leggings." + - "Click here to customize" + - "armor trim patterns and materials" + - "for your leggings." - "" BOOTS-ICON: - NAME: "&eBoots" + NAME: "Boots" MATERIAL: LEATHER_BOOTS LORE: - "" - - "&7Click here to customize" - - "&7armor trim patterns and materials" - - "&7for your boots." + - "Click here to customize" + - "armor trim patterns and materials" + - "for your boots." - "" SHIELD-ICON: - NAME: "&eShield" + NAME: "Shield" MATERIAL: SHIELD LORE: - "" - - "&7Click here to customize" - - "&7the trim pattern for your shield." + - "Click here to customize" + - "the trim pattern for your shield." - "" INFO-ICON: - NAME: "&bCosmetics Information" + NAME: "Cosmetics Information" MATERIAL: BOOK LORE: - - "&8&m------------------------" - - "&7Unlocked Patterns: &b%pattern_unlocked%&7/&b%pattern_total%" - - "&7Unlocked Materials: &6%material_unlocked%&7/&6%material_total%" + - "------------------------" + - "Unlocked Patterns: %pattern_unlocked%/%pattern_total%" + - "Unlocked Materials: %material_unlocked%/%material_total%" - "" - - "&7Select a category item to edit" - - "&7your active trim cosmetics." - - "&8&m------------------------" + - "Select a category item to edit" + - "your active trim cosmetics." + - "------------------------" APPLY-ALL-TIERS: - NAME: "&aApply To All Armor Tiers" + NAME: "Apply To All Armor Tiers" MATERIAL: SMITHING_TABLE LORE: - - "&8&m------------------------" - - "&7Copies the active tier trim" - - "&7pattern and material to all tiers." + - "------------------------" + - "Copies the active tier trim" + - "pattern and material to all tiers." - "" - - "&eHelmet -> Helmet" - - "&eChestplate -> Chestplate" - - "&eLeggings -> Leggings" - - "&eBoots -> Boots" + - "Helmet -> Helmet" + - "Chestplate -> Chestplate" + - "Leggings -> Leggings" + - "Boots -> Boots" - "" - - "&aClick to apply" - - "&8&m------------------------" + - "Click to apply" + - "------------------------" BACK-TO: - NAME: "&cBack" + NAME: "Back" MATERIAL: ARROW # Dynamically built lore templates for armor cosmetics ARMOR-PREVIEW-LORE: - - "&7Tier: &e%tier%" - - "&7Active Pattern: %pattern%" - - "&7Active Material: %material%" + - "Tier: %tier%" + - "Active Pattern: %pattern%" + - "Active Material: %material%" - "" - - "&eLeft-Click to customize" - - "&cRight-Click to reset" + - "Left-Click to customize" + - "Right-Click to reset" TIER-TOGGLE-LORE: - "" - - "&7Left-click: &cPrevious tier" - - "&7Right-click: &aNext tier" - SUB-TITLE: "&8Customize %armor% Cosmetics" + - "Left-click: Previous tier" + - "Right-click: Next tier" + SUB-TITLE: "Customize %armor% Cosmetics" # Armor Piece Hub Configuration ARMOR-PIECE-HUB: INVENTORY-ROWS: 4 @@ -3265,144 +3281,144 @@ GUIS: PATTERN-MENU: 20 MATERIAL-MENU: 24 PREVIEW-ITEM: - NAME: "&eCurrent Preview" + NAME: "Current Preview" PATTERN-SELECTION-BUTTON: - NAME: "&bPattern Selection" + NAME: "Pattern Selection" LORE: - - "&7Open all available trim patterns." - - "&eClick to open." + - "Open all available trim patterns." + - "Click to open." DEFAULT-MATERIAL: SMITHING_TABLE MATERIAL-SELECTION-BUTTON: - NAME: "&6Material Selection" + NAME: "Material Selection" LORE: - - "&7Open all available trim materials." - - "&eClick to open." + - "Open all available trim materials." + - "Click to open." DEFAULT-MATERIAL: ANVIL # Pattern Selection GUI Configuration PATTERN-SELECTION: INVENTORY-ROWS: 5 BACK-SLOT: 36 START-SLOT: 10 - INVENTORY-TITLE: "&8Select Pattern - %armor%" + INVENTORY-TITLE: "Select Pattern - %armor%" PATTERN-ITEM: - NAME: "&b%pattern_name% Pattern" + NAME: "%pattern_name% Pattern" LORE: - - "&7Status: %state%" - - "&7Access: %access%" + - "Status: %state%" + - "Access: %access%" # Material Selection GUI Configuration MATERIAL-SELECTION: INVENTORY-ROWS: 5 BACK-SLOT: 36 START-SLOT: 10 - INVENTORY-TITLE: "&8Select Material - %armor%" + INVENTORY-TITLE: "Select Material - %armor%" MATERIAL-ITEM: - NAME: "&6%material_name% Material" + NAME: "%material_name% Material" LORE: - - "&7Status: %state%" - - "&7Access: %access%" + - "Status: %state%" + - "Access: %access%" MATERIAL-ICONS: LAPIS: LAPIS_LAZULI AMETHYST: AMETHYST_SHARD RESIN: RESIN_BRICK HUB: - TITLE: "&8✦ Cosmetics" + TITLE: "✦ Cosmetics" BUTTONS: ARMOR-TRIMS: - NAME: "&6✦ Armor Trims" + NAME: "✦ Armor Trims" MATERIAL: DIAMOND_CHESTPLATE GLOW: true LORE: - "" - - "&7Customize your armor tier," - - "&7trim patterns and materials." + - "Customize your armor tier," + - "trim patterns and materials." - "" - - "&eClick to open." + - "Click to open." SHIELD: - NAME: "&9✦ Shield" + NAME: "✦ Shield" MATERIAL: SHIELD GLOW: false LORE: - "" - - "&7Design your shield with any" - - "&7color and pattern combination." - - "&7Save multiple layouts." + - "Design your shield with any" + - "color and pattern combination." + - "Save multiple layouts." - "" - - "&eClick to open." + - "Click to open." LOBBY-ITEMS: - NAME: "&b✦ Lobby Items" + NAME: "✦ Lobby Items" MATERIAL: ELYTRA GLOW: false LORE: - "" - - "&7Choose your lobby movement" - - "&7cosmetic item loadout." + - "Choose your lobby movement" + - "cosmetic item loadout." - "" - - "&eClick to open." + - "Click to open." KILL-EFFECTS: - NAME: "&c✦ Death Effects" + NAME: "✦ Death Effects" MATERIAL: BLAZE_POWDER GLOW: false LORE: - "" - - "&7Choose a particle effect that" - - "&7plays when you kill someone." + - "Choose a particle effect that" + - "plays when you kill someone." - "" - - "&eClick to open." + - "Click to open." LOBBY-ITEMS: - TITLE: "&8✦ Lobby Items" + TITLE: "✦ Lobby Items" NO-PERMISSION-MESSAGE: "You don't have permission for this lobby cosmetic item!" ENTRIES: NONE: - NAME: "&7None" + NAME: "None" MATERIAL: BARRIER LORE: - "" - - "&7Disable lobby movement cosmetics." + - "Disable lobby movement cosmetics." - "" - - "&7Status: %status%" + - "Status: %status%" - "" WIND_CHARGE: - NAME: "&bWind Charge" + NAME: "Wind Charge" MATERIAL: WIND_CHARGE LORE: - "" - - "&7Infinite lobby wind charge" - - "&7while you are in lobby states." + - "Infinite lobby wind charge" + - "while you are in lobby states." - "" - - "&7Status: %status%" + - "Status: %status%" - "" TRIDENT: - NAME: "&3Riptide Trident" + NAME: "Riptide Trident" MATERIAL: TRIDENT LORE: - "" - - "&7Right-click with Trident in main hand" - - "&7to trigger riptide boost in lobby." + - "Right-click with Trident in main hand" + - "to trigger riptide boost in lobby." - "" - - "&7Status: %status%" + - "Status: %status%" - "" SPEAR: - NAME: "&5Lunge Spear" + NAME: "Lunge Spear" MATERIAL: NETHERITE_SPEAR LORE: - "" - - "&7Right-click with Spear in main hand" - - "&7to trigger lunge dash in lobby." + - "Right-click with Spear in main hand" + - "to trigger lunge dash in lobby." - "" - - "&7Status: %status%" + - "Status: %status%" - "" DEATH-EFFECTS: - TITLE: "&8✦ Death Effects" + TITLE: "✦ Death Effects" NO-PERMISSION-MESSAGE: "You don't have permission for this death effect!" - SELECTED-PREFIX: "&a✔ " - UNLOCKED-PREFIX: "&e" - LOCKED-PREFIX: "&c🔒 " - CLICK-TO-SELECT: "&eClick to select." - CLICK-TO-DESELECT: "&7Click to deselect." - NO-PERMISSION-LORE: "&cRequires: &7%permission%" + SELECTED-PREFIX: "✔ " + UNLOCKED-PREFIX: "" + LOCKED-PREFIX: "🔒 " + CLICK-TO-SELECT: "Click to select." + CLICK-TO-DESELECT: "Click to deselect." + NO-PERMISSION-LORE: "Requires: %permission%" DEFAULT-LORE: - "" - - "&7Status: %status%" + - "Status: %status%" - "" ENTRIES: NONE: @@ -3410,152 +3426,152 @@ GUIS: ICON: BARRIER LORE: - "" - - "&7No kill effect." - - "&7Status: %status%" + - "No kill effect." + - "Status: %status%" - "" FLAME: DISPLAY-NAME: "Flame" ICON: BLAZE_POWDER LORE: - "" - - "&7Bursts of fire on kill." - - "&7Status: %status%" + - "Bursts of fire on kill." + - "Status: %status%" - "" LIGHTNING: DISPLAY-NAME: "Lightning" ICON: LIGHTNING_ROD LORE: - "" - - "&7A lightning strike on kill." - - "&7Status: %status%" + - "A lightning strike on kill." + - "Status: %status%" - "" FIREWORK: DISPLAY-NAME: "Firework" ICON: FIREWORK_ROCKET LORE: - "" - - "&7Fireworks burst on kill." - - "&7Status: %status%" + - "Fireworks burst on kill." + - "Status: %status%" - "" EXPLOSION: DISPLAY-NAME: "Explosion" ICON: TNT LORE: - "" - - "&7Smoke & fire explosion on kill." - - "&7Status: %status%" + - "Smoke & fire explosion on kill." + - "Status: %status%" - "" BLOOD: DISPLAY-NAME: "Blood" ICON: REDSTONE LORE: - "" - - "&7Red dust particles on kill." - - "&7Status: %status%" + - "Red dust particles on kill." + - "Status: %status%" - "" ENCHANT: DISPLAY-NAME: "Enchant" ICON: ENCHANTING_TABLE LORE: - "" - - "&7Magic enchant particles on kill." - - "&7Status: %status%" + - "Magic enchant particles on kill." + - "Status: %status%" - "" ENDER: DISPLAY-NAME: "Ender" ICON: ENDER_PEARL LORE: - "" - - "&7Ender portal particles on kill." - - "&7Status: %status%" + - "Ender portal particles on kill." + - "Status: %status%" - "" HEARTS: DISPLAY-NAME: "Hearts" ICON: PINK_DYE LORE: - "" - - "&7Floating hearts on kill." - - "&7Status: %status%" + - "Floating hearts on kill." + - "Status: %status%" - "" ICE: DISPLAY-NAME: "Ice" ICON: PACKED_ICE LORE: - "" - - "&7Snowflake & ice particles on kill." - - "&7Status: %status%" + - "Snowflake & ice particles on kill." + - "Status: %status%" - "" SUPERNOVA: DISPLAY-NAME: "Supernova" ICON: NETHER_STAR LORE: - "" - - "&7Massive cosmic blast with" - - "&7bright starburst visuals." - - "&7Status: %status%" + - "Massive cosmic blast with" + - "bright starburst visuals." + - "Status: %status%" - "" VOIDSTORM: DISPLAY-NAME: "Voidstorm" ICON: ENDER_EYE LORE: - "" - - "&7Dark void surge with portal" - - "&7and dragon-breath energy." - - "&7Status: %status%" + - "Dark void surge with portal" + - "and dragon-breath energy." + - "Status: %status%" - "" PHOENIX: DISPLAY-NAME: "Phoenix" ICON: TOTEM_OF_UNDYING LORE: - "" - - "&7Fiery rebirth burst with" - - "&7totem-like impact effects." - - "&7Status: %status%" + - "Fiery rebirth burst with" + - "totem-like impact effects." + - "Status: %status%" - "" COMET: DISPLAY-NAME: "Comet" ICON: FIRE_CHARGE LORE: - "" - - "&7A high-energy comet strike" - - "&7with sparkling shockwaves." - - "&7Status: %status%" + - "A high-energy comet strike" + - "with sparkling shockwaves." + - "Status: %status%" - "" # ── Shield Cosmetics ────────────────────────────────────────────────────── SHIELD: NO-PERMISSION-MESSAGE: "You don't have permission to use shield cosmetics!" # Layout list GUI LAYOUTS: - TITLE: "&8\u2756 Shield Layouts" + TITLE: "\u2756 Shield Layouts" NAME-TITLE: "Layout Name" RENAME-TITLE: "Rename Layout" LIMIT-REACHED: "You've reached your layout limit! Get a higher rank for more." DELETED-MESSAGE: "Layout deleted." NEW-BUTTON: - NAME: "&aNew Layout" + NAME: "New Layout" # Editor GUI EDITOR: - TITLE: "&8Editing: &e%name%" + TITLE: "Editing: %name%" APPLIED-MESSAGE: "Shield layout applied!" UNAPPLIED-MESSAGE: "Shield cosmetic removed." ADD-LAYER: - NAME: "&aAdd Layer" + NAME: "Add Layer" MAX-LAYERS: - NAME: "&cMax Layers Reached" + NAME: "Max Layers Reached" MESSAGE: "Maximum of 6 layers reached!" REMOVE-LAYER: - NAME: "&cRemove Top Layer" + NAME: "Remove Top Layer" # Color picker GUI COLOR-PICKER: - BASE-TITLE: "&8Pick Base Color" - LAYER-TITLE: "&8Pick Layer Color" + BASE-TITLE: "Pick Base Color" + LAYER-TITLE: "Pick Layer Color" # Pattern picker GUI PATTERN-PICKER: - TITLE: "&8Pick Pattern" + TITLE: "Pick Pattern" APPLIED-MESSAGE: "Layer applied!" MATCH-HISTORY: # GUI title. %player% = the target player's name. - TITLE: "&8Match History &7- &6%player%" + TITLE: "Match History - %player%" # Total number of slots. Must be a multiple of 9, max 54. SIZE: 27 @@ -3586,25 +3602,25 @@ GUIS: # Item display name. Supports & colour codes. # Placeholders: %opponent% %result% %score% %kit% %arena% # %player_health% %opponent_health% %duration% %date% - NAME: "&eMatch vs &f%opponent%" + NAME: "Match vs %opponent%" # Item lore. Supports & colour codes and the same placeholders. LORE: - - "&8&m--------------------" - - "&7Result: %result%" - - "&7Score: &f%score%" - - "&7Kit: &f%kit%" - - "&7Arena: &f%arena%" + - "--------------------" + - "Result: %result%" + - "Score: %score%" + - "Kit: %kit%" + - "Arena: %arena%" - "" - - "&7Your Health: %player_health%" - - "&7Opp Health: %opponent_health%" + - "Your Health: %player_health%" + - "Opp Health: %opponent_health%" - "" - - "&7Duration: &f%duration%" - - "&7Played: &f%date%" - - "&8&m--------------------" + - "Duration: %duration%" + - "Played: %date%" + - "--------------------" # Result label strings inserted into %result%. MESSAGES: - WIN: "&aWin" - LOSS: "&cLoss" - DRAW: "&eDraw" + WIN: "Win" + LOSS: "Loss" + DRAW: "Draw" diff --git a/core/src/main/resources/inventories.yml b/core/src/main/resources/inventories.yml index 6a25bc8f5..f45848b16 100644 --- a/core/src/main/resources/inventories.yml +++ b/core/src/main/resources/inventories.yml @@ -9,31 +9,31 @@ LOBBY-BASIC: QUEUE: SLOT: 0 ITEM: - NAME: "&6Queue &7(Right-Click)" + NAME: "Queue (Right-Click)" MATERIAL: GOLDEN_SWORD UNRANKED: SLOT: 0 ITEM: - NAME: "&eUnranked Queue &7(Right-Click)" + NAME: "Unranked Queue (Right-Click)" MATERIAL: WOODEN_SWORD DURABILITY: 100 RANKED: SLOT: 1 ITEM: - NAME: "&cRanked Queue &7(Right-Click)" + NAME: "Ranked Queue (Right-Click)" MATERIAL: IRON_SWORD COSMETICS: SLOT: 4 ITEM: - NAME: "&dCosmetics Hub &7(Right-Click)" + NAME: "Cosmetics Hub (Right-Click)" MATERIAL: NETHER_STAR LORE: - "" - - "&7Customize your style with" - - "&fArmor Trims&7, &fShield Layouts&7," - - "and &fDeath Effects&7." + - "Customize your style with" + - "Armor Trims, Shield Layouts," + - "and Death Effects." - "" - - "&eOpen the cosmetics menu." + - "Open the cosmetics menu." ENCHANTMENTS: - "DURABILITY:1" FLAGS: @@ -41,17 +41,17 @@ LOBBY-BASIC: ENABLE-SPECTATE-MODE: SLOT: -1 ITEM: - NAME: "&aEnable &eSpectate Mode &7(Right-Click)" + NAME: "Enable Spectate Mode (Right-Click)" MATERIAL: REDSTONE_TORCH PARTY-CREATE: SLOT: 7 ITEM: - NAME: "&dCreate Party &7(Right-Click)" + NAME: "Create Party (Right-Click)" MATERIAL: NAME_TAG SETTINGS: SLOT: -1 ITEM: - NAME: "&aSettings &7(Right-Click)" + NAME: "Settings (Right-Click)" MATERIAL: CLOCK AMOUNT: 1 ENCHANTMENTS: @@ -61,27 +61,27 @@ LOBBY-BASIC: KIT-EDITOR: SLOT: 8 ITEM: - NAME: "&6Kit Editor &7(Right-Click)" + NAME: "Kit Editor (Right-Click)" MATERIAL: BOOK SETUP: SLOT: -1 ITEM: - NAME: "&cManage Server &7(Right-Click)" + NAME: "Manage Server (Right-Click)" MATERIAL: REDSTONE STAFF-MODE: SLOT: -1 ITEM: - NAME: "&aEnable &dStaff Mode &7(Right-Click)" + NAME: "Enable Staff Mode (Right-Click)" MATERIAL: PINK_DYE REMATCH: SLOT: 4 ITEM: - NAME: "&6Rematch &7(Right-Click)" + NAME: "Rematch (Right-Click)" MATERIAL: BLAZE_POWDER STATISTICS: SLOT: -1 ITEM: - NAME: "&2Statistics &7(Right-Click)" + NAME: "Statistics (Right-Click)" MATERIAL: EMERALD EXTRA: # HERE YOU CAN PUT THE EXTRA ITEMS LIKE THIS: @@ -89,12 +89,12 @@ LOBBY-BASIC: # COMMAND: unranked # Don't write the / character before the command. # SLOT: 2 # ITEM: - # NAME: "&cStuff Item" + # NAME: "Stuff Item" # MATERIAL: DIRT # DAMAGE: 0 # LORE: # - "" - # - "&dLore" + # - "Lore" # # Party inventory items # @@ -103,32 +103,32 @@ PARTY: HOST-PARTY-GAME: SLOT: 0 ITEM: - NAME: "&eHost Party Event &7(Right-Click)" + NAME: "Host Party Event (Right-Click)" MATERIAL: GOLDEN_AXE PARTY-INFO: SLOT: 1 ITEM: - NAME: "&bParty Information &7(Right-Click)" + NAME: "Party Information (Right-Click)" MATERIAL: NETHER_STAR OTHER-PARTIES: SLOT: 2 ITEM: - NAME: "&aOther Parties &7(Right-Click)" + NAME: "Other Parties (Right-Click)" MATERIAL: PLAYER_HEAD LEAVE-PARTY: SLOT: 8 ITEM: - NAME: "&cLeave Party &7(Right-Click)" + NAME: "Leave Party (Right-Click)" MATERIAL: RED_DYE PARTY-SETTINGS: SLOT: 4 ITEM: - NAME: "&6Party Settings &7(Right-Click)" + NAME: "Party Settings (Right-Click)" MATERIAL: CLOCK PARTY-KIT-EDITOR: SLOT: 7 ITEM: - NAME: "&6Kit Editor &7(Right-Click)" + NAME: "Kit Editor (Right-Click)" MATERIAL: BOOK EXTRA: # EXTRA ITEMS LIKE UPPER @@ -141,7 +141,7 @@ QUEUE: LEAVE-MATCH-QUEUE: SLOT: 4 ITEM: - NAME: "&cLeave Queue &7(Right-Click)" + NAME: "Leave Queue (Right-Click)" MATERIAL: RED_DYE EXTRA: # EXTRA ITEMS LIKE UPPER @@ -150,7 +150,7 @@ QUEUE: LEAVE-EVENT-QUEUE: SLOT: 4 ITEM: - NAME: "&cLeave &e%event% &cEvent Queue &7(Right-Click)" + NAME: "Leave %event% Event Queue (Right-Click)" MATERIAL: RED_DYE EXTRA: # EXTRA ITEMS LIKE UPPER @@ -163,17 +163,17 @@ SPECTATOR: MENU: SLOT: 5 ITEM: - NAME: "&bSpectate Menu &7(Right-Click)" + NAME: "Spectate Menu (Right-Click)" MATERIAL: PAPER DISABLE: SLOT: 4 ITEM: - NAME: "&cDisable &eSpectate Mode &7(Right-Click)" + NAME: "Disable Spectate Mode (Right-Click)" MATERIAL: REDSTONE_TORCH RANDOM: SLOT: 3 ITEM: - NAME: "&aSpectate Random Match &7(Right-Click)" + NAME: "Spectate Random Match (Right-Click)" MATERIAL: COMPASS EXTRA: # EXTRA ITEMS LIKE UPPER @@ -182,27 +182,27 @@ SPECTATOR: MENU: SLOT: 5 ITEM: - NAME: "&bSpectate Menu &7(Right-Click)" + NAME: "Spectate Menu (Right-Click)" MATERIAL: PAPER RANDOM: SLOT: 4 ITEM: - NAME: "&dSpectate Random Match &7(Right-Click)" + NAME: "Spectate Random Match (Right-Click)" MATERIAL: COMPASS SHOW-SPECTATORS: SLOT: 0 ITEM: - NAME: "&eShow Spectators &7(Right-Click)" + NAME: "Show Spectators (Right-Click)" MATERIAL: GRAY_DYE HIDE-SPECTATORS: SLOT: 0 ITEM: - NAME: "&eHide Spectators &7(Right-Click)" + NAME: "Hide Spectators (Right-Click)" MATERIAL: LIME_DYE LEAVE: SLOT: 8 ITEM: - NAME: "&cStop Spectating &7(Right-Click)" + NAME: "Stop Spectating (Right-Click)" MATERIAL: RED_DYE EXTRA: # EXTRA ITEMS LIKE UPPER @@ -211,7 +211,7 @@ SPECTATOR: LEAVE: SLOT: 8 ITEM: - NAME: "&cStop Spectating &7(Right-Click)" + NAME: "Stop Spectating (Right-Click)" MATERIAL: RED_DYE EXTRA: # EXTRA ITEMS LIKE UPPER @@ -220,7 +220,7 @@ SPECTATOR: LEAVE: SLOT: 8 ITEM: - NAME: "&cStop Spectating &7(Right-Click)" + NAME: "Stop Spectating (Right-Click)" MATERIAL: RED_DYE EXTRA: # EXTRA ITEMS LIKE UPPER @@ -232,32 +232,32 @@ STAFF-MODE: RANDOM-GAME-SPECTATE: SLOT: 0 ITEM: - NAME: "&dSpectate Random Match &7(Right-Click)" + NAME: "Spectate Random Match (Right-Click)" MATERIAL: COMPASS PLAYER-INVENTORY: SLOT: 1 ITEM: - NAME: "&6View Player's Inventory &7(Right-Click)" + NAME: "View Player's Inventory (Right-Click)" MATERIAL: STICK HIDE-FROM-PLAYERS-ON: SLOT: 8 ITEM: - NAME: "&eShow Myself To Players &7(Right-Click)" + NAME: "Show Myself To Players (Right-Click)" MATERIAL: GRAY_DYE HIDE-FROM-PLAYERS-OFF: SLOT: 8 ITEM: - NAME: "&eHide Myself From Players &7(Right-Click)" + NAME: "Hide Myself From Players (Right-Click)" MATERIAL: LIME_DYE TURN-OFF: SLOT: 4 ITEM: - NAME: "&cTurn Off StaffMode &7(Right-Click)" + NAME: "Turn Off StaffMode (Right-Click)" MATERIAL: RED_DYE LEAVE-SPECTATE: SLOT: 7 ITEM: - NAME: "&cLeave Spectation &7(Right-Click)" + NAME: "Leave Spectation (Right-Click)" MATERIAL: RED_DYE EXTRA: # EXTRA ITEMS LIKE UPPER \ No newline at end of file diff --git a/core/src/main/resources/ladders/axe.yml b/core/src/main/resources/ladders/axe.yml index 564284f8b..484ba1260 100644 --- a/core/src/main/resources/ladders/axe.yml +++ b/core/src/main/resources/ladders/axe.yml @@ -34,7 +34,7 @@ icon: id: minecraft:diamond_axe count: 1 components: - minecraft:custom_name: '"§bAxe"' + minecraft:custom_name: '{"text":"Axe","color":"aqua"}' schema_version: 1 armor: rO0ABXcEAAAABHNyABpvcmcuYnVra2l0LnV0aWwuaW8uV3JhcHBlcvJQR+zxEm8FAgABTAADbWFwdAAPTGphdmEvdXRpbC9NYXA7eHBzcgA1Y29tLmdvb2dsZS5jb21tb24uY29sbGVjdC5JbW11dGFibGVNYXAkU2VyaWFsaXplZEZvcm0AAAAAAAAAAAIAAkwABGtleXN0ABJMamF2YS9sYW5nL09iamVjdDtMAAZ2YWx1ZXNxAH4ABHhwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAABXQAAj09dAALRGF0YVZlcnNpb250AAJpZHQABWNvdW50dAAOc2NoZW1hX3ZlcnNpb251cQB+AAYAAAAFdAAeb3JnLmJ1a2tpdC5pbnZlbnRvcnkuSXRlbVN0YWNrc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAEj90ABdtaW5lY3JhZnQ6ZGlhbW9uZF9ib290c3NxAH4ADwAAAAFxAH4AE3NxAH4AAHNxAH4AA3VxAH4ABgAAAAVxAH4ACHEAfgAJcQB+AApxAH4AC3EAfgAMdXEAfgAGAAAABXEAfgAOc3EAfgAPAAASP3QAGm1pbmVjcmFmdDpkaWFtb25kX2xlZ2dpbmdzcQB+ABNxAH4AE3NxAH4AAHNxAH4AA3VxAH4ABgAAAAVxAH4ACHEAfgAJcQB+AApxAH4AC3EAfgAMdXEAfgAGAAAABXEAfgAOc3EAfgAPAAASP3QAHG1pbmVjcmFmdDpkaWFtb25kX2NoZXN0cGxhdGVxAH4AE3EAfgATc3EAfgAAc3EAfgADdXEAfgAGAAAABXEAfgAIcQB+AAlxAH4ACnEAfgALcQB+AAx1cQB+AAYAAAAFcQB+AA5zcQB+AA8AABI/dAAYbWluZWNyYWZ0OmRpYW1vbmRfaGVsbWV0cQB+ABNxAH4AEw== inventory: rO0ABXcEAAAAJHNyABpvcmcuYnVra2l0LnV0aWwuaW8uV3JhcHBlcvJQR+zxEm8FAgABTAADbWFwdAAPTGphdmEvdXRpbC9NYXA7eHBzcgA1Y29tLmdvb2dsZS5jb21tb24uY29sbGVjdC5JbW11dGFibGVNYXAkU2VyaWFsaXplZEZvcm0AAAAAAAAAAAIAAkwABGtleXN0ABJMamF2YS9sYW5nL09iamVjdDtMAAZ2YWx1ZXNxAH4ABHhwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAABXQAAj09dAALRGF0YVZlcnNpb250AAJpZHQABWNvdW50dAAOc2NoZW1hX3ZlcnNpb251cQB+AAYAAAAFdAAeb3JnLmJ1a2tpdC5pbnZlbnRvcnkuSXRlbVN0YWNrc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAEj90ABVtaW5lY3JhZnQ6ZGlhbW9uZF9heGVzcQB+AA8AAAABcQB+ABNzcQB+AABzcQB+AAN1cQB+AAYAAAAFcQB+AAhxAH4ACXEAfgAKcQB+AAtxAH4ADHVxAH4ABgAAAAVxAH4ADnNxAH4ADwAAEj90ABdtaW5lY3JhZnQ6ZGlhbW9uZF9zd29yZHEAfgATcQB+ABNzcQB+AABzcQB+AAN1cQB+AAYAAAAFcQB+AAhxAH4ACXEAfgAKcQB+AAtxAH4ADHVxAH4ABgAAAAVxAH4ADnNxAH4ADwAAEj90ABJtaW5lY3JhZnQ6Y3Jvc3Nib3dxAH4AE3EAfgATcHBwcHBzcQB+AABzcQB+AAN1cQB+AAYAAAAFcQB+AAhxAH4ACXEAfgAKcQB+AAtxAH4ADHVxAH4ABgAAAAVxAH4ADnNxAH4ADwAAEj90AA9taW5lY3JhZnQ6YXJyb3dzcQB+AA8AAAAFcQB+ABNwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHA= diff --git a/core/src/main/resources/ladders/mlgrush.yml b/core/src/main/resources/ladders/mlgrush.yml index d9120fffb..8a474e27f 100644 --- a/core/src/main/resources/ladders/mlgrush.yml +++ b/core/src/main/resources/ladders/mlgrush.yml @@ -33,7 +33,7 @@ icon: id: minecraft:stick count: 1 components: - minecraft:custom_name: '"§cMLG Rush"' + minecraft:custom_name: '{"text":"MLG Rush","color":"red"}' schema_version: 1 inventory: rO0ABXcEAAAAJHNyABpvcmcuYnVra2l0LnV0aWwuaW8uV3JhcHBlcvJQR+zxEm8FAgABTAADbWFwdAAPTGphdmEvdXRpbC9NYXA7eHBzcgA1Y29tLmdvb2dsZS5jb21tb24uY29sbGVjdC5JbW11dGFibGVNYXAkU2VyaWFsaXplZEZvcm0AAAAAAAAAAAIAAkwABGtleXN0ABJMamF2YS9sYW5nL09iamVjdDtMAAZ2YWx1ZXNxAH4ABHhwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAABnQAAj09dAALRGF0YVZlcnNpb250AAJpZHQABWNvdW50dAAKY29tcG9uZW50c3QADnNjaGVtYV92ZXJzaW9udXEAfgAGAAAABnQAHm9yZy5idWtraXQuaW52ZW50b3J5Lkl0ZW1TdGFja3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAABI/dAAPbWluZWNyYWZ0OnN0aWNrc3EAfgAQAAAAAXNyABdqYXZhLnV0aWwuTGlua2VkSGFzaE1hcDTATlwQbMD7AgABWgALYWNjZXNzT3JkZXJ4cgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAMdwgAAAAQAAAAAnQAFW1pbmVjcmFmdDpyZXBhaXJfY29zdHQAATF0ABZtaW5lY3JhZnQ6ZW5jaGFudG1lbnRzdAAZeyJtaW5lY3JhZnQ6a25vY2tiYWNrIjoxfXgAcQB+ABRzcQB+AABzcQB+AAN1cQB+AAYAAAAGcQB+AAhxAH4ACXEAfgAKcQB+AAtxAH4ADHEAfgANdXEAfgAGAAAABnEAfgAPc3EAfgAQAAASP3QAGG1pbmVjcmFmdDp3b29kZW5fcGlja2F4ZXEAfgAUc3EAfgAVP0AAAAAAAAx3CAAAABAAAAABdAAWbWluZWNyYWZ0OmVuY2hhbnRtZW50c3QAGnsibWluZWNyYWZ0OmVmZmljaWVuY3kiOjJ9eABxAH4AFHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHA= armor: rO0ABXcEAAAABHBwcHA= diff --git a/core/src/main/resources/ladders/sword.yml b/core/src/main/resources/ladders/sword.yml index 2a74ae683..040d68077 100644 --- a/core/src/main/resources/ladders/sword.yml +++ b/core/src/main/resources/ladders/sword.yml @@ -36,7 +36,7 @@ icon: id: minecraft:diamond_sword count: 1 components: - minecraft:custom_name: '"§bSword"' + minecraft:custom_name: '{"text":"Sword","color":"aqua"}' schema_version: 1 inventory: rO0ABXcEAAAAJHNyABpvcmcuYnVra2l0LnV0aWwuaW8uV3JhcHBlcvJQR+zxEm8FAgABTAADbWFwdAAPTGphdmEvdXRpbC9NYXA7eHBzcgA1Y29tLmdvb2dsZS5jb21tb24uY29sbGVjdC5JbW11dGFibGVNYXAkU2VyaWFsaXplZEZvcm0AAAAAAAAAAAIAAkwABGtleXN0ABJMamF2YS9sYW5nL09iamVjdDtMAAZ2YWx1ZXNxAH4ABHhwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAABXQAAj09dAALRGF0YVZlcnNpb250AAJpZHQABWNvdW50dAAOc2NoZW1hX3ZlcnNpb251cQB+AAYAAAAFdAAeb3JnLmJ1a2tpdC5pbnZlbnRvcnkuSXRlbVN0YWNrc3IAEWphdmEubGFuZy5JbnRlZ2VyEuKgpPeBhzgCAAFJAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cAAAEj90ABdtaW5lY3JhZnQ6ZGlhbW9uZF9zd29yZHNxAH4ADwAAAAFxAH4AE3BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBw armor: rO0ABXcEAAAABHNyABpvcmcuYnVra2l0LnV0aWwuaW8uV3JhcHBlcvJQR+zxEm8FAgABTAADbWFwdAAPTGphdmEvdXRpbC9NYXA7eHBzcgA1Y29tLmdvb2dsZS5jb21tb24uY29sbGVjdC5JbW11dGFibGVNYXAkU2VyaWFsaXplZEZvcm0AAAAAAAAAAAIAAkwABGtleXN0ABJMamF2YS9sYW5nL09iamVjdDtMAAZ2YWx1ZXNxAH4ABHhwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAABnQAAj09dAALRGF0YVZlcnNpb250AAJpZHQABWNvdW50dAAKY29tcG9uZW50c3QADnNjaGVtYV92ZXJzaW9udXEAfgAGAAAABnQAHm9yZy5idWtraXQuaW52ZW50b3J5Lkl0ZW1TdGFja3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAABI/dAAXbWluZWNyYWZ0OmRpYW1vbmRfYm9vdHNzcQB+ABAAAAABc3IAF2phdmEudXRpbC5MaW5rZWRIYXNoTWFwNMBOXBBswPsCAAFaAAthY2Nlc3NPcmRlcnhyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAACdAAVbWluZWNyYWZ0OnJlcGFpcl9jb3N0dAABMXQAFm1pbmVjcmFmdDplbmNoYW50bWVudHN0ABp7Im1pbmVjcmFmdDpwcm90ZWN0aW9uIjozfXgAcQB+ABRzcQB+AABzcQB+AAN1cQB+AAYAAAAGcQB+AAhxAH4ACXEAfgAKcQB+AAtxAH4ADHEAfgANdXEAfgAGAAAABnEAfgAPc3EAfgAQAAASP3QAGm1pbmVjcmFmdDpkaWFtb25kX2xlZ2dpbmdzcQB+ABRzcQB+ABU/QAAAAAAADHcIAAAAEAAAAAJ0ABVtaW5lY3JhZnQ6cmVwYWlyX2Nvc3R0AAExdAAWbWluZWNyYWZ0OmVuY2hhbnRtZW50c3QAGnsibWluZWNyYWZ0OnByb3RlY3Rpb24iOjN9eABxAH4AFHNxAH4AAHNxAH4AA3VxAH4ABgAAAAZxAH4ACHEAfgAJcQB+AApxAH4AC3EAfgAMcQB+AA11cQB+AAYAAAAGcQB+AA9zcQB+ABAAABI/dAAcbWluZWNyYWZ0OmRpYW1vbmRfY2hlc3RwbGF0ZXEAfgAUc3EAfgAVP0AAAAAAAAx3CAAAABAAAAACdAAVbWluZWNyYWZ0OnJlcGFpcl9jb3N0dAABMXQAFm1pbmVjcmFmdDplbmNoYW50bWVudHN0ABp7Im1pbmVjcmFmdDpwcm90ZWN0aW9uIjo0fXgAcQB+ABRzcQB+AABzcQB+AAN1cQB+AAYAAAAGcQB+AAhxAH4ACXEAfgAKcQB+AAtxAH4ADHEAfgANdXEAfgAGAAAABnEAfgAPc3EAfgAQAAASP3QAGG1pbmVjcmFmdDpkaWFtb25kX2hlbG1ldHEAfgAUc3EAfgAVP0AAAAAAAAx3CAAAABAAAAACdAAVbWluZWNyYWZ0OnJlcGFpcl9jb3N0dAABMXQAFm1pbmVjcmFmdDplbmNoYW50bWVudHN0ABp7Im1pbmVjcmFmdDpwcm90ZWN0aW9uIjo0fXgAcQB+ABQ= diff --git a/core/src/main/resources/ladders/tntsumo.yml b/core/src/main/resources/ladders/tntsumo.yml index 048941902..479d127e7 100644 --- a/core/src/main/resources/ladders/tntsumo.yml +++ b/core/src/main/resources/ladders/tntsumo.yml @@ -34,7 +34,7 @@ icon: id: minecraft:tnt count: 1 components: - minecraft:custom_name: '"§cTNT §eSumo"' + minecraft:custom_name: '{"extra":[{"text":"TNT ","color":"red"},{"text":"Sumo","color":"yellow"}],"text":""}' schema_version: 1 inventory: rO0ABXcEAAAAJHNyABpvcmcuYnVra2l0LnV0aWwuaW8uV3JhcHBlcvJQR+zxEm8FAgABTAADbWFwdAAPTGphdmEvdXRpbC9NYXA7eHBzcgA1Y29tLmdvb2dsZS5jb21tb24uY29sbGVjdC5JbW11dGFibGVNYXAkU2VyaWFsaXplZEZvcm0AAAAAAAAAAAIAAkwABGtleXN0ABJMamF2YS9sYW5nL09iamVjdDtMAAZ2YWx1ZXNxAH4ABHhwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAABnQAAj09dAALRGF0YVZlcnNpb250AAJpZHQABWNvdW50dAAKY29tcG9uZW50c3QADnNjaGVtYV92ZXJzaW9udXEAfgAGAAAABnQAHm9yZy5idWtraXQuaW52ZW50b3J5Lkl0ZW1TdGFja3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAABI/dAANbWluZWNyYWZ0OnRudHNxAH4AEAAAAApzcgAXamF2YS51dGlsLkxpbmtlZEhhc2hNYXA0wE5cEGzA+wIAAVoAC2FjY2Vzc09yZGVyeHIAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAADHcIAAAAEAAAAAF0ABVtaW5lY3JhZnQ6Y3VzdG9tX25hbWV0ACciwqc2wqdsSW5zdGEtQm9vbSBUTlQgwqc3KFJpZ2h0IENsaWNrKSJ4AHNxAH4AEAAAAAFzcQB+AABzcQB+AAN1cQB+AAYAAAAFcQB+AAhxAH4ACXEAfgAKcQB+AAtxAH4ADXVxAH4ABgAAAAVxAH4AD3NxAH4AEAAAEj90ABhtaW5lY3JhZnQ6cmVkX3RlcnJhY290dGFzcQB+ABAAAABAcQB+ABpzcQB+AABzcQB+AAN1cQB+AAYAAAAGcQB+AAhxAH4ACXEAfgAKcQB+AAtxAH4ADHEAfgANdXEAfgAGAAAABnEAfgAPc3EAfgAQAAASP3QAGG1pbmVjcmFmdDp3b29kZW5fcGlja2F4ZXEAfgAac3EAfgAVP0AAAAAAAAx3CAAAABAAAAABdAAWbWluZWNyYWZ0OmVuY2hhbnRtZW50c3QAGnsibWluZWNyYWZ0OmVmZmljaWVuY3kiOjJ9eABxAH4AGnBwcHBwc3EAfgAAc3EAfgADdXEAfgAGAAAABXEAfgAIcQB+AAlxAH4ACnEAfgALcQB+AA11cQB+AAYAAAAFcQB+AA9zcQB+ABAAABI/dAAVbWluZWNyYWZ0OmVuZGVyX3BlYXJscQB+ABpxAH4AGnBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcA== armor: rO0ABXcEAAAABHBwcHA= diff --git a/core/src/main/resources/language.yml b/core/src/main/resources/language.yml index cf2f4413d..b98e67e71 100644 --- a/core/src/main/resources/language.yml +++ b/core/src/main/resources/language.yml @@ -1,4 +1,4 @@ -VERSION: 40 +VERSION: 42 CONSOLE-NAME: "Console" CANT-USE-CONSOLE: "You can't use this command from the console." @@ -140,6 +140,7 @@ COMMAND: - " » Set the maximum build height.'>/%label% set buildmax " - " » Set the deadzone Y level.'>/%label% set deadzone " - " » Set the side building limit.'>/%label% set sidebuildlimit " + - " » Set Party FFA center to your location.'>/%label% set partyffacenter " - "------------------------------------------" INFO: COMMAND-HELP: "/%label% info " @@ -163,6 +164,7 @@ COMMAND: - "" - " » Player 2 Position: %position1%" - " » Player 2 Position: %position2%" + - " » Party FFA Center: %partyFfaCenter%" - "" - " » Status: %status%" - "-----------------------------------" @@ -304,6 +306,14 @@ COMMAND: NOT-BUILD: "Arena must be build to set this property." INVALID-NUMBER: "Please give a correctly formatted number between 0 and 10" SET-SIDEBUILDLIMIT: "You set the side build limit for the arena %arena%. Side Build Limit: %sideBuildLimit%" + PARTYFFACENTER: + COMMAND-HELP: "/%label% set partyffacenter " + ARENA-NOT-EXISTS: "%arena% arena doesn't exists." + ARENA-ENABLED: "You can't edit an enabled arena." + CANT-EDIT: "You can't edit arenas that have copies. (%arena%)" + NO-REGION: "You must set the two corners of the arena first." + POS-OUTSIDE-REGION: "The center must be inside the arena cube." + SET: "You set the Party FFA center for arena %arena%." LADDER: NO-PERMISSION: "You don't have permission!" ARGUMENTS: @@ -334,7 +344,7 @@ COMMAND: - "------------------------------------------" CREATE: COMMAND-HELP: "/%label% create " - REACHED-MAX: "The server has reached the maximum number of ladders. (45/45)" + REACHED-MAX: "The server has reached the maximum number of ladders. (%max%/%max%)" DELETE: COMMAND-HELP: "/%label% delete " NOT-EXISTS: "%ladder% ladder doesn't exists." @@ -616,13 +626,19 @@ COMMAND: HOLOGRAM: NO-PERMISSION: "You don't have permission." CANT-USE: "You can't use this right now!" - COMMAND-HELP: "/%label% create " + COMMAND-HELP: + - "/%label% create " + - "/%label% teleport " INVALID-TYPE: "Invalid hologram type. Available types: global, ladder_static, ladder_dynamic" ONLY-IN-LOBBY: "You can only create holograms in the lobby." REACHED-MAX: "You can't create more than 18 holograms." HOLO-EXISTS: "Hologram with this name is already exists." CREATE-ERROR: "Hologram name must be 9 character or less." CREATE-SUCCESS: "You successfully created the %hologram% hologram." + TELEPORT: + COMMAND-HELP: "/%label% teleport " + HOLOGRAM-NOT-EXISTS: "%hologram% hologram doesn't exists." + TELEPORTED: "You moved %hologram% to your current location." MATCH-STAT: COMMAND-HELP: "/matchinv " INVALID-MATCH-ID: "Match id is either invalid or it has expired." @@ -695,7 +711,7 @@ COMMAND: NO-INVITES: "%target% doesn't accept party invites." ALREADY-INVITED: "%target% is already invited to the party." PLAYER-INVITED: "%target% has been invited to the party!" - PLAYER-GOT-INVITE: "%inviter% has invited you to their party. Click here to accept the invite.'>&a[ACCEPT]" + PLAYER-GOT-INVITE: "%inviter% has invited you to their party. Click here to accept the invite.'>[ACCEPT]" KICK: COMMAND-HELP: "/%label% kick " NO-PARTY: "You are not a member of a party." @@ -745,6 +761,7 @@ COMMAND: - " » /%label% lobby set - Set lobby location." - " » /%label% lobby load - Load lobby inventory." - " » /%label% arenas - Teleport to arenas world." + - " » /%label% hologram - Manage practice holograms." - " » /%label% rename - Rename the item in your hand." - " » /%label% info - View player's info." - " » /%label% goldenhead - Get some golden heads." @@ -910,7 +927,7 @@ COMMAND: ARENAS-WORLD: "You must be in the arenas world to set up the event." SET-FIRST-CORNER: "You set the first corner for the %event% event." SET-SECOND-CORNER: "You set the seconds corner for the %event% event." - MAP-SET: "You have successfully selected the area for the %event% event&a." + MAP-SET: "You have successfully selected the area for the %event% event." HOLOGRAM: CANT-EDIT-ENABLED: "You can't edit enabled holograms." NO-REQUIREMENTS: "Hologram doesn't meet the requirements." @@ -973,14 +990,14 @@ COMMAND: PLAYER: "You removed %target% as spectator." TARGET: "You've got removed from spectating by %player%." HELP: - - "&c&m------------------------------------------------" - - " &c » /%label% enable - Enable staff mode." - - " &c » /%label% chat - Toggle staff chat." - - " &c » /%label% chat - Send message in staff chat." # Console - - " &c » /%label% vanish - Toggle visibility." - - " &c » /%label% forceend - Force end any match or event." # Console - - " &c » /%label% stop - Remove a player from a match or event." # Console - - "&c&m------------------------------------------------" + - "------------------------------------------------" + - " » /%label% enable - Enable staff mode." + - " » /%label% chat - Toggle staff chat." + - " » /%label% chat - Send message in staff chat." # Console + - " » /%label% vanish - Toggle visibility." + - " » /%label% forceend - Force end any match or event." # Console + - " » /%label% stop - Remove a player from a match or event." # Console + - "------------------------------------------------" VANISH: COMMAND-HELP: "/%label% vanish" CANT-USE: "You can't use this command right now." @@ -1460,15 +1477,15 @@ MATCH: BED-WARS: RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" FIREBALL-FIGHT: RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" MLG-RUSH: RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" BATTLE-RUSH: RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." @@ -1573,15 +1590,15 @@ MATCH: BED-WARS: RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" FIREBALL-FIGHT: RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" MLG-RUSH: RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" BATTLE-RUSH: RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." @@ -1636,17 +1653,17 @@ MATCH: PLAYER-DIED: "%teamColor%%player% has died." RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" FIREBALL-FIGHT: PLAYER-DIED: "%teamColor%%player% has died." RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" MLG-RUSH: PLAYER-DIED: "%teamColor%%player% has died." RESPAWN: "You will respawn in %seconds% %secondName%." PLAYER-RESPAWNED: "%teamColor%%player% has respawned." - BED-DESTROYED: "%team% team's &ebed has been destroyed!" + BED-DESTROYED: "%team% team's bed has been destroyed!" BATTLE-RUSH: PLAYER-DIED: "%teamColor%%player% has died." RESPAWN: "You will respawn in %seconds% %secondName%." diff --git a/core/src/main/resources/playerkit.yml b/core/src/main/resources/playerkit.yml index b2333cb26..dce49e9bd 100644 --- a/core/src/main/resources/playerkit.yml +++ b/core/src/main/resources/playerkit.yml @@ -2,82 +2,82 @@ VERSION: 4 GUI: MAIN: - TITLE: "&8%name%" + TITLE: "%name%" ICONS: BACK-TO: - NAME: "&7&lBack" + NAME: "Back" MATERIAL: ARROW LORE: - - "&7Click to go back" + - "Click to go back" CUSTOM-SETTINGS: - NAME: "&bCustom Settings" + NAME: "Custom Settings" MATERIAL: COMPARATOR GUIDE: - NAME: "&b&lGuide" + NAME: "Guide" MATERIAL: PAPER LORE: - - "&fLeft click to change item" - - "&fShit left click to remove item" - - "&fRight click to enchant or change count" - - "&fShift right click to copy or paste item" + - "Left click to change item" + - "Shit left click to remove item" + - "Right click to enchant or change count" + - "Shift right click to copy or paste item" RESET-KIT: - NAME: "&cReset Kit" + NAME: "Reset Kit" MATERIAL: GUNPOWDER CHANGE-NAME: - NAME: "&bChange the name of kit" + NAME: "Change the name of kit" MATERIAL: NAME_TAG SHARE-KIT: - NAME: "&bShare Kit" + NAME: "Share Kit" MATERIAL: OAK_SIGN KIT-SLOT-PLACEHOLDERS: HEAD: - NAME: "&7Head" + NAME: "Head" MATERIAL: BLUE_STAINED_GLASS_PANE LORE: - - "&3Click to add" + - "Click to add" CHEST: - NAME: "&7Chest" + NAME: "Chest" MATERIAL: BLUE_STAINED_GLASS_PANE LORE: - - "&3Click to add" + - "Click to add" LEGS: - NAME: "&7Legs" + NAME: "Legs" MATERIAL: BLUE_STAINED_GLASS_PANE LORE: - - "&3Click to add" + - "Click to add" BOOTS: - NAME: "&7Feet" + NAME: "Feet" MATERIAL: BLUE_STAINED_GLASS_PANE LORE: - - "&3Click to add" + - "Click to add" OFFHAND: - NAME: "&7Offhand" + NAME: "Offhand" MATERIAL: BLUE_STAINED_GLASS_PANE LORE: - - "&3Click to add" + - "Click to add" HOTBAR: - NAME: "&7None" + NAME: "None" MATERIAL: LIGHT_BLUE_STAINED_GLASS_PANE LORE: - - "&3Click to add" + - "Click to add" OTHER-INVENTORY: - NAME: "&7None" + NAME: "None" MATERIAL: GRAY_STAINED_GLASS_PANE LORE: - - "&3Click to add" + - "Click to add" MAIN-ARMOR: - TITLE: "&8Armor" + TITLE: "Armor" SIZE: 6 ICONS: OFFICIAL: BACK-TO: - NAME: "&7&lBack" + NAME: "Back" MATERIAL: ARROW SLOT: 45 LORE: - - "&7Click to go back" + - "Click to go back" NONE: - NAME: "&7None" + NAME: "None" SLOT: 18 MATERIAL: GRAY_STAINED_GLASS_PANE HELMETS: @@ -166,212 +166,212 @@ GUI: MATERIAL: NETHERITE_BOOTS SLOT: 24 CUSTOM-SETTINGS: - TITLE: "&8Settings" + TITLE: "Settings" ICONS: NAV: GO-BACK: - NAME: "&cGo Back" + NAME: "Go Back" MATERIAL: ARROW NORMAL-SETTINGS: REGENERATION: ENABLED: - NAME: "&7Regeneration: &aEnabled" + NAME: "Regeneration: Enabled" MATERIAL: GLOWSTONE_DUST LORE: - "" - - "&7Players health is automatically regenerate." + - "Players health is automatically regenerate." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Regeneration: &cDisabled" + NAME: "Regeneration: Disabled" MATERIAL: GLOWSTONE_DUST LORE: - "" - - "&7Players health is not regenerate." + - "Players health is not regenerate." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." HUNGER: ENABLED: - NAME: "&7Hunger: &aEnabled" + NAME: "Hunger: Enabled" MATERIAL: COOKED_BEEF LORE: - "" - - "&7Players starve during the game." + - "Players starve during the game." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Hunger: &cDisabled" + NAME: "Hunger: Disabled" MATERIAL: COOKED_BEEF LORE: - "" - - "&7Players don't starve." + - "Players don't starve." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." BUILD: ENABLED: - NAME: "&7Build: &aEnabled" + NAME: "Build: Enabled" MATERIAL: DIAMOND_PICKAXE LORE: - "" - - "&7Players can build during the game." + - "Players can build during the game." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Build: &cDisabled" + NAME: "Build: Disabled" MATERIAL: DIAMOND_PICKAXE LORE: - "" - - "&7Players can't build." + - "Players can't build." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." ROUNDS: - NAME: "&7Rounds: &6%rounds%" + NAME: "Rounds: %rounds%" MATERIAL: FIRE_CHARGE LORE: - "" - - "&7The first player/team to reach" - - "&7the, winning rounds wins." + - "The first player/team to reach" + - "the, winning rounds wins." - "" - - "&a&lLEFT-CLICK &ato reduce the rounds." - - "&b&lRIGHT-CLICK &bto increase the rounds." + - "LEFT-CLICK to reduce the rounds." + - "RIGHT-CLICK to increase the rounds." KNOCKBACK: - NAME: "&eKnockback Modifier" + NAME: "Knockback Modifier" MATERIAL: STICK LORE: - "" - "%knockbackTypes%" HITDELAY: - NAME: "&7Attack Cooldown: &6%hitdelay%x" + NAME: "Attack Cooldown: %hitdelay%x" MATERIAL: DIAMOND_SWORD LORE: - "" - - "&71.0 = Normal speed (20 ticks)" - - "&70.5 = 2x faster" - - "&72.0 = 2x slower" + - "1.0 = Normal speed (20 ticks)" + - "0.5 = 2x faster" + - "2.0 = 2x slower" - "" - - "&c&lNote: &71 sec = 20 tick" + - "Note: 1 sec = 20 tick" - "" - - "&a&lLEFT-CLICK &ato reduce the rounds." - - "&b&lRIGHT-CLICK &bto increase the rounds." + - "LEFT-CLICK to reduce the rounds." + - "RIGHT-CLICK to increase the rounds." ENDERPEARL-COOLDOWN: - NAME: "&7EnderPearl Cooldown: &6%epCooldown% sec" + NAME: "EnderPearl Cooldown: %epCooldown% sec" MATERIAL: ENDER_PEARL LORE: - "" - - "&7Players must wait this long before" - - "&7they can throw the next enderpearl." + - "Players must wait this long before" + - "they can throw the next enderpearl." - "" - - "&a&lLEFT-CLICK &ato reduce the cooldown." - - "&b&lRIGHT-CLICK &bto increase the cooldown." + - "LEFT-CLICK to reduce the cooldown." + - "RIGHT-CLICK to increase the cooldown." GOLDENAPPLE-COOLDOWN: - NAME: "&7Golden Apple Cooldown: &6%gaCooldown%" + NAME: "Golden Apple Cooldown: %gaCooldown%" MATERIAL: GOLDEN_APPLE LORE: - "" - - "&7Players must wait this long before" - - "&7they can consume the next golden apple." + - "Players must wait this long before" + - "they can consume the next golden apple." - "" - - "&7This setting includes both enchanted" - - "&7and non-enchanted golden apples." + - "This setting includes both enchanted" + - "and non-enchanted golden apples." - "" - - "&a&lLEFT-CLICK &ato reduce the cooldown." - - "&b&lRIGHT-CLICK &bto increase the cooldown." + - "LEFT-CLICK to reduce the cooldown." + - "RIGHT-CLICK to increase the cooldown." WIND-CHARGE-COOLDOWN: - NAME: "&7Wind Charge Cooldown: &6%windChargeCooldown% sec" + NAME: "Wind Charge Cooldown: %windChargeCooldown% sec" MATERIAL: WIND_CHARGE LORE: - "" - - "&7Players must wait this long before" - - "&7they can launch the next wind charge." + - "Players must wait this long before" + - "they can launch the next wind charge." - "" - - "&a&lLEFT-CLICK &ato reduce the cooldown." - - "&b&lRIGHT-CLICK &bto increase the cooldown." + - "LEFT-CLICK to reduce the cooldown." + - "RIGHT-CLICK to increase the cooldown." HEALTH-BELOW-NAME: ENABLED: - NAME: "&7Health Below Name: &aEnabled" + NAME: "Health Below Name: Enabled" MATERIAL: RED_DYE LORE: - "" - - "&7Players will display their hearts" - - "&7during the match." + - "Players will display their hearts" + - "during the match." - "" - - "&e&lClick here &7to &cdisable&7." + - "Click here to disable." DISABLED: - NAME: "&7Health Below Name: &cDisabled" + NAME: "Health Below Name: Disabled" MATERIAL: RED_DYE LORE: - "" - - "&7Players will display their hearts" - - "&7during the match." + - "Players will display their hearts" + - "during the match." - "" - - "&e&lClick here &7to &aenable&7." + - "Click here to enable." ITEMS: CATEGORY-GUI: - TITLE: "&8Item categories" + TITLE: "Item categories" SIZE: 6 ICONS: BACK-TO: - NAME: "&7&lBack" + NAME: "Back" MATERIAL: ARROW SLOT: 45 LORE: - - "&7Click to go back" + - "Click to go back" NONE: - NAME: "&bNone" + NAME: "None" MATERIAL: GRAY_STAINED_GLASS_PANE SLOT: 18 ARMOR: - NAME: "&bArmor" + NAME: "Armor" MATERIAL: DIAMOND_CHESTPLATE SLOT: 19 WEAPONS-TOOLS: - NAME: "&bWeapons & Tools" + NAME: "Weapons & Tools" MATERIAL: IRON_SWORD SLOT: 20 BOWS-ARROWS: - NAME: "&bBows & Arrows" + NAME: "Bows & Arrows" MATERIAL: BOW SLOT: 21 POTIONS: - NAME: "&bPotions" + NAME: "Potions" MATERIAL: POTION SLOT: 22 SHULKER-BOXES: - NAME: "&bShulker Boxes" + NAME: "Shulker Boxes" MATERIAL: PURPLE_SHULKER_BOX SLOT: 32 # ── Custom categories ────────────────────────────────────────────────── # Any key added here (that isn't a built-in) becomes a custom category. # Add a matching entry under ITEMS-GUI.CATEGORIES with TITLE and ITEMS. FOOD: - NAME: "&bFood" + NAME: "Food" MATERIAL: COOKED_BEEF SLOT: 23 BLOCKS: - NAME: "&bBlocks" + NAME: "Blocks" MATERIAL: COBBLESTONE SLOT: 24 ITEMS-GUI: SIZE: 6 OFFICIAL-ICONS: BACK-TO: - NAME: "&7&lBack" + NAME: "Back" MATERIAL: ARROW LORE: - - "&7Click to go back" + - "Click to go back" NEXT-PAGE: - NAME: "&7&lNext Page" + NAME: "Next Page" MATERIAL: ARROW LORE: - - "&7Click" + - "Click" PREVIOUS-PAGE: - NAME: "&7&lPrevious Page" + NAME: "Previous Page" MATERIAL: ARROW LORE: - - "&7Click" + - "Click" CATEGORIES: ARMOR: - TITLE: "&8Armor" + TITLE: "Armor" ITEMS: - "LEATHER_HELMET" - "GOLDEN_HELMET" @@ -407,7 +407,7 @@ GUI: - "DIAMOND_BOOTS" - "NETHERITE_BOOTS" WEAPONS-TOOLS: - TITLE: "&8Weapons and Tools" + TITLE: "Weapons and Tools" ITEMS: - "WOODEN_SWORD" - "GOLDEN_SWORD" @@ -455,7 +455,7 @@ GUI: - "SNOWBALL" - "FIREWORK_ROCKET" BOWS-ARROWS: - TITLE: "&8Bows and Arrows" + TITLE: "Bows and Arrows" ITEMS: - "BOW" - "CROSSBOW" @@ -500,18 +500,18 @@ GUI: - "TIPPED_ARROW::SLOW_FALLING" - "TIPPED_ARROW::LONG_SLOW_FALLING" POTION: - TITLE: "&8Potions" + TITLE: "Potions" OFFICIAL-ICONS: BACK-TO: - NAME: "&7&lBack" + NAME: "Back" MATERIAL: ARROW LORE: - - "&7Click to go back" + - "Click to go back" SWITCH-TO-SPLASH: - NAME: "&bShow splash potions" + NAME: "Show splash potions" MATERIAL: SPLASH_POTION SWITCH-TO-DRINKABLE: - NAME: "&bShow drinkable potions" + NAME: "Show drinkable potions" MATERIAL: POTION DRINKABLE-POTIONS: ITEMS: @@ -594,7 +594,7 @@ GUI: - "SPLASH_POTION::SLOW_FALLING" - "SPLASH_POTION::LONG_SLOW_FALLING" FOOD: - TITLE: "&8Food" + TITLE: "Food" ITEMS: - "APPLE" - "MUSHROOM_STEW" @@ -637,7 +637,7 @@ GUI: - "GLOW_BERRIES" - "HONEY_BOTTLE" BLOCKS: - TITLE: "&8Blocks" + TITLE: "Blocks" ITEMS: - "OBSIDIAN" - "ANVIL" @@ -708,58 +708,58 @@ GUI: - "MOSS_BLOCK" - "STONE" SHULKER-BOXES: - TITLE: "&8Shulker Boxes" + TITLE: "Shulker Boxes" ENCHANT-GUI: - TITLE: "&8Add enchantments" + TITLE: "Add enchantments" ICONS: BACK-TO: - NAME: "&7&lBack" + NAME: "Back" MATERIAL: ARROW LORE: - - "&7Click to go back" + - "Click to go back" MAKE-UNBREAKABLE: - NAME: "&bMake unbreakable" + NAME: "Make unbreakable" MATERIAL: STONE_BRICKS MAKE-BREAKABLE: - NAME: "&bMake breakable" + NAME: "Make breakable" MATERIAL: STONE_BRICKS CLEAR-ENCHANTS: - NAME: "&bClear Enchants" + NAME: "Clear Enchants" MATERIAL: BARRIER CHANGE-DURABILITY: - NAME: "&bChange Durability" + NAME: "Change Durability" MATERIAL: ANVIL SET-ENCHANTMENT-LEVEL: - NAME: "&d%enchantment% &7- &e%level%" + NAME: "%enchantment% - %level%" MATERIAL: SUGAR LORE: - - "&8&m------------------------" - - "&7Click here to set the level of" - - "&7the &d%enchantment% &7enchantment." - - "&8&m------------------------" + - "------------------------" + - "Click here to set the level of" + - "the %enchantment% enchantment." + - "------------------------" SET-ENCHANTMENT-LEVEL-PLACEHOLDER: NAME: " " MATERIAL: BLUE_STAINED_GLASS_PANE ENCHANTMENT-ICON: - NAME: "&d%enchantment%" + NAME: "%enchantment%" MATERIAL: ENCHANTED_BOOK LORE: - - "&8&m------------------------" - - "&7Click here to select" - - "&7the &d%enchantment% &7enchantment." - - "&8&m------------------------" + - "------------------------" + - "Click here to select" + - "the %enchantment% enchantment." + - "------------------------" CUSTOM-DURABILITY-GUI: TITLE: "1-%max%" CHANGE-COUNT-GUI: - TITLE: "&8Change item count" + TITLE: "Change item count" ICONS: BACK-TO: - NAME: "&7&lBack" + NAME: "Back" MATERIAL: ARROW LORE: - - "&7Click to go back" + - "Click to go back" CUSTOM-COUNT: - NAME: "&bCustom Amount" + NAME: "Custom Amount" MATERIAL: PAPER CUSTOM-COUNT-GUI: TITLE: "Enter a number 1-%max%" diff --git a/core/src/main/resources/sidebar.yml b/core/src/main/resources/sidebar.yml index 58352d4b6..9b405ca1f 100644 --- a/core/src/main/resources/sidebar.yml +++ b/core/src/main/resources/sidebar.yml @@ -1,4 +1,4 @@ -VERSION: 5 +VERSION: 6 TITLE: "PRACTICE" LOBBY: @@ -101,6 +101,7 @@ LOBBY: ######################################################################## MATCH: ROUND-SYMBOL: "⬤" + ROUND-SYMBOL-MAX-ROUNDS: 3 # If wins-needed is above this, show rounds as won/total instead of repeated symbols. BED-STATUS: NOT-DESTROYED: "✓" DESTROYED: "✗" @@ -969,4 +970,4 @@ GROUP-EXTENSIONS: - "---------------------" SUPREME: - "Rank: Supreme" - - "---------------------" \ No newline at end of file + - "---------------------" diff --git a/distribution/pom.xml b/distribution/pom.xml index a6135c218..5334d0597 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -10,7 +10,7 @@ dev.nandi0813 practice-parent - 7.5.0-SNAPSHOT + 7.6.0-SNAPSHOT @@ -113,6 +113,10 @@ com.zaxxer.hikari dev.nandi0813.practice.dependencies.hikari + + org.mariadb.jdbc + dev.nandi0813.practice.dependencies.mariadb + diff --git a/pom.xml b/pom.xml index 4e5204413..b92d0ca0f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ dev.nandi0813 practice-parent - 7.5.0-SNAPSHOT + 7.6.0-SNAPSHOT pom ZonePractice Pro @@ -117,7 +117,7 @@ com.github.retrooper packetevents-spigot - 2.12.0 + 2.12.1 provided @@ -138,7 +138,7 @@ net.wesjd anvilgui - 1.10.12-SNAPSHOT + 1.10.13-SNAPSHOT