From 5bcab8fa46e8c1f41ed3e572b4bbca7e25f79022 Mon Sep 17 00:00:00 2001 From: Andreas Troelsen Date: Sun, 1 Nov 2020 14:01:38 +0100 Subject: [PATCH] Use arena class slugs for class selection. This commit is a minor refactoring of the class selection functionality plugin-wide. Instead of selecting classes based on the "lowercase name" of a class, commands and listeners are now "slug aware", as it were. The ArenaClass class now uses its slug instead of its "lowercase name" for equality and hash codes. The `/ma class` command now tab completes slugs, but it still supports class names as they appear in the config-file when executing the command itself. The same applies to the `/ma classchest` command. The sign handling in ArenaListener slugifies sign text instead of just lowercasing and stripping spaces. --- changelog.md | 1 + .../com/garbagemule/MobArena/ArenaClass.java | 9 ++++---- .../com/garbagemule/MobArena/ArenaImpl.java | 9 ++++---- .../garbagemule/MobArena/ArenaListener.java | 22 ++++++++++--------- .../garbagemule/MobArena/ArenaMasterImpl.java | 5 ++--- .../commands/setup/ClassChestCommand.java | 10 +++++---- .../commands/user/PickClassCommand.java | 19 ++++++++-------- .../MobArena/util/ClassChests.java | 6 ++--- 8 files changed, 43 insertions(+), 38 deletions(-) diff --git a/changelog.md b/changelog.md index 890c345..dcd7913 100644 --- a/changelog.md +++ b/changelog.md @@ -24,6 +24,7 @@ These changes will (most likely) be included in the next version. - New command `/ma addreward ` can be used to add a reward to an arena player's reward list. This can be useful for hooking into the rewards system from scripts or other plugins. - The Root Target ability now uses potion effects (slowness, slow falling, and negative jump boost) instead of repeated teleports. This should make for a smoother root experience. - Permissions for arenas and classes are now based on "slugs". It is now possible to configure permissions for arenas and classes with multi-word names (including "My Items"). Check the Permissions page on the wiki for details. +- Commands that resolve class names now consistently resolve and tab complete "slugs" instead of arbitrarily "squashed" names. This greatly improves support for multi-word names. - Using `spectate-on-death: true` no longer forces players out to their join location/exit warp before moving them to the spectator area. This should prevent "jumpy" behavior in multi-world setups. - Players should now properly respawn at the spectator area rather than at world spawn on servers with plugins that override respawn locations. - Config-files with missing `pet-items` nodes no longer errors. A missing `pet-items` node in `global-settings` is treated as empty, i.e. no pet items will be registered. diff --git a/src/main/java/com/garbagemule/MobArena/ArenaClass.java b/src/main/java/com/garbagemule/MobArena/ArenaClass.java index a809ba0..bf4d030 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaClass.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaClass.java @@ -16,7 +16,7 @@ import java.util.stream.IntStream; public class ArenaClass { - private String configName, lowercaseName; + private String configName; private String slug; private Thing helmet, chestplate, leggings, boots, offhand; private List armor; @@ -35,7 +35,6 @@ public class ArenaClass public ArenaClass(String name, Thing price, boolean unbreakableWeapons, boolean unbreakableArmor) { this.configName = name; this.slug = Slugs.create(name); - this.lowercaseName = name.toLowerCase().replace(" ", ""); this.items = new ArrayList<>(); this.armor = new ArrayList<>(4); @@ -72,7 +71,7 @@ public class ArenaClass */ @Deprecated public String getLowercaseName() { - return lowercaseName; + return slug; } /** @@ -238,12 +237,12 @@ public class ArenaClass if (!this.getClass().equals(o.getClass())) return false; ArenaClass other = (ArenaClass) o; - return other.lowercaseName.equals(this.lowercaseName); + return other.slug.equals(this.slug); } @Override public int hashCode() { - return lowercaseName.hashCode(); + return slug.hashCode(); } public static class MyItems extends ArenaClass { diff --git a/src/main/java/com/garbagemule/MobArena/ArenaImpl.java b/src/main/java/com/garbagemule/MobArena/ArenaImpl.java index 87e0455..f503256 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaImpl.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaImpl.java @@ -757,7 +757,8 @@ public class ArenaImpl implements Arena if (defaultClass != null) { // Assign default class if applicable if (!ClassChests.assignClassFromStoredClassChest(this, p, defaultClass)) { - assignClass(p, defaultClass.getLowercaseName()); + String slug = defaultClass.getSlug(); + assignClass(p, slug); messenger.tell(p, Msg.LOBBY_CLASS_PICKED, defaultClass.getConfigName()); } } @@ -1319,10 +1320,10 @@ public class ArenaImpl implements Arena } int index = MobArena.random.nextInt(classes.size()); - String className = classes.get(index).getConfigName(); + String slug = classes.get(index).getSlug(); - assignClass(p, className); - messenger.tell(p, Msg.LOBBY_CLASS_PICKED, this.classes.get(className).getConfigName()); + assignClass(p, slug); + messenger.tell(p, Msg.LOBBY_CLASS_PICKED, this.classes.get(slug).getConfigName()); } private void addClassPermissions(Player player) { diff --git a/src/main/java/com/garbagemule/MobArena/ArenaListener.java b/src/main/java/com/garbagemule/MobArena/ArenaListener.java index 41a6b79..ecf5a08 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaListener.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaListener.java @@ -17,6 +17,7 @@ import com.garbagemule.MobArena.things.ExperienceThing; import com.garbagemule.MobArena.things.Thing; import com.garbagemule.MobArena.things.ThingPicker; import com.garbagemule.MobArena.util.ClassChests; +import com.garbagemule.MobArena.util.Slugs; import com.garbagemule.MobArena.waves.MABoss; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -1114,15 +1115,16 @@ public class ArenaListener private void handleSign(Sign sign, Player p) { // Check if the first line is a class name. - String className = ChatColor.stripColor(sign.getLine(0)).toLowerCase().replace(" ", ""); + String className = ChatColor.stripColor(sign.getLine(0)); + String slug = Slugs.create(className); - if (!arena.getClasses().containsKey(className) && !className.equals("random")) + if (!arena.getClasses().containsKey(slug) && !slug.equals("random")) return; - ArenaClass newAC = arena.getClasses().get(className); + ArenaClass newAC = arena.getClasses().get(slug); // Check for permission. - if (!newAC.hasPermission(p) && !className.equals("random")) { + if (!newAC.hasPermission(p) && !slug.equals("random")) { arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PERMISSION); return; } @@ -1154,7 +1156,7 @@ public class ArenaListener classLimits.playerPickedClass(newAC, p); // Delay the inventory stuff to ensure that right-clicking works. - delayAssignClass(p, className, price, sign); + delayAssignClass(p, slug, price, sign); } /*private boolean cansPlayerJoinClass(ArenaClass ac, Player p) { @@ -1169,12 +1171,12 @@ public class ArenaListener return true; }*/ - private void delayAssignClass(final Player p, final String className, final Thing price, final Sign sign) { + private void delayAssignClass(final Player p, final String slug, final Thing price, final Sign sign) { plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin,new Runnable() { public void run() { - if (!className.equalsIgnoreCase("random")) { + if (!slug.equalsIgnoreCase("random")) { if (useClassChests) { - ArenaClass ac = plugin.getArenaMaster().getClasses().get(className.toLowerCase().replace(" ", "")); + ArenaClass ac = plugin.getArenaMaster().getClasses().get(slug); if (ClassChests.assignClassFromStoredClassChest(arena, p, ac)) { return; } @@ -1183,8 +1185,8 @@ public class ArenaListener } // Otherwise just fall through and use the items from the config-file } - arena.assignClass(p, className); - arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(className).getConfigName()); + arena.assignClass(p, slug); + arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(slug).getConfigName()); if (price != null) { arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PRICE, price.toString()); } diff --git a/src/main/java/com/garbagemule/MobArena/ArenaMasterImpl.java b/src/main/java/com/garbagemule/MobArena/ArenaMasterImpl.java index 5a81712..5774a3b 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaMasterImpl.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaMasterImpl.java @@ -337,14 +337,13 @@ public class ArenaMasterImpl implements ArenaMaster private ArenaClass loadClass(String classname) { FileConfiguration config = plugin.getConfig(); ConfigurationSection section = config.getConfigurationSection("classes." + classname); - String lowercase = classname.toLowerCase().replace(" ", ""); // If the section doesn't exist, the class doesn't either. if (section == null) { // We may not have a class entry for My Items, but that's fine if (classname.equals("My Items")) { ArenaClass myItems = new ArenaClass.MyItems(null, false, false, this); - classes.put(lowercase, myItems); + classes.put(myItems.getSlug(), myItems); return myItems; } plugin.getLogger().severe("Failed to load class '" + classname + "'."); @@ -393,7 +392,7 @@ public class ArenaMasterImpl implements ArenaMaster } // Finally add the class to the classes map. - classes.put(lowercase, arenaClass); + classes.put(arenaClass.getSlug(), arenaClass); return arenaClass; } diff --git a/src/main/java/com/garbagemule/MobArena/commands/setup/ClassChestCommand.java b/src/main/java/com/garbagemule/MobArena/commands/setup/ClassChestCommand.java index 036c4c3..83b0b77 100644 --- a/src/main/java/com/garbagemule/MobArena/commands/setup/ClassChestCommand.java +++ b/src/main/java/com/garbagemule/MobArena/commands/setup/ClassChestCommand.java @@ -8,6 +8,7 @@ import com.garbagemule.MobArena.commands.Command; import com.garbagemule.MobArena.commands.CommandInfo; import com.garbagemule.MobArena.commands.Commands; import com.garbagemule.MobArena.framework.ArenaMaster; +import com.garbagemule.MobArena.util.Slugs; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; @@ -37,7 +38,8 @@ public class ClassChestCommand implements Command { // Require a class name if (args.length != 1) return false; - ArenaClass ac = am.getClasses().get(args[0].toLowerCase()); + String slug = Slugs.create(args[0]); + ArenaClass ac = am.getClasses().get(slug); if (ac == null) { am.getGlobalMessenger().tell(sender, "Class not found."); return true; @@ -69,13 +71,13 @@ public class ClassChestCommand implements Command { return Collections.emptyList(); } - String prefix = args[0].toLowerCase(); + String prefix = Slugs.create(args[0]); Collection classes = am.getClasses().values(); return classes.stream() - .filter(cls -> cls.getConfigName().toLowerCase().startsWith(prefix)) - .map(ArenaClass::getConfigName) + .filter(cls -> cls.getSlug().startsWith(prefix)) + .map(ArenaClass::getSlug) .collect(Collectors.toList()); } } diff --git a/src/main/java/com/garbagemule/MobArena/commands/user/PickClassCommand.java b/src/main/java/com/garbagemule/MobArena/commands/user/PickClassCommand.java index 4c600d8..097a91e 100644 --- a/src/main/java/com/garbagemule/MobArena/commands/user/PickClassCommand.java +++ b/src/main/java/com/garbagemule/MobArena/commands/user/PickClassCommand.java @@ -10,6 +10,7 @@ import com.garbagemule.MobArena.framework.Arena; import com.garbagemule.MobArena.framework.ArenaMaster; import com.garbagemule.MobArena.things.Thing; import com.garbagemule.MobArena.util.ClassChests; +import com.garbagemule.MobArena.util.Slugs; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -51,15 +52,15 @@ public class PickClassCommand implements Command } // Grab the ArenaClass, if it exists - String lowercase = args[0].toLowerCase(); - ArenaClass ac = am.getClasses().get(lowercase); + String slug = Slugs.create(args[0]); + ArenaClass ac = am.getClasses().get(slug); if (ac == null) { - arena.getMessenger().tell(p, Msg.LOBBY_NO_SUCH_CLASS, lowercase); + arena.getMessenger().tell(p, Msg.LOBBY_NO_SUCH_CLASS, slug); return true; } // Check for permission. - if (!ac.hasPermission(p) && !lowercase.equals("random")) { + if (!ac.hasPermission(p) && !slug.equals("random")) { arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PERMISSION); return true; } @@ -88,15 +89,15 @@ public class PickClassCommand implements Command clm.playerLeftClass(oldAC, p); clm.playerPickedClass(ac, p); - if (!lowercase.equalsIgnoreCase("random")) { + if (!slug.equalsIgnoreCase("random")) { if (arena.getSettings().getBoolean("use-class-chests", false)) { if (ClassChests.assignClassFromStoredClassChest(arena, p, ac)) { return true; } // No linked chest? Fall through to config-file } - arena.assignClass(p, lowercase); - arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(lowercase).getConfigName()); + arena.assignClass(p, slug); + arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(slug).getConfigName()); if (price != null) { arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PRICE, price.toString()); } @@ -118,9 +119,9 @@ public class PickClassCommand implements Command Collection classes = am.getClasses().values(); return classes.stream() - .filter(cls -> cls.getConfigName().toLowerCase().startsWith(prefix)) + .filter(cls -> cls.getSlug().startsWith(prefix)) .filter(cls -> cls.hasPermission(player)) - .map(ArenaClass::getConfigName) + .map(ArenaClass::getSlug) .collect(Collectors.toList()); } } diff --git a/src/main/java/com/garbagemule/MobArena/util/ClassChests.java b/src/main/java/com/garbagemule/MobArena/util/ClassChests.java index a9c723d..29936cb 100644 --- a/src/main/java/com/garbagemule/MobArena/util/ClassChests.java +++ b/src/main/java/com/garbagemule/MobArena/util/ClassChests.java @@ -96,7 +96,7 @@ public class ClassChests { } private static void assignClassAndGrantChestItems(Arena arena, Player player, ArenaClass ac, Block block) { - String classname = ac.getLowercaseName(); + String slug = ac.getSlug(); InventoryHolder holder = (InventoryHolder) block.getState(); ItemStack[] contents = holder.getInventory().getContents(); @@ -106,8 +106,8 @@ public class ClassChests { System.arraycopy(contents, 0, newContents, 0, 36); contents = newContents; } - arena.assignClassGiveInv(player, classname, contents); - arena.getMessenger().tell(player, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(classname).getConfigName()); + arena.assignClassGiveInv(player, slug, contents); + arena.getMessenger().tell(player, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(slug).getConfigName()); Thing price = ac.getPrice(); if (price != null) {