More ported flag types, and additions to the flag API.

This commit is contained in:
Alexander Söderberg 2020-02-10 14:58:04 +01:00
parent 364c693b8c
commit b3db67ab76
12 changed files with 233 additions and 36 deletions

View File

@ -6,11 +6,12 @@ import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.config.Settings;
import com.github.intellectualsites.plotsquared.plot.database.DBFunc;
import com.github.intellectualsites.plotsquared.plot.flag.BlockStateListFlag;
import com.github.intellectualsites.plotsquared.plot.flag.Flag;
import com.github.intellectualsites.plotsquared.plot.flag.FlagManager;
import com.github.intellectualsites.plotsquared.plot.flag.Flags;
import com.github.intellectualsites.plotsquared.plot.flag.IntegerFlag;
import com.github.intellectualsites.plotsquared.plot.flag.ListFlag;
import com.github.intellectualsites.plotsquared.plot.flags.GlobalFlagContainer;
import com.github.intellectualsites.plotsquared.plot.flags.PlotFlag;
import com.github.intellectualsites.plotsquared.plot.flags.types.BlockTypeListFlag;
import com.github.intellectualsites.plotsquared.plot.flags.types.IntegerFlag;
import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
@ -37,7 +38,7 @@ import java.util.Set;
"setflag"}, usage = "/plot flag <set|remove|add|list|info> <flag> <value>", description = "Set plot flags", category = CommandCategory.SETTINGS, requiredType = RequiredType.NONE, permission = "plots.flag")
public class FlagCmd extends SubCommand {
private boolean checkPermValue(PlotPlayer player, Flag flag, String key, String value) {
private boolean checkPermValue(PlotPlayer player, PlotFlag<?> flag, String key, String value) {
key = key.toLowerCase();
value = value.toLowerCase();
String perm = Captions
@ -62,9 +63,10 @@ public class FlagCmd extends SubCommand {
} catch (NumberFormatException ignore) {
}
} else if (flag instanceof BlockStateListFlag) {
final BlockStateListFlag blockListFlag = (BlockStateListFlag) flag;
Set<BlockType> parsedBlocks = blockListFlag.parseValue(value);
} else if (flag instanceof BlockTypeListFlag) {
final BlockTypeListFlag blockListFlag = (BlockTypeListFlag) flag;
try {
List<BlockType> parsedBlocks = blockListFlag.parse(value);
for (final BlockType block : parsedBlocks) {
final String permission = Captions
.format(Captions.PERMISSION_SET_FLAG_KEY_VALUE.getTranslated(),
@ -77,6 +79,9 @@ public class FlagCmd extends SubCommand {
return false;
}
}
} catch (final Exception e) {
return false;
}
return true;
}
final boolean result = Permissions.hasPermission(player, perm);
@ -117,13 +122,13 @@ public class FlagCmd extends SubCommand {
.sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_SET_FLAG_OTHER);
return false;
}
Flag<?> flag = null;
PlotFlag<?> flag = null;
if (args.length > 1) {
flag = FlagManager.getFlag(args[1]);
flag = GlobalFlagContainer.getInstance().getFlagFromString(args[1]);
if (flag == null || flag.isReserved()) {
boolean suggested = false;
try {
StringComparison<Flag<?>> stringComparison =
StringComparison<PlotFlag<?>> stringComparison =
new StringComparison<>(args[1], Flags.getFlags());
String best = stringComparison.getBestMatch();
if (best != null) {

View File

@ -548,6 +548,9 @@ public enum Captions {
FLAG_CATEGORY_BOOLEAN("Boolean Flags", "Flags"),
FLAG_CATEGORY_MIXED("Mixed Value Flags", "Flags"),
//</editor-fold>
//<editor-fold desc="Flag descriptions">
FLAG_DESCRIPTION_EXPLOSION("Set to 'true' to enable explosions in the plot, and 'false' to disable them", "Flags"),
//</editor-fold>
//<editor-fold desc="Flag category errors">
FLAG_ERROR_BOOLEAN("Flag value must be a boolean (true|false)", "Flags"),
FLAG_ERROR_ENUM("Must be one of: %s", "Flags"),
@ -558,6 +561,7 @@ public enum Captions {
FLAG_ERROR_KEEP("Flag value must be a timestamp or a boolean", "Flags"),
FLAG_ERROR_LONG("Flag value must be a whole number (large numbers allowed)", "Flags"),
FLAG_ERROR_PLOTBLOCKLIST("Flag value must be a block list", "Flags"),
FLAG_ERROR_INVALID_BLOCK("The provided value is not a valid block", "Flags"),
FLAG_ERROR_PRICE("Flag value must be a positive number.", "Flags"),
FLAG_ERROR_STRING("Flag value must be alphanumeric. Some special characters are allowed.", "Flags"),
FLAG_ERROR_STRINGLIST("Flag value must be a string list", "Flags"),

View File

@ -50,6 +50,18 @@ import java.util.Map;
return this;
}
public PlotFlag<?> getFlagErased(Class<?> flagClass) {
final PlotFlag<?> flag = this.flagMap.get(flagClass);
if (flag != null) {
return flag;
} else {
if (getParentContainer() != null) {
return getParentContainer().getFlagErased(flagClass);
}
}
return null;
}
public <T> PlotFlag<T> getFlag(final Class<? extends PlotFlag<T>> flagClass) {
final PlotFlag<?> flag = this.flagMap.get(flagClass);
if (flag != null) {

View File

@ -1,15 +1,19 @@
package com.github.intellectualsites.plotsquared.plot.flags;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
public class FlagParseException extends Exception {
private final PlotFlag<?> flag;
private final String value;
private final Captions errorMessage;
public FlagParseException(final PlotFlag<?> flag, final String value) {
public FlagParseException(final PlotFlag<?> flag, final String value, final Captions errorMessage) {
super(String.format("Failed to parse flag of type '%s'. Value '%s' was not accepted.",
flag.getName(), value));
this.flag = flag;
this.value = value;
this.errorMessage = errorMessage;
}
/**
@ -30,4 +34,7 @@ public class FlagParseException extends Exception {
return this.flag;
}
public Captions getErrorMessage() {
return errorMessage;
}
}

View File

@ -4,11 +4,26 @@ import com.github.intellectualsites.plotsquared.plot.flags.implementations.Explo
import lombok.Getter;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public final class GlobalFlagContainer extends FlagContainer {
@Getter private static final GlobalFlagContainer instance = new GlobalFlagContainer();
private final Map<String, Class<?>> stringClassMap = new HashMap<>();
@Override public PlotFlag<?> getFlagErased(Class<?> flagClass) {
final PlotFlag<?> flag = super.getFlagErased(flagClass);
if (flag != null) {
return flag;
} else {
throw new IllegalStateException(String.format("Unrecognized flag '%s'. All flag types"
+ " must be present in the global flag container.", flagClass.getSimpleName()));
}
}
@Nonnull @Override public <T> PlotFlag<T> getFlag(Class<? extends PlotFlag<T>> flagClass) {
final PlotFlag<?> flag = super.getFlag(flagClass);
if (flag != null) {
@ -25,4 +40,21 @@ public final class GlobalFlagContainer extends FlagContainer {
this.addFlag(new ExplosionFlag());
}
@Override public void addFlag(PlotFlag<?> flag) {
super.addFlag(flag);
this.stringClassMap.put(flag.getName().toLowerCase(Locale.ENGLISH), flag.getClass());
}
public Class<?> getFlagClassFromString(final String name) {
return this.stringClassMap.get(name.toLowerCase(Locale.ENGLISH));
}
public PlotFlag<?> getFlagFromString(final String name) {
final Class<?> flagClass = this.getFlagClassFromString(name);
if (flagClass == null) {
return null;
}
return getFlagErased(flagClass);
}
}

View File

@ -1,9 +1,12 @@
package com.github.intellectualsites.plotsquared.plot.flags;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.google.common.base.Preconditions;
import lombok.EqualsAndHashCode;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
/**
* A plot flag is any property that can be assigned
* to a plot, that will alter its functionality in some way.
@ -14,14 +17,19 @@ import org.jetbrains.annotations.NotNull;
@EqualsAndHashCode(of = "value") public abstract class PlotFlag<T> {
private T value;
private final Captions flagCategory;
private final Captions flagDescription;
/**
* Construct a new flag instance.
*
* @param value Flag value
*/
protected PlotFlag(@NotNull final T value) {
this.value = Preconditions.checkNotNull(value, "flag values may not be null");
protected PlotFlag(@NotNull final T value, @NotNull final Captions flagCategory,
@NotNull final Captions flagDescription) {
this.value = Preconditions.checkNotNull(value, "flag value may not be null");
this.flagCategory = Preconditions.checkNotNull(flagCategory, "flag category may not be null");
this.flagDescription = Preconditions.checkNotNull(flagDescription, "flag description may not be null");
}
/**
@ -72,7 +80,17 @@ import org.jetbrains.annotations.NotNull;
public abstract String toString();
public final String getName() {
return this.getClass().getSimpleName();
return this.getClass().getSimpleName().toLowerCase(Locale.ENGLISH);
}
public Captions getFlagDescription() {
return this.flagDescription;
}
public Captions getFlagCategory() {
return this.flagCategory;
}
public abstract String getExample();
}

View File

@ -1,6 +1,16 @@
package com.github.intellectualsites.plotsquared.plot.flags.implementations;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.flags.types.BooleanFlag;
public class ExplosionFlag extends BooleanFlag {
public ExplosionFlag() {
super(Captions.FLAG_DESCRIPTION_EXPLOSION);
}
@Override public String getExample() {
return "true";
}
}

View File

@ -0,0 +1,40 @@
package com.github.intellectualsites.plotsquared.plot.flags.types;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.flags.FlagParseException;
import com.github.intellectualsites.plotsquared.plot.util.world.BlockUtil;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class BlockTypeListFlag extends ListFlag<BlockType> {
public BlockTypeListFlag(Captions description) {
super(Captions.FLAG_CATEGORY_BLOCK_LIST, description);
}
@Override public List<BlockType> parse(@NotNull String input) throws FlagParseException {
final List<BlockType> parsedBlocks = new ArrayList<>();
final String[] split = input.split(",(?![^\\(\\[]*[\\]\\)])");
if (split.length == 0) {
return parsedBlocks;
}
for (final String blockString : split) {
final BlockState blockState = BlockUtil.get(blockString);
if (blockState == null) {
throw new FlagParseException(this, blockString, Captions.FLAG_ERROR_INVALID_BLOCK);
} else {
parsedBlocks.add(blockState.getBlockType());
}
}
return parsedBlocks;
}
@Override public String getExample() {
return "air,grass_block";
}
}

View File

@ -1,5 +1,6 @@
package com.github.intellectualsites.plotsquared.plot.flags.types;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.flags.FlagParseException;
import com.github.intellectualsites.plotsquared.plot.flags.PlotFlag;
import org.jetbrains.annotations.NotNull;
@ -17,26 +18,29 @@ public abstract class BooleanFlag extends PlotFlag<Boolean> {
* Construct a new flag instance.
*
* @param value Flag value
* @param description Flag description
*/
protected BooleanFlag(boolean value) {
super(value);
protected BooleanFlag(final boolean value, final Captions description) {
super(value, Captions.FLAG_CATEGORY_BOOLEAN, description);
}
/**
* Construct a new boolean flag, with
* {@code false} as the default value.
*
* @param description Flag description
*/
protected BooleanFlag() {
this(false);
protected BooleanFlag(final Captions description) {
this(false, description);
}
@Override public Boolean parse(@NotNull String input) throws FlagParseException {
if (positiveValues.contains(input.toLowerCase(Locale.ENGLISH))) {
return this.setFlagValue(true);
return true;
} else if (negativeValues.contains(input.toLowerCase(Locale.ENGLISH))) {
return this.setFlagValue(false);
return false;
} else {
throw new FlagParseException(this, input);
throw new FlagParseException(this, input, Captions.FLAG_ERROR_BOOLEAN);
}
}

View File

@ -0,0 +1,38 @@
package com.github.intellectualsites.plotsquared.plot.flags.types;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.flags.FlagParseException;
import com.github.intellectualsites.plotsquared.plot.flags.PlotFlag;
import org.jetbrains.annotations.NotNull;
public class IntegerFlag extends PlotFlag<Integer> {
protected IntegerFlag(final int defaultValue, @NotNull Captions flagDescription) {
super(defaultValue, Captions.FLAG_CATEGORY_INTEGERS, flagDescription);
}
protected IntegerFlag(@NotNull Captions flagDescription) {
this(0, flagDescription);
}
@Override public Integer parse(@NotNull String input) throws FlagParseException {
try {
return Integer.parseInt(input);
} catch (final Throwable throwable) {
throw new FlagParseException(this, input, Captions.FLAG_ERROR_INTEGER);
}
}
@Override public Integer merge(@NotNull Integer oldValue, @NotNull Integer newValue) {
return oldValue + newValue;
}
@Override public String toString() {
return this.getValue().toString();
}
@Override public String getExample() {
return "10";
}
}

View File

@ -0,0 +1,27 @@
package com.github.intellectualsites.plotsquared.plot.flags.types;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.flags.PlotFlag;
import com.github.intellectualsites.plotsquared.plot.util.StringMan;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public abstract class ListFlag<V> extends PlotFlag<List<V>> {
public ListFlag(final Captions category, final Captions description) {
super(new ArrayList<>(), category, description);
}
@Override public List<V> merge(@NotNull List<V> oldValue, @NotNull List<V> newValue) {
final List<V> mergedList = new ArrayList<>();
mergedList.addAll(oldValue);
mergedList.addAll(newValue);
return this.setFlagValue(mergedList);
}
@Override public String toString() {
return StringMan.join(this.getValue(), ",");
}
}

View File

@ -18,9 +18,9 @@ import java.util.Map;
public final class BlockUtil {
private BlockUtil(){}
private static final ParserContext PARSER_CONTEXT = new ParserContext();
private static ParserContext PARSER_CONTEXT = new ParserContext();
private static final InputParser<BaseBlock> PARSER;
private static InputParser<BaseBlock> PARSER;
static {
PARSER_CONTEXT.setRestricted(false);
@ -29,15 +29,15 @@ public final class BlockUtil {
PARSER = WorldEdit.getInstance().getBlockFactory().getParsers().get(0);
}
public static final BlockState get(int id) {
public static BlockState get(int id) {
return LegacyMapper.getInstance().getBlockFromLegacy(id);
}
public static final BlockState get(int id, int data) {
public static BlockState get(int id, int data) {
return LegacyMapper.getInstance().getBlockFromLegacy(id, data);
}
public static final BlockState get(String id) {
public static BlockState get(String id) {
if (id.length() == 1 && id.charAt(0) == '*') {
return FuzzyBlockState.builder().type(BlockTypes.AIR).build();
}
@ -66,7 +66,7 @@ public final class BlockUtil {
}
}
public static final BlockState[] parse(String commaDelimited) {
public static BlockState[] parse(String commaDelimited) {
String[] split = commaDelimited.split(",(?![^\\(\\[]*[\\]\\)])");
BlockState[] result = new BlockState[split.length];
for (int i = 0; i < split.length; i++) {