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.
This commit is contained in:
@@ -24,6 +24,7 @@ These changes will (most likely) be included in the next version.
|
|||||||
- New command `/ma addreward <player> <thing>` 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.
|
- New command `/ma addreward <player> <thing>` 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.
|
- 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.
|
- 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.
|
- 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.
|
- 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.
|
- 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.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import java.util.stream.IntStream;
|
|||||||
|
|
||||||
public class ArenaClass
|
public class ArenaClass
|
||||||
{
|
{
|
||||||
private String configName, lowercaseName;
|
private String configName;
|
||||||
private String slug;
|
private String slug;
|
||||||
private Thing helmet, chestplate, leggings, boots, offhand;
|
private Thing helmet, chestplate, leggings, boots, offhand;
|
||||||
private List<Thing> armor;
|
private List<Thing> armor;
|
||||||
@@ -35,7 +35,6 @@ public class ArenaClass
|
|||||||
public ArenaClass(String name, Thing price, boolean unbreakableWeapons, boolean unbreakableArmor) {
|
public ArenaClass(String name, Thing price, boolean unbreakableWeapons, boolean unbreakableArmor) {
|
||||||
this.configName = name;
|
this.configName = name;
|
||||||
this.slug = Slugs.create(name);
|
this.slug = Slugs.create(name);
|
||||||
this.lowercaseName = name.toLowerCase().replace(" ", "");
|
|
||||||
|
|
||||||
this.items = new ArrayList<>();
|
this.items = new ArrayList<>();
|
||||||
this.armor = new ArrayList<>(4);
|
this.armor = new ArrayList<>(4);
|
||||||
@@ -72,7 +71,7 @@ public class ArenaClass
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public String getLowercaseName() {
|
public String getLowercaseName() {
|
||||||
return lowercaseName;
|
return slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -238,12 +237,12 @@ public class ArenaClass
|
|||||||
if (!this.getClass().equals(o.getClass())) return false;
|
if (!this.getClass().equals(o.getClass())) return false;
|
||||||
|
|
||||||
ArenaClass other = (ArenaClass) o;
|
ArenaClass other = (ArenaClass) o;
|
||||||
return other.lowercaseName.equals(this.lowercaseName);
|
return other.slug.equals(this.slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return lowercaseName.hashCode();
|
return slug.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MyItems extends ArenaClass {
|
public static class MyItems extends ArenaClass {
|
||||||
|
|||||||
@@ -757,7 +757,8 @@ public class ArenaImpl implements Arena
|
|||||||
if (defaultClass != null) {
|
if (defaultClass != null) {
|
||||||
// Assign default class if applicable
|
// Assign default class if applicable
|
||||||
if (!ClassChests.assignClassFromStoredClassChest(this, p, defaultClass)) {
|
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());
|
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());
|
int index = MobArena.random.nextInt(classes.size());
|
||||||
String className = classes.get(index).getConfigName();
|
String slug = classes.get(index).getSlug();
|
||||||
|
|
||||||
assignClass(p, className);
|
assignClass(p, slug);
|
||||||
messenger.tell(p, Msg.LOBBY_CLASS_PICKED, this.classes.get(className).getConfigName());
|
messenger.tell(p, Msg.LOBBY_CLASS_PICKED, this.classes.get(slug).getConfigName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addClassPermissions(Player player) {
|
private void addClassPermissions(Player player) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import com.garbagemule.MobArena.things.ExperienceThing;
|
|||||||
import com.garbagemule.MobArena.things.Thing;
|
import com.garbagemule.MobArena.things.Thing;
|
||||||
import com.garbagemule.MobArena.things.ThingPicker;
|
import com.garbagemule.MobArena.things.ThingPicker;
|
||||||
import com.garbagemule.MobArena.util.ClassChests;
|
import com.garbagemule.MobArena.util.ClassChests;
|
||||||
|
import com.garbagemule.MobArena.util.Slugs;
|
||||||
import com.garbagemule.MobArena.waves.MABoss;
|
import com.garbagemule.MobArena.waves.MABoss;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -1114,15 +1115,16 @@ public class ArenaListener
|
|||||||
|
|
||||||
private void handleSign(Sign sign, Player p) {
|
private void handleSign(Sign sign, Player p) {
|
||||||
// Check if the first line is a class name.
|
// 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;
|
return;
|
||||||
|
|
||||||
ArenaClass newAC = arena.getClasses().get(className);
|
ArenaClass newAC = arena.getClasses().get(slug);
|
||||||
|
|
||||||
// Check for permission.
|
// 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);
|
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PERMISSION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1154,7 +1156,7 @@ public class ArenaListener
|
|||||||
classLimits.playerPickedClass(newAC, p);
|
classLimits.playerPickedClass(newAC, p);
|
||||||
|
|
||||||
// Delay the inventory stuff to ensure that right-clicking works.
|
// 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) {
|
/*private boolean cansPlayerJoinClass(ArenaClass ac, Player p) {
|
||||||
@@ -1169,12 +1171,12 @@ public class ArenaListener
|
|||||||
return true;
|
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() {
|
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin,new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!className.equalsIgnoreCase("random")) {
|
if (!slug.equalsIgnoreCase("random")) {
|
||||||
if (useClassChests) {
|
if (useClassChests) {
|
||||||
ArenaClass ac = plugin.getArenaMaster().getClasses().get(className.toLowerCase().replace(" ", ""));
|
ArenaClass ac = plugin.getArenaMaster().getClasses().get(slug);
|
||||||
if (ClassChests.assignClassFromStoredClassChest(arena, p, ac)) {
|
if (ClassChests.assignClassFromStoredClassChest(arena, p, ac)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1183,8 +1185,8 @@ public class ArenaListener
|
|||||||
}
|
}
|
||||||
// Otherwise just fall through and use the items from the config-file
|
// Otherwise just fall through and use the items from the config-file
|
||||||
}
|
}
|
||||||
arena.assignClass(p, className);
|
arena.assignClass(p, slug);
|
||||||
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(className).getConfigName());
|
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(slug).getConfigName());
|
||||||
if (price != null) {
|
if (price != null) {
|
||||||
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PRICE, price.toString());
|
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PRICE, price.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -337,14 +337,13 @@ public class ArenaMasterImpl implements ArenaMaster
|
|||||||
private ArenaClass loadClass(String classname) {
|
private ArenaClass loadClass(String classname) {
|
||||||
FileConfiguration config = plugin.getConfig();
|
FileConfiguration config = plugin.getConfig();
|
||||||
ConfigurationSection section = config.getConfigurationSection("classes." + classname);
|
ConfigurationSection section = config.getConfigurationSection("classes." + classname);
|
||||||
String lowercase = classname.toLowerCase().replace(" ", "");
|
|
||||||
|
|
||||||
// If the section doesn't exist, the class doesn't either.
|
// If the section doesn't exist, the class doesn't either.
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
// We may not have a class entry for My Items, but that's fine
|
// We may not have a class entry for My Items, but that's fine
|
||||||
if (classname.equals("My Items")) {
|
if (classname.equals("My Items")) {
|
||||||
ArenaClass myItems = new ArenaClass.MyItems(null, false, false, this);
|
ArenaClass myItems = new ArenaClass.MyItems(null, false, false, this);
|
||||||
classes.put(lowercase, myItems);
|
classes.put(myItems.getSlug(), myItems);
|
||||||
return myItems;
|
return myItems;
|
||||||
}
|
}
|
||||||
plugin.getLogger().severe("Failed to load class '" + classname + "'.");
|
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.
|
// Finally add the class to the classes map.
|
||||||
classes.put(lowercase, arenaClass);
|
classes.put(arenaClass.getSlug(), arenaClass);
|
||||||
return arenaClass;
|
return arenaClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.garbagemule.MobArena.commands.Command;
|
|||||||
import com.garbagemule.MobArena.commands.CommandInfo;
|
import com.garbagemule.MobArena.commands.CommandInfo;
|
||||||
import com.garbagemule.MobArena.commands.Commands;
|
import com.garbagemule.MobArena.commands.Commands;
|
||||||
import com.garbagemule.MobArena.framework.ArenaMaster;
|
import com.garbagemule.MobArena.framework.ArenaMaster;
|
||||||
|
import com.garbagemule.MobArena.util.Slugs;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@@ -37,7 +38,8 @@ public class ClassChestCommand implements Command {
|
|||||||
// Require a class name
|
// Require a class name
|
||||||
if (args.length != 1) return false;
|
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) {
|
if (ac == null) {
|
||||||
am.getGlobalMessenger().tell(sender, "Class not found.");
|
am.getGlobalMessenger().tell(sender, "Class not found.");
|
||||||
return true;
|
return true;
|
||||||
@@ -69,13 +71,13 @@ public class ClassChestCommand implements Command {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
String prefix = args[0].toLowerCase();
|
String prefix = Slugs.create(args[0]);
|
||||||
|
|
||||||
Collection<ArenaClass> classes = am.getClasses().values();
|
Collection<ArenaClass> classes = am.getClasses().values();
|
||||||
|
|
||||||
return classes.stream()
|
return classes.stream()
|
||||||
.filter(cls -> cls.getConfigName().toLowerCase().startsWith(prefix))
|
.filter(cls -> cls.getSlug().startsWith(prefix))
|
||||||
.map(ArenaClass::getConfigName)
|
.map(ArenaClass::getSlug)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.garbagemule.MobArena.framework.Arena;
|
|||||||
import com.garbagemule.MobArena.framework.ArenaMaster;
|
import com.garbagemule.MobArena.framework.ArenaMaster;
|
||||||
import com.garbagemule.MobArena.things.Thing;
|
import com.garbagemule.MobArena.things.Thing;
|
||||||
import com.garbagemule.MobArena.util.ClassChests;
|
import com.garbagemule.MobArena.util.ClassChests;
|
||||||
|
import com.garbagemule.MobArena.util.Slugs;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
@@ -51,15 +52,15 @@ public class PickClassCommand implements Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Grab the ArenaClass, if it exists
|
// Grab the ArenaClass, if it exists
|
||||||
String lowercase = args[0].toLowerCase();
|
String slug = Slugs.create(args[0]);
|
||||||
ArenaClass ac = am.getClasses().get(lowercase);
|
ArenaClass ac = am.getClasses().get(slug);
|
||||||
if (ac == null) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for permission.
|
// 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);
|
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PERMISSION);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -88,15 +89,15 @@ public class PickClassCommand implements Command
|
|||||||
clm.playerLeftClass(oldAC, p);
|
clm.playerLeftClass(oldAC, p);
|
||||||
clm.playerPickedClass(ac, p);
|
clm.playerPickedClass(ac, p);
|
||||||
|
|
||||||
if (!lowercase.equalsIgnoreCase("random")) {
|
if (!slug.equalsIgnoreCase("random")) {
|
||||||
if (arena.getSettings().getBoolean("use-class-chests", false)) {
|
if (arena.getSettings().getBoolean("use-class-chests", false)) {
|
||||||
if (ClassChests.assignClassFromStoredClassChest(arena, p, ac)) {
|
if (ClassChests.assignClassFromStoredClassChest(arena, p, ac)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// No linked chest? Fall through to config-file
|
// No linked chest? Fall through to config-file
|
||||||
}
|
}
|
||||||
arena.assignClass(p, lowercase);
|
arena.assignClass(p, slug);
|
||||||
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(lowercase).getConfigName());
|
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(slug).getConfigName());
|
||||||
if (price != null) {
|
if (price != null) {
|
||||||
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PRICE, price.toString());
|
arena.getMessenger().tell(p, Msg.LOBBY_CLASS_PRICE, price.toString());
|
||||||
}
|
}
|
||||||
@@ -118,9 +119,9 @@ public class PickClassCommand implements Command
|
|||||||
Collection<ArenaClass> classes = am.getClasses().values();
|
Collection<ArenaClass> classes = am.getClasses().values();
|
||||||
|
|
||||||
return classes.stream()
|
return classes.stream()
|
||||||
.filter(cls -> cls.getConfigName().toLowerCase().startsWith(prefix))
|
.filter(cls -> cls.getSlug().startsWith(prefix))
|
||||||
.filter(cls -> cls.hasPermission(player))
|
.filter(cls -> cls.hasPermission(player))
|
||||||
.map(ArenaClass::getConfigName)
|
.map(ArenaClass::getSlug)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public class ClassChests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void assignClassAndGrantChestItems(Arena arena, Player player, ArenaClass ac, Block block) {
|
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();
|
InventoryHolder holder = (InventoryHolder) block.getState();
|
||||||
ItemStack[] contents = holder.getInventory().getContents();
|
ItemStack[] contents = holder.getInventory().getContents();
|
||||||
|
|
||||||
@@ -106,8 +106,8 @@ public class ClassChests {
|
|||||||
System.arraycopy(contents, 0, newContents, 0, 36);
|
System.arraycopy(contents, 0, newContents, 0, 36);
|
||||||
contents = newContents;
|
contents = newContents;
|
||||||
}
|
}
|
||||||
arena.assignClassGiveInv(player, classname, contents);
|
arena.assignClassGiveInv(player, slug, contents);
|
||||||
arena.getMessenger().tell(player, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(classname).getConfigName());
|
arena.getMessenger().tell(player, Msg.LOBBY_CLASS_PICKED, arena.getClasses().get(slug).getConfigName());
|
||||||
|
|
||||||
Thing price = ac.getPrice();
|
Thing price = ac.getPrice();
|
||||||
if (price != null) {
|
if (price != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user