diff --git a/src/com/massivecraft/factions/Factions.java b/src/com/massivecraft/factions/Factions.java index 5d4ab97e..e10a0ee0 100644 --- a/src/com/massivecraft/factions/Factions.java +++ b/src/com/massivecraft/factions/Factions.java @@ -77,6 +77,7 @@ public class Factions extends JavaPlugin { commands.add(new FCommandBypass()); commands.add(new FCommandChat()); commands.add(new FCommandClaim()); + commands.add(new FCommandConfig()); commands.add(new FCommandCreate()); commands.add(new FCommandDeinvite()); commands.add(new FCommandDescription()); @@ -337,6 +338,10 @@ public class Factions extends JavaPlugin { return hasPerm(sender, "factions.lock"); } + public static boolean hasPermConfigure(CommandSender sender) { + return hasPerm(sender, "factions.config"); + } + public static boolean hasPermDisband(CommandSender sender) { return hasPerm(sender, "factions.disband"); } diff --git a/src/com/massivecraft/factions/commands/FBaseCommand.java b/src/com/massivecraft/factions/commands/FBaseCommand.java index 1bd3190c..60cc7cbc 100644 --- a/src/com/massivecraft/factions/commands/FBaseCommand.java +++ b/src/com/massivecraft/factions/commands/FBaseCommand.java @@ -1,6 +1,7 @@ package com.massivecraft.factions.commands; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.bukkit.command.CommandSender; @@ -229,15 +230,10 @@ public class FBaseCommand { return false; } + public static final List aliasTrue = new ArrayList(Arrays.asList("true", "yes", "y", "ok", "on", "+")); + public static final List aliasFalse = new ArrayList(Arrays.asList("false", "no", "n", "off", "-")); + public boolean parseBool(String str) { - List aliasTrue = new ArrayList(); - aliasTrue.add("true"); - aliasTrue.add("yes"); - aliasTrue.add("y"); - aliasTrue.add("ok"); - aliasTrue.add("on"); - aliasTrue.add("+"); - return aliasTrue.contains(str.toLowerCase()); } diff --git a/src/com/massivecraft/factions/commands/FCommandConfig.java b/src/com/massivecraft/factions/commands/FCommandConfig.java new file mode 100644 index 00000000..d7dea900 --- /dev/null +++ b/src/com/massivecraft/factions/commands/FCommandConfig.java @@ -0,0 +1,225 @@ +package com.massivecraft.factions.commands; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Set; +import java.util.HashMap; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import com.massivecraft.factions.Conf; +import com.massivecraft.factions.Factions; + +public class FCommandConfig extends FBaseCommand { + + private static HashMap properFieldNames = new HashMap(); + + public FCommandConfig() { + aliases.add("config"); + + senderMustBePlayer = false; + + requiredParameters.add("setting"); + requiredParameters.add("value"); + + helpDescription = "change a conf.json setting"; + } + + @Override + public boolean hasPermission(CommandSender sender) { + return Factions.hasPermConfigure(sender); + } + + @Override + public void perform() { + + if( isLocked() ) { + sendLockMessage(); + return; + } + + // store a lookup map of lowercase field names paired with proper capitalization field names + // that way, if the person using this command messes up the capitalization, we can fix that + if (properFieldNames.isEmpty()) { + Field[] fields = Conf.class.getDeclaredFields(); + for(int i = 0; i < fields.length; i++) { + properFieldNames.put(fields[i].getName().toLowerCase(), fields[i].getName()); + } + } + + String fieldName = properFieldNames.get(parameters.get(0).toLowerCase()); + + if (fieldName == null || fieldName.isEmpty()) { + sendMessage("No configuration setting \""+parameters.get(0)+"\" exists."); + return; + } + + String success = ""; + + String value = parameters.get(1); + for(int i = 2; i < parameters.size(); i++) { + value += ' ' + parameters.get(i); + } + + try { + Field target = Conf.class.getField(fieldName); + + // boolean + if (target.getType() == boolean.class) { + if (aliasTrue.contains(value.toLowerCase())) { + target.setBoolean(null, true); + success = "\""+fieldName+"\" option set to true (enabled)."; + } + else if (aliasFalse.contains(value.toLowerCase())) { + target.setBoolean(null, false); + success = "\""+fieldName+"\" option set to false (disabled)."; + } + else { + sendMessage("Cannot set \""+fieldName+"\": boolean value required (true or false)."); + return; + } + } + + // int + else if (target.getType() == int.class) { + try { + int intVal = Integer.parseInt(value); + target.setInt(null, intVal); + success = "\""+fieldName+"\" option set to "+intVal+"."; + } + catch(NumberFormatException ex) { + sendMessage("Cannot set \""+fieldName+"\": integer (whole number) value required."); + return; + } + } + + // double + else if (target.getType() == double.class) { + try { + double doubleVal = Double.parseDouble(value); + target.setDouble(null, doubleVal); + success = "\""+fieldName+"\" option set to "+doubleVal+"."; + } + catch(NumberFormatException ex) { + sendMessage("Cannot set \""+fieldName+"\": double (numeric) value required."); + return; + } + } + + // String + else if (target.getType() == String.class) { + target.set(null, value); + success = "\""+fieldName+"\" option set to \""+value+"\"."; + } + + // ChatColor + else if (target.getType() == ChatColor.class) { + ChatColor newColor = null; + try { + newColor = ChatColor.valueOf(value.toUpperCase()); + } + catch (IllegalArgumentException ex) { + } + if (newColor == null) { + sendMessage("Cannot set \""+fieldName+"\": \""+value.toUpperCase()+"\" is not a valid color."); + return; + } + target.set(null, newColor); + success = "\""+fieldName+"\" color option set to \""+value.toUpperCase()+"\"."; + } + + // Set or other parameterized collection + else if (target.getGenericType() instanceof ParameterizedType) { + ParameterizedType targSet = (ParameterizedType)target.getGenericType(); + Type innerType = targSet.getActualTypeArguments()[0]; + + // not a Set, somehow, and that should be the only collection we're using in Conf.java + if (targSet.getRawType() != Set.class) { + sendMessage("\""+fieldName+"\" is not a data collection type which can be modified with this command."); + return; + } + + // Set + else if (innerType == Material.class) { + Material newMat = null; + try { + newMat = Material.valueOf(value.toUpperCase()); + } + catch (IllegalArgumentException ex) { + } + if (newMat == null) { + sendMessage("Cannot change \""+fieldName+"\" set: \""+value.toUpperCase()+"\" is not a valid material."); + return; + } + + Set matSet = (Set)target.get(null); + + // Material already present, so remove it + if (matSet.contains(newMat)) { + matSet.remove(newMat); + target.set(null, matSet); + success = "\""+fieldName+"\" set: Material \""+value.toUpperCase()+"\" removed."; + } + // Material not present yet, add it + else { + matSet.add(newMat); + target.set(null, matSet); + success = "\""+fieldName+"\" set: Material \""+value.toUpperCase()+"\" added."; + } + } + + // Set + else if (innerType == String.class) { + Set stringSet = (Set)target.get(null); + + // String already present, so remove it + if (stringSet.contains(value)) { + stringSet.remove(value); + target.set(null, stringSet); + success = "\""+fieldName+"\" set: \""+value+"\" removed."; + } + // String not present yet, add it + else { + stringSet.add(value); + target.set(null, stringSet); + success = "\""+fieldName+"\" set: \""+value+"\" added."; + } + } + + // Set of unknown type + else { + sendMessage("\""+fieldName+"\" is not a data type set which can be modified with this command."); + return; + } + } + + // unknown type + else { + sendMessage("\""+fieldName+"\" is not a data type which can be modified with this command."); + return; + } + } + catch (NoSuchFieldException ex) { + sendMessage("Configuration setting \""+fieldName+"\" couldn't be matched, though it should be... please report this error."); + return; + } + catch (IllegalAccessException ex) { + sendMessage("Error setting configuration setting \""+fieldName+"\" to \""+value+"\"."); + return; + } + + if (!success.isEmpty()) { + sendMessage(success); + if (sender instanceof Player) { + Factions.log(success + " Command was run by "+player.getName()+"."); + } + } + // save change to disk + Conf.save(); + } + +} diff --git a/src/com/massivecraft/factions/commands/FCommandHelp.java b/src/com/massivecraft/factions/commands/FCommandHelp.java index 0cca49f8..8a0633fd 100644 --- a/src/com/massivecraft/factions/commands/FCommandHelp.java +++ b/src/com/massivecraft/factions/commands/FCommandHelp.java @@ -147,6 +147,7 @@ public class FCommandHelp extends FBaseCommand { pageLines.add( new FCommandReload().getUseageTemplate() ); pageLines.add( new FCommandSaveAll().getUseageTemplate() ); pageLines.add( new FCommandVersion().getUseageTemplate() ); + pageLines.add( new FCommandConfig().getUseageTemplate() ); helpPages.add(pageLines); } diff --git a/src/plugin.yml b/src/plugin.yml index 7f4863af..4adb2a09 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -27,6 +27,7 @@ permissions: factions.disband: true factions.worldOptions: true factions.commandDisable.none: true + factions.config: true factions.participate: description: Allows the player to participate in a faction default: true @@ -57,6 +58,9 @@ permissions: factions.worldOptions: description: Can use the /f worldnoclaim and /f worldnopowerloss commands default: op + factions.config: + description: Can use /f config command to change conf.json options + default: op factions.commandDisable.none: description: no commands disabled (ignore all other commandDisable permissions) default: op