diff --git a/module/placeholderapi-integration/src/main/java/org/battleplugins/arena/module/placeholderapi/BattleArenaExpansion.java b/module/placeholderapi-integration/src/main/java/org/battleplugins/arena/module/placeholderapi/BattleArenaExpansion.java index e2a89ae4..9695fa1d 100644 --- a/module/placeholderapi-integration/src/main/java/org/battleplugins/arena/module/placeholderapi/BattleArenaExpansion.java +++ b/module/placeholderapi-integration/src/main/java/org/battleplugins/arena/module/placeholderapi/BattleArenaExpansion.java @@ -5,6 +5,9 @@ import org.battleplugins.arena.ArenaPlayer; import org.battleplugins.arena.BattleArena; import org.battleplugins.arena.competition.Competition; +import org.battleplugins.arena.competition.LiveCompetition; +import org.battleplugins.arena.competition.map.CompetitionMap; +import org.battleplugins.arena.competition.map.LiveCompetitionMap; import org.battleplugins.arena.competition.phase.CompetitionPhaseType; import org.battleplugins.arena.resolver.Resolver; import org.battleplugins.arena.resolver.ResolverKey; @@ -13,6 +16,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + public class BattleArenaExpansion extends PlaceholderExpansion { private final BattleArena plugin; @@ -68,6 +73,31 @@ public BattleArenaExpansion(BattleArena plugin) { // Remaining text in split array String placeholder = String.join("_", split).substring(arenaName.length() + 1); + if (placeholder.startsWith("map")) { + placeholder = placeholder.substring("map_".length()); + + // Next value after map_ is the actual placeholder + String mapName = placeholder.split("_")[0]; + List> competitions = this.plugin.getCompetitions(arena, mapName); + if (competitions.isEmpty()) { + return null; + } + + placeholder = placeholder.substring(mapName.length() + 1); + + // Just get the first competition for now + Competition competition = competitions.get(0); + if (!(competition instanceof LiveCompetition liveCompetition)) { + return null; + } + + Resolver resolver = liveCompetition.resolve(); + ResolverKey resolverKey = ResolverKeys.get(placeholder.replace("_", "-")); + if (resolverKey != null && resolver.has(resolverKey)) { + return resolver.resolveToString(resolverKey); + } + } + switch (placeholder) { case "active_competitions": { return String.valueOf(this.plugin.getCompetitions(arena).size()); diff --git a/plugin/src/main/java/org/battleplugins/arena/ArenaPlayer.java b/plugin/src/main/java/org/battleplugins/arena/ArenaPlayer.java index b1281849..38d91411 100644 --- a/plugin/src/main/java/org/battleplugins/arena/ArenaPlayer.java +++ b/plugin/src/main/java/org/battleplugins/arena/ArenaPlayer.java @@ -335,7 +335,7 @@ public static Optional arenaPlayer(Player player) { */ @Nullable public static ArenaPlayer getArenaPlayer(Player player) { - if (!player.hasMetadata(ARENA_PLAYER_META_KEY)) { + if (player == null || !player.hasMetadata(ARENA_PLAYER_META_KEY)) { return null; } diff --git a/plugin/src/main/java/org/battleplugins/arena/competition/CompetitionManager.java b/plugin/src/main/java/org/battleplugins/arena/competition/CompetitionManager.java index 5a1f9463..303a92f4 100644 --- a/plugin/src/main/java/org/battleplugins/arena/competition/CompetitionManager.java +++ b/plugin/src/main/java/org/battleplugins/arena/competition/CompetitionManager.java @@ -45,7 +45,7 @@ public List> getCompetitions(Arena arena) { public List> getCompetitions(Arena arena, String name) { List> competitions = this.getCompetitions(arena); return competitions.stream() - .filter(competition -> competition.getMap().getName().equals(name)) + .filter(competition -> competition.getMap().getName().equalsIgnoreCase(name)) .toList(); } @@ -105,7 +105,7 @@ public CompletableFuture getOrCreateCompetition(Arena arena, continue; } - if ((name == null || map.getName().equals(name))) { + if ((name == null || map.getName().equalsIgnoreCase(name))) { Competition competition = map.createDynamicCompetition(arena); if (competition == null) { this.plugin.warn("Failed to create dynamic competition for map {} in arena {}!", map.getName(), arena.getName()); diff --git a/plugin/src/main/java/org/battleplugins/arena/competition/PlayerStorage.java b/plugin/src/main/java/org/battleplugins/arena/competition/PlayerStorage.java index 55666902..275206cc 100644 --- a/plugin/src/main/java/org/battleplugins/arena/competition/PlayerStorage.java +++ b/plugin/src/main/java/org/battleplugins/arena/competition/PlayerStorage.java @@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.BitSet; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -45,8 +46,8 @@ public class PlayerStorage { private final Collection effects = new ArrayList<>(); private Location lastLocation; - - private boolean stored; + + private final BitSet stored = new BitSet(); public PlayerStorage(ArenaPlayer player) { this.player = player; @@ -58,15 +59,16 @@ public PlayerStorage(ArenaPlayer player) { * @param toStore the types to store */ public void store(Set toStore, boolean clearState) { - if (this.stored) { - return; - } - for (Type type : toStore) { + if (this.stored.get(type.ordinal())) { + BattleArena.getInstance().warn("Type {} is already stored for player {}.", type, this.player.getPlayer().getName()); + continue; + } + type.store(this); + this.stored.set(type.ordinal()); } - this.stored = true; if (clearState) { this.clearState(toStore); } @@ -147,26 +149,26 @@ private void storeLocation() { * @param toRestore the types to restore */ public void restore(Set toRestore) { - if (!this.stored) { - return; - } - for (Type type : toRestore) { + if (!this.stored.get(type.ordinal())) { + BattleArena.getInstance().warn("Type {} is not stored for player {}.", type, this.player.getPlayer().getName()); + continue; + } + type.restore(this); + this.stored.clear(type.ordinal()); } // Reset everything we have in this class - this.inventory = null; - this.attributes.clear(); - this.health = 0; - this.hunger = 0; - this.totalExp = 0; - this.exp = 0; - this.expLevels = 0; - this.effects.clear(); - this.lastLocation = null; - - this.stored = false; + if (toRestore.contains(Type.INVENTORY)) this.inventory = null; + if (toRestore.contains(Type.ATTRIBUTES)) this.attributes.clear(); + if (toRestore.contains(Type.HEALTH)) this.health = 0; + if (toRestore.contains(Type.HEALTH)) this.hunger = 0; + if (toRestore.contains(Type.EXPERIENCE)) this.totalExp = 0; + if (toRestore.contains(Type.EXPERIENCE)) this.exp = 0; + if (toRestore.contains(Type.EXPERIENCE)) this.expLevels = 0; + if (toRestore.contains(Type.EFFECTS)) this.effects.clear(); + if (toRestore.contains(Type.LOCATION)) this.lastLocation = null; } private void restoreAll() { diff --git a/plugin/src/main/java/org/battleplugins/arena/event/action/types/RestoreAction.java b/plugin/src/main/java/org/battleplugins/arena/event/action/types/RestoreAction.java index ab5865f5..25934f3d 100644 --- a/plugin/src/main/java/org/battleplugins/arena/event/action/types/RestoreAction.java +++ b/plugin/src/main/java/org/battleplugins/arena/event/action/types/RestoreAction.java @@ -5,6 +5,7 @@ import org.battleplugins.arena.competition.PlayerStorage; import org.battleplugins.arena.resolver.Resolvable; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -20,7 +21,7 @@ public void call(ArenaPlayer arenaPlayer, Resolvable resolvable) { String[] types = this.get(TYPES_KEY).split(","); PlayerStorage.Type[] toStore = new PlayerStorage.Type[types.length]; for (int i = 0; i < types.length; i++) { - toStore[i] = PlayerStorage.Type.valueOf(types[i].toUpperCase()); + toStore[i] = PlayerStorage.Type.valueOf(types[i].toUpperCase(Locale.ROOT)); } arenaPlayer.getStorage().restore(Set.of(toStore)); diff --git a/plugin/src/main/java/org/battleplugins/arena/event/action/types/StoreAction.java b/plugin/src/main/java/org/battleplugins/arena/event/action/types/StoreAction.java index 56efe1e0..f75b1427 100644 --- a/plugin/src/main/java/org/battleplugins/arena/event/action/types/StoreAction.java +++ b/plugin/src/main/java/org/battleplugins/arena/event/action/types/StoreAction.java @@ -5,6 +5,7 @@ import org.battleplugins.arena.competition.PlayerStorage; import org.battleplugins.arena.resolver.Resolvable; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -21,7 +22,7 @@ public void call(ArenaPlayer arenaPlayer, Resolvable resolvable) { String[] types = this.get(TYPES_KEY).split(","); PlayerStorage.Type[] toStore = new PlayerStorage.Type[types.length]; for (int i = 0; i < types.length; i++) { - toStore[i] = PlayerStorage.Type.valueOf(types[i].toUpperCase()); + toStore[i] = PlayerStorage.Type.valueOf(types[i].toUpperCase(Locale.ROOT)); } boolean clearState = Boolean.parseBoolean(this.getOrDefault(CLEAR_STATE, "true")); diff --git a/plugin/src/main/java/org/battleplugins/arena/util/Util.java b/plugin/src/main/java/org/battleplugins/arena/util/Util.java index e254b977..c79f4b7f 100644 --- a/plugin/src/main/java/org/battleplugins/arena/util/Util.java +++ b/plugin/src/main/java/org/battleplugins/arena/util/Util.java @@ -3,7 +3,6 @@ import org.battleplugins.arena.BattleArena; import org.battleplugins.arena.config.ArenaOption; import org.battleplugins.arena.messages.Messages; -import org.bukkit.Bukkit; import java.io.File; import java.io.IOException; @@ -12,7 +11,10 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; import java.time.Duration; +import java.util.Arrays; import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -174,7 +176,10 @@ public static void copyDirectories(File jarFile, Path outputPath, String directo Path relativePath = directoryPath.relativize(path); Path targetPath = outputPath.resolve(relativePath.toString()); if (Files.exists(targetPath)) { - return; + // Check hashes - if different, copy from jar + if (Arrays.equals(getHash(path), getHash(targetPath))) { + return; + } } for (String ignoredFile : ignoredFiles) { @@ -185,7 +190,7 @@ public static void copyDirectories(File jarFile, Path outputPath, String directo try { Files.createDirectories(targetPath.getParent()); - Files.copy(path, targetPath); + Files.copy(path, targetPath, StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { BattleArena.getInstance().error("Failed to copy module {}!", path.getFileName(), e); } @@ -197,23 +202,15 @@ public static void copyDirectories(File jarFile, Path outputPath, String directo } } - public static String getNmsPackage() { - String NMS; + private static byte[] getHash(Path path) { + byte[] sha256; + try { - // This fails for versions without an NMS package - NMS = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; - } catch (ArrayIndexOutOfBoundsException ex) { - NMS = createCompatPackage(); + sha256 = MessageDigest.getInstance("SHA-256").digest(Files.readAllBytes(path)); + } catch (Exception e) { + throw new RuntimeException("Could not calculate pack hash", e); } - return NMS; - } - private static String createCompatPackage() { - String fullVersion = Bukkit.getBukkitVersion(); - String[] parts = fullVersion.split("-"); - String version = parts[0]; - version = version.replace(".", "_"); - version = "v" + version; - return version; + return sha256; } }