Add /rg flags command.

Provides an overview of all flags set on a region, including inherited
values, and allows the user to set or unset flags with a single click.
This commit is contained in:
wizjany 2019-05-04 20:03:33 -04:00
parent fc4c67ff29
commit 7199b8e70f
9 changed files with 672 additions and 65 deletions

View File

@ -0,0 +1,502 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.commands.region;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.registry.Registry;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import com.sk89q.worldedit.util.formatting.text.serializer.legacy.LegacyComponentSerializer;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.internal.permission.RegionPermissionModel;
import com.sk89q.worldguard.protection.flags.BooleanFlag;
import com.sk89q.worldguard.protection.flags.DoubleFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.Flags;
import com.sk89q.worldguard.protection.flags.IntegerFlag;
import com.sk89q.worldguard.protection.flags.LocationFlag;
import com.sk89q.worldguard.protection.flags.RegistryFlag;
import com.sk89q.worldguard.protection.flags.SetFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StringFlag;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
class FlagHelperBox extends PaginationBox {
private static final List<Flag<?>> FLAGS = WorldGuard.getInstance().getFlagRegistry().getAll().stream()
.sorted((f1, f2) -> {
if (f1 == f2) return 0;
int idx1 = Flags.INBUILT_FLAGS.indexOf(f1.getName());
int idx2 = Flags.INBUILT_FLAGS.indexOf(f2.getName());
if (idx1 < 0 && idx2 >= 0) return 1;
if (idx2 < 0 && idx1 >= 0) return -1;
if (idx1 < 0) return f1.getName().compareTo(f2.getName());
return idx1 < idx2 ? -1 : 1;
})
.collect(Collectors.toList());
private static final int SIZE = FLAGS.size() == Flags.INBUILT_FLAGS.size() ? FLAGS.size() : FLAGS.size() + 1;
private static final int PAD_PX_SIZE = 180;
private final World world;
private final ProtectedRegion region;
private final RegionPermissionModel perms;
FlagHelperBox(World world, ProtectedRegion region, RegionPermissionModel perms) {
super("Flags for " + region.getId(), "/rg flags -w " + world.getName() + " " + region.getId() + " %page%");
this.world = world;
this.region = region;
this.perms = perms;
}
@Override
public Component getComponent(int number) {
if (number == Flags.INBUILT_FLAGS.size()) {
return centerAndBorder(TextComponent.of("Third-Party Flags", TextColor.AQUA));
} else if (number > Flags.INBUILT_FLAGS.size()) {
number -= 1;
}
Flag<?> flag = FLAGS.get(number);
return createLine(flag, number >= Flags.INBUILT_FLAGS.size()); }
@Override
public int getComponentsSize() {
return SIZE;
}
private Component createLine(Flag<?> flag, boolean thirdParty) {
final TextComponent.Builder builder = TextComponent.builder("");
appendFlagName(builder, flag, thirdParty ? TextColor.LIGHT_PURPLE : TextColor.GOLD);
appendFlagValue(builder, flag);
return builder.build();
}
private void appendFlagName(TextComponent.Builder builder, Flag<?> flag, TextColor color) {
final String name = flag.getName();
int length = FlagFontInfo.getPxLength(name);
builder.append(TextComponent.of(name, color));
if (flag.usesMembershipAsDefault()) {
builder.append(Component.empty().append(TextComponent.of("*", TextColor.AQUA))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("This is a special flag which defaults to allow for members, and deny for non-members"))));
length += FlagFontInfo.getPxLength('*');
}
if (flag == Flags.PASSTHROUGH) {
builder.append(Component.empty().append(TextComponent.of("*", TextColor.AQUA))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("This is a special flag which overrides build checks. (Not movement related!)"))));
length += FlagFontInfo.getPxLength('*');
}
int leftover = PAD_PX_SIZE - length;
builder.append(Component.space());
leftover -= 4;
if (leftover > 0) {
builder.append(TextComponent.of(Strings.repeat(".", leftover / 2), TextColor.DARK_GRAY));
}
}
private void appendFlagValue(TextComponent.Builder builder, Flag<?> flag) {
if (flag instanceof StateFlag) {
appendStateFlagValue(builder, (StateFlag) flag);
} else if (flag instanceof BooleanFlag) {
appendBoolFlagValue(builder, ((BooleanFlag) flag));
} else if (flag instanceof SetFlag) {
appendSetFlagValue(builder, ((SetFlag<?>) flag));
} else if (flag instanceof RegistryFlag) {
appendRegistryFlagValue(builder, ((RegistryFlag<?>) flag));
} else if (flag instanceof StringFlag) {
appendStringFlagValue(builder, ((StringFlag) flag));
} else if (flag instanceof LocationFlag) {
appendLocationFlagValue(builder, ((LocationFlag) flag));
} else if (flag instanceof IntegerFlag) {
appendNumericFlagValue(builder, (IntegerFlag) flag);
} else if (flag instanceof DoubleFlag) {
appendNumericFlagValue(builder, (DoubleFlag) flag);
} else {
String display = String.valueOf(region.getFlag(flag));
if (display.length() > 23) {
display = display.substring(0, 20) + "...";
}
appendValueText(builder, flag, display, null);
}
}
private <T> T getInheritedValue(ProtectedRegion region, Flag<T> flag) {
ProtectedRegion parent = region.getParent();
T val;
while (parent != null) {
val = parent.getFlag(flag);
if (val != null) {
return val;
}
parent = parent.getParent();
}
return null;
}
private <V> void appendValueChoices(TextComponent.Builder builder, Flag<V> flag, Iterator<V> choices, @Nullable String suggestChoice) {
V defVal = flag.getDefault();
V currVal = region.getFlag(flag);
boolean inherited = false;
if (currVal == null) {
currVal = getInheritedValue(region, flag);
if (currVal != null) {
inherited = true;
}
}
while (choices.hasNext()) {
V choice = choices.next();
boolean isExplicitSet = currVal == choice && !inherited;
boolean maySet = perms.maySetFlag(region, flag, isExplicitSet ? null : String.valueOf(choice));
TextColor col = isExplicitSet ? TextColor.WHITE : inherited && currVal == choice ? TextColor.GRAY : TextColor.DARK_GRAY;
Set<TextDecoration> styles = choice == defVal ? ImmutableSet.of(TextDecoration.UNDERLINED) : Collections.emptySet();
Component choiceComponent = Component.empty().append(TextComponent.of(capitalize(String.valueOf(choice)), col, styles));
List<Component> hoverTexts = new ArrayList<>();
if (maySet) {
if (isExplicitSet) {
hoverTexts.add(TextComponent.of("Click to unset", TextColor.GOLD));
} else {
hoverTexts.add(TextComponent.of("Click to set", TextColor.GOLD));
}
}
Component valType = getToolTipHint(defVal, choice, inherited);
if (valType != null) {
hoverTexts.add(valType);
}
if (!hoverTexts.isEmpty()) {
TextComponent.Builder hoverBuilder = TextComponent.builder("");
for (Iterator<Component> hovIt = hoverTexts.iterator(); hovIt.hasNext(); ) {
hoverBuilder.append(hovIt.next());
if (hovIt.hasNext()) {
hoverBuilder.append(Component.newline());
}
}
choiceComponent = choiceComponent.hoverEvent(
new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverBuilder.build()));
}
if (maySet) {
builder.append(choiceComponent.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
makeCommand(flag, isExplicitSet ? "" : choice))));
} else {
builder.append(choiceComponent);
}
builder.append(Component.space());
}
if (suggestChoice != null && perms.maySetFlag(region, flag)) {
builder.append(TextComponent.of(suggestChoice, TextColor.DARK_GRAY)
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
TextComponent.of("Click to set custom value", TextColor.GOLD)))
.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, makeCommand(flag, ""))));
}
}
private <V> void appendValueText(TextComponent.Builder builder, Flag<V> flag, String display, @Nullable Component hover) {
V defVal = flag.getDefault();
V currVal = region.getFlag(flag);
boolean inherited = false;
if (currVal == null) {
currVal = getInheritedValue(region, flag);
if (currVal != null) {
inherited = true;
}
}
boolean isExplicitSet = currVal != null && !inherited;
boolean maySet = perms.maySetFlag(region, flag);
TextColor col = isExplicitSet ? TextColor.WHITE : inherited ? TextColor.GRAY : TextColor.DARK_GRAY;
Set<TextDecoration> styles = currVal == defVal ? ImmutableSet.of(TextDecoration.UNDERLINED) : Collections.emptySet();
Component displayComponent = Component.empty().append(TextComponent.of(display, col, styles));
List<Component> hoverTexts = new ArrayList<>();
if (maySet) {
if (isExplicitSet) {
hoverTexts.add(TextComponent.of("Click to change", TextColor.GOLD));
} else {
hoverTexts.add(TextComponent.of("Click to set", TextColor.GOLD));
}
}
Component valType = getToolTipHint(defVal, currVal, inherited);
if (valType != null) {
hoverTexts.add(valType);
}
if (!hoverTexts.isEmpty()) {
TextComponent.Builder hoverBuilder = TextComponent.builder("");
for (Iterator<Component> hovIt = hoverTexts.iterator(); hovIt.hasNext(); ) {
hoverBuilder.append(hovIt.next());
if (hovIt.hasNext()) {
hoverBuilder.append(Component.newline());
}
}
if (hover != null) {
hoverBuilder.append(Component.newline());
hoverBuilder.append(hover);
}
displayComponent = displayComponent.hoverEvent(
new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverBuilder.build()));
}
if (maySet) {
builder.append(displayComponent.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND,
makeCommand(flag, ""))));
} else {
builder.append(displayComponent);
}
builder.append(Component.space());
}
private String makeCommand(Flag<?> flag, Object choice) {
return "/rg flag -w " + world.getName() + " -h " + getCurrentPage()
+ " " + region.getId() + " " + flag.getName() + " " + choice;
}
private String capitalize(String value) {
if (value.isEmpty()) return value;
value = value.toLowerCase();
return value.length() > 1
? Character.toUpperCase(value.charAt(0)) + value.substring(1)
: String.valueOf(Character.toUpperCase(value.charAt(0)));
}
@Nullable
private <V> Component getToolTipHint(V defVal, V currVal, boolean inherited) {
Component valType;
if (inherited) {
if (currVal == defVal) {
valType = TextComponent.of("Inherited & ")
.append(TextComponent.of("default")
.decoration(TextDecoration.UNDERLINED, true))
.append(TextComponent.of(" value"));
} else {
valType = TextComponent.of("Inherited value");
}
} else {
if (currVal == defVal) {
valType = Component.empty()
.append(TextComponent.of("Default")
.decoration(TextDecoration.UNDERLINED, true))
.append(TextComponent.of(" value"));
} else {
valType = null;
}
}
return valType;
}
private void appendStateFlagValue(TextComponent.Builder builder, StateFlag flag) {
final Iterator<StateFlag.State> choices = Iterators.forArray(StateFlag.State.values());
appendValueChoices(builder, flag, choices, null);
}
private void appendBoolFlagValue(TextComponent.Builder builder, BooleanFlag flag) {
final Iterator<Boolean> choices = Iterators.forArray(Boolean.TRUE, Boolean.FALSE);
appendValueChoices(builder, flag, choices, null);
}
private <V> void appendSetFlagValue(TextComponent.Builder builder, SetFlag<V> flag) {
Flag<V> subType = flag.getType();
Class<?> clazz = subType.getClass();
String subName;
subName = clazz.isAssignableFrom(RegistryFlag.class)
? ((RegistryFlag<?>) subType).getRegistry().getName()
: subType.getClass().getSimpleName().replace("Flag", "");
Set<V> currVal = region.getFlag(flag);
if (currVal == null) {
currVal = getInheritedValue(region, flag);
}
@SuppressWarnings("unchecked")
List<V> values = currVal == null ? Collections.emptyList() : (List<V>) flag.marshal(currVal);
String display = (currVal == null ? "" : currVal.size() + "x ") + subName;
final String stringValue = currVal == null ? ""
: values.stream().map(String::valueOf).collect(Collectors.joining(","));
TextComponent hoverComp = TextComponent.of("");
if (currVal != null) {
hoverComp = hoverComp.append(TextComponent.of("Current values:"))
.append(Component.newline()).append(TextComponent.of(stringValue));
}
appendValueText(builder, flag, display, hoverComp);
}
private void appendRegistryFlagValue(TextComponent.Builder builder, RegistryFlag<?> flag) {
final Registry<?> registry = flag.getRegistry();
String regName = registry.getName();
Keyed currVal = region.getFlag(flag);
if (currVal == null) {
currVal = getInheritedValue(region, flag);
}
String display = currVal == null ? regName : currVal.getId();
appendValueText(builder, flag, display, null);
}
private void appendLocationFlagValue(TextComponent.Builder builder, LocationFlag flag) {
Location currVal = region.getFlag(flag);
if (currVal == null) {
currVal = getInheritedValue(region, flag);
}
if (currVal == null) {
final Location defVal = flag.getDefault();
if (defVal == null) {
appendValueText(builder, flag, "unset location", null);
} else {
appendValueText(builder, flag, defVal.toString(), TextComponent.of("Default value:")
.append(Component.newline()).append(TextComponent.of(defVal.toString())));
}
} else {
appendValueText(builder, flag, currVal.toString(), TextComponent.of("Current value:")
.append(Component.newline()).append(TextComponent.of(currVal.toString())));
}
}
private <V extends Number> void appendNumericFlagValue(TextComponent.Builder builder, Flag<V> flag) {
Number currVal = region.getFlag(flag);
if (currVal == null) {
currVal = getInheritedValue(region, flag);
}
Number defVal = flag.getDefault();
Number[] suggested = getSuggestedNumbers(flag);
SortedSet<Number> choices = new TreeSet<>(Comparator.comparing(Number::doubleValue));
if (currVal != null) {
choices.add(currVal);
}
if (defVal != null) {
choices.add(defVal);
}
if (suggested.length > 0) {
choices.addAll(Arrays.asList(suggested));
}
//noinspection unchecked
appendValueChoices(builder, flag, (Iterator<V>) choices.iterator(), choices.isEmpty() ? "unset number" : "[custom]");
}
private Number[] getSuggestedNumbers(Flag<? extends Number> flag) {
if (flag == Flags.HEAL_AMOUNT || flag == Flags.FEED_AMOUNT) {
return new Number[]{0, 5, 10, 20};
} else if (flag == Flags.MIN_FOOD || flag == Flags.MIN_HEAL) {
return new Number[]{0, 10};
} else if (flag == Flags.MAX_FOOD || flag == Flags.MAX_HEAL) {
return new Number[]{10, 20};
} else if (flag == Flags.HEAL_DELAY || flag == Flags.FEED_DELAY) {
return new Number[]{0, 1, 5};
}
return new Number[0];
}
private void appendStringFlagValue(TextComponent.Builder builder, StringFlag flag) {
String currVal = region.getFlag(flag);
if (currVal == null) {
currVal = getInheritedValue(region, flag);
}
if (currVal == null) {
final String defVal = flag.getDefault();
if (defVal == null) {
appendValueText(builder, flag, "unset string", null);
} else {
final TextComponent defComp = LegacyComponentSerializer.INSTANCE.deserialize(defVal);
String display = reduceToText(defComp);
if (display.length() > 23) {
display = display.substring(0, 20) + "...";
}
appendValueText(builder, flag, display, TextComponent.of("Default value:")
.append(Component.newline()).append(defComp));
}
} else {
TextComponent currComp = LegacyComponentSerializer.INSTANCE.deserialize(currVal);
String display = reduceToText(currComp);
if (display.length() > 23) {
display = display.substring(0, 20) + "...";
}
appendValueText(builder, flag, display, TextComponent.of("Current value:")
.append(Component.newline()).append(currComp));
}
}
private static String reduceToText(Component component) {
StringBuilder text = new StringBuilder();
appendTextTo(text, component);
return text.toString();
}
private static void appendTextTo(StringBuilder builder, Component component) {
if (component instanceof TextComponent) {
builder.append(((TextComponent) component).content());
} else if (component instanceof TranslatableComponent) {
builder.append(((TranslatableComponent) component).key());
}
for (Component child : component.children()) {
appendTextTo(builder, child);
}
}
private static final class FlagFontInfo {
static int getPxLength(char c) {
switch (c) {
case 'i':
case ':':
return 1;
case 'l':
return 2;
case '*':
case 't':
return 3;
case 'f':
case 'k':
return 4;
default:
return 5;
}
}
static int getPxLength(String string) {
return string.chars().reduce(0, (p, i) -> p + getPxLength((char) i) + 1);
}
}
}

View File

@ -21,6 +21,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.sk89q.minecraft.util.commands.Command;
@ -35,6 +36,7 @@
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException;
import com.sk89q.worldedit.util.formatting.component.LabelFormat;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.Component;
@ -319,7 +321,7 @@ public void select(CommandContext args, Actor sender) throws CommandException {
// If no arguments were given, get the region that the player is inside
if (args.argsLength() == 0) {
existing = checkRegionStandingIn(manager, player);
existing = checkRegionStandingIn(manager, player, "/rg select %id%");
} else {
existing = checkExistingRegion(manager, args.getString(0), false);
}
@ -360,7 +362,8 @@ public void info(CommandContext args, Actor sender) throws CommandException {
throw new CommandException("Please specify the region with /region info -w world_name region_name.");
}
existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true);
existing = checkRegionStandingIn(manager, (LocalPlayer) sender, true,
"/rg info -w " + world.getName() + " %id%" + (args.hasFlag('u') ? " -u" : "") + (args.hasFlag('s') ? " -s" : ""));
} else { // Get region from the ID
existing = checkExistingRegion(manager, args.getString(0), true);
}
@ -463,7 +466,7 @@ public void list(CommandContext args, Actor sender) throws CommandException {
*/
@Command(aliases = {"flag", "f"},
usage = "<id> <flag> [-w world] [-g group] [value]",
flags = "g:w:e",
flags = "g:w:eh:",
desc = "Set flags",
min = 2)
public void flag(CommandContext args, Actor sender) throws CommandException {
@ -537,9 +540,9 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
sender.print(builder.build());
return;
} else {
} else if (value != null) {
if (foundFlag == Flags.BUILD || foundFlag == Flags.BLOCK_BREAK || foundFlag == Flags.BLOCK_PLACE) {
sender.print(Component.empty().append(TextComponent.of("WARNING:", TextColor.RED).decoration(TextDecoration.BOLD, true))
sender.print(Component.empty().append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" Setting the " + foundFlag.getName() + " flag is not required for protection."))
.append(Component.newline())
.append(TextComponent.of("Setting this flag will completely override default protection, and apply" +
@ -554,7 +557,7 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
sender.printRaw("https://worldguard.readthedocs.io/en/latest/regions/flags/#protection-related");
}
} else if (foundFlag == Flags.PASSTHROUGH) {
sender.print(Component.empty().append(TextComponent.of("WARNING:", TextColor.RED).decoration(TextDecoration.BOLD, true))
sender.print(Component.empty().append(TextComponent.of("WARNING:", TextColor.RED, Sets.newHashSet(TextDecoration.BOLD)))
.append(ErrorFormat.wrap(" This flag is unrelated to moving through regions."))
.append(Component.newline())
.append(TextComponent.of("It overrides build checks. If you're unsure what this means, see ")
@ -604,7 +607,9 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
throw new CommandException(e.getMessage());
}
sender.print("Region flag " + foundFlag.getName() + " set on '" + existing.getId() + "' to '" + value + "'.");
if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " set on '" + existing.getId() + "' to '" + value + "'.");
}
// No value? Clear the flag, if -g isn't specified
} else if (!args.hasFlag('g')) {
@ -617,7 +622,9 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
existing.setFlag(groupFlag, null);
}
sender.print("Region flag " + foundFlag.getName() + " removed from '" + existing.getId() + "'. (Any -g(roups) were also removed.)");
if (!args.hasFlag('h')) {
sender.print("Region flag " + foundFlag.getName() + " removed from '" + existing.getId() + "'. (Any -g(roups) were also removed.)");
}
}
// Now set the group
@ -635,11 +642,48 @@ public void flag(CommandContext args, Actor sender) throws CommandException {
}
// Print region information
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), existing, null, sender);
printout.append(SubtleFormat.wrap("(Current flags: "));
printout.appendFlagsList(false);
printout.append(SubtleFormat.wrap(")"));
printout.send(sender);
if (args.hasFlag('h')) {
int page = args.getFlagInteger('h');
try {
final FlagHelperBox flagHelperBox = new FlagHelperBox(world, existing, permModel);
flagHelperBox.setComponentsPerPage(18);
sender.print(flagHelperBox.create(page));
} catch (InvalidComponentException e) {
throw new CommandException("Error creating component.", e);
}
} else {
RegionPrintoutBuilder printout = new RegionPrintoutBuilder(world.getName(), existing, null, sender);
printout.append(SubtleFormat.wrap("(Current flags: "));
printout.appendFlagsList(false);
printout.append(SubtleFormat.wrap(")"));
printout.send(sender);
}
}
@Command(aliases = "flags",
usage = "<id> [page]",
flags = "w:",
desc = "View region flags",
min = 1, max = 2)
public void flagHelper(CommandContext args, Actor sender) throws CommandException {
World world = checkWorld(args, sender, 'w'); // Get the world
// Lookup the existing region
RegionManager manager = checkRegionManager(world);
ProtectedRegion region = checkExistingRegion(manager, args.getString(0), true);
final RegionPermissionModel perms = getPermissionModel(sender);
if (!perms.mayLookup(region)) {
throw new CommandPermissionsException();
}
int page = args.getInteger(1, 1);
try {
final FlagHelperBox flagHelperBox = new FlagHelperBox(world, region, perms);
flagHelperBox.setComponentsPerPage(18);
sender.print(flagHelperBox.create(page));
} catch (InvalidComponentException e) {
throw new CommandException("Error creating component.", e);
}
}
/**

View File

@ -34,6 +34,8 @@
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldguard.LocalPlayer;
@ -157,8 +159,8 @@ protected static ProtectedRegion checkExistingRegion(RegionManager regionManager
* @return a region
* @throws CommandException thrown if no region was found
*/
protected static ProtectedRegion checkRegionStandingIn(RegionManager regionManager, LocalPlayer player) throws CommandException {
return checkRegionStandingIn(regionManager, player, false);
protected static ProtectedRegion checkRegionStandingIn(RegionManager regionManager, LocalPlayer player, String rgCmd) throws CommandException {
return checkRegionStandingIn(regionManager, player, false, rgCmd);
}
/**
@ -176,7 +178,7 @@ protected static ProtectedRegion checkRegionStandingIn(RegionManager regionManag
* @return a region
* @throws CommandException thrown if no region was found
*/
protected static ProtectedRegion checkRegionStandingIn(RegionManager regionManager, LocalPlayer player, boolean allowGlobal) throws CommandException {
protected static ProtectedRegion checkRegionStandingIn(RegionManager regionManager, LocalPlayer player, boolean allowGlobal, String rgCmd) throws CommandException {
ApplicableRegionSet set = regionManager.getApplicableRegions(player.getLocation().toVector().toBlockPoint());
if (set.size() == 0) {
@ -190,19 +192,24 @@ protected static ProtectedRegion checkRegionStandingIn(RegionManager regionManag
"You're not standing in a region." +
"Specify an ID if you want to select a specific region.");
} else if (set.size() > 1) {
StringBuilder builder = new StringBuilder();
boolean first = true;
final TextComponent.Builder builder = TextComponent.builder("");
builder.append(TextComponent.of("Current regions: ", TextColor.GOLD));
for (ProtectedRegion region : set) {
if (!first) {
builder.append(", ");
builder.append(TextComponent.of(", "));
}
first = false;
builder.append(region.getId());
TextComponent regionComp = TextComponent.of(region.getId(), TextColor.AQUA);
if (rgCmd != null && rgCmd.contains("%id%")) {
regionComp = regionComp.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to pick this region")))
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, rgCmd.replace("%id%", region.getId())));
}
builder.append(regionComp);
}
throw new CommandException(
"You're standing in several regions (please pick one).\nYou're in: " + builder.toString());
player.print(builder.build());
throw new CommandException("You're standing in several regions (please pick one).");
}
return set.iterator().next();

View File

@ -163,9 +163,9 @@ public void appendFlagsList(boolean useColors) {
if (perms != null && perms.maySetFlag(region)) {
builder.append(Component.space())
.append(TextComponent.of("[Add]", useColors ? TextColor.GREEN : TextColor.GRAY)
.append(TextComponent.of("[Flags]", useColors ? TextColor.GREEN : TextColor.GRAY)
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to set a flag")))
.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/rg flag -w " + world + " " + region.getId() + " ")));
.clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/rg flags -w " + world + " " + region.getId())));
}
}

View File

@ -33,7 +33,15 @@
import com.sk89q.worldguard.protection.util.NormativeOrders;
import javax.annotation.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@ -49,7 +57,6 @@
*/
public class FlagValueCalculator {
private final List<ProtectedRegion> regions;
@Nullable
private final ProtectedRegion globalRegion;
private final Iterable<ProtectedRegion> applicable;
@ -63,14 +70,10 @@ public class FlagValueCalculator {
public FlagValueCalculator(List<ProtectedRegion> regions, @Nullable ProtectedRegion globalRegion) {
checkNotNull(regions);
this.regions = regions;
this.globalRegion = globalRegion;
if (globalRegion != null) {
applicable = Iterables.concat(regions, Arrays.asList(globalRegion));
} else {
applicable = regions;
}
applicable = globalRegion == null ? regions
: Iterables.concat(regions, Collections.singletonList(globalRegion));
}
/**
@ -128,7 +131,7 @@ public Result getMembership(RegionAssociable subject) {
minimumPriority = getPriority(region);
boolean member = RegionGroup.MEMBERS.contains(subject.getAssociation(Arrays.asList(region)));
boolean member = RegionGroup.MEMBERS.contains(subject.getAssociation(Collections.singletonList(region)));
if (member) {
result = Result.SUCCESS;

View File

@ -32,12 +32,18 @@
import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* The flags that are used in WorldGuard.
*/
public final class Flags {
private static final List<String> INBUILT_FLAGS_LIST = new ArrayList<>();
public static final List<String> INBUILT_FLAGS = Collections.unmodifiableList(INBUILT_FLAGS_LIST);
// Overrides membership check
public static final StateFlag PASSTHROUGH = register(new StateFlag("passthrough", false));
@ -91,7 +97,7 @@ public final class Flags {
// mob spawning related
public static final StateFlag MOB_SPAWNING = register(new StateFlag("mob-spawning", true));
public static final SetFlag<EntityType> DENY_SPAWN = register(new SetFlag<>("deny-spawn", new EntityTypeFlag(null)));
public static final SetFlag<EntityType> DENY_SPAWN = register(new SetFlag<>("deny-spawn", new RegistryFlag<>(null, EntityType.REGISTRY)));
// block dynamics
public static final StateFlag PISTONS = register(new StateFlag("pistons", true));
@ -111,6 +117,9 @@ public final class Flags {
public static final StateFlag WATER_FLOW = register(new StateFlag("water-flow", true));
public static final StateFlag LAVA_FLOW = register(new StateFlag("lava-flow", true));
public static final RegistryFlag<WeatherType> WEATHER_LOCK = register(new RegistryFlag<>("weather-lock", WeatherType.REGISTRY));
public static final StringFlag TIME_LOCK = register(new StringFlag("time-lock"));
// chat related flags
public static final StateFlag SEND_CHAT = register(new StateFlag("send-chat", true));
public static final StateFlag RECEIVE_CHAT = register(new StateFlag("receive-chat", true));
@ -140,9 +149,7 @@ public final class Flags {
public static final BooleanFlag NOTIFY_ENTER = register(new BooleanFlag("notify-enter"));
public static final BooleanFlag NOTIFY_LEAVE = register(new BooleanFlag("notify-leave"));
public static final Flag<GameMode> GAME_MODE = register(new GameModeTypeFlag("game-mode"));
public static final StringFlag TIME_LOCK = register(new StringFlag("time-lock"));
public static final Flag<WeatherType> WEATHER_LOCK = register(new WeatherTypeFlag("weather-lock"));
public static final RegistryFlag<GameMode> GAME_MODE = register(new RegistryFlag<>("game-mode", GameMode.REGISTRY));
public static final IntegerFlag HEAL_DELAY = register(new IntegerFlag("heal-delay"));
public static final IntegerFlag HEAL_AMOUNT = register(new IntegerFlag("heal-amount"));
@ -173,6 +180,7 @@ private Flags() {
private static <T extends Flag<?>> T register(final T flag) throws FlagConflictException {
WorldGuard.getInstance().getFlagRegistry().register(flag);
INBUILT_FLAGS_LIST.add(flag.getName());
return flag;
}

View File

@ -67,23 +67,14 @@ public static boolean isMember(ProtectedRegion region, RegionGroup group, @Nulla
if (group == null || group == RegionGroup.ALL) {
return true;
} else if (group == RegionGroup.OWNERS) {
if (player != null && region.isOwner(player)) {
return true;
}
return player != null && region.isOwner(player);
} else if (group == RegionGroup.MEMBERS) {
if (player != null && region.isMember(player)) {
return true;
}
return player != null && region.isMember(player);
} else if (group == RegionGroup.NON_OWNERS) {
if (player == null || !region.isOwner(player)) {
return true;
}
return player == null || !region.isOwner(player);
} else if (group == RegionGroup.NON_MEMBERS) {
if (player == null || !region.isMember(player)) {
return true;
}
return player == null || !region.isMember(player);
}
return false;
}
@ -91,23 +82,14 @@ public static boolean isMember(ApplicableRegionSet set, @Nullable RegionGroup gr
if (group == null || group == RegionGroup.ALL) {
return true;
} else if (group == RegionGroup.OWNERS) {
if (set.isOwnerOfAll(player)) {
return true;
}
return set.isOwnerOfAll(player);
} else if (group == RegionGroup.MEMBERS) {
if (set.isMemberOfAll(player)) {
return true;
}
return set.isMemberOfAll(player);
} else if (group == RegionGroup.NON_OWNERS) {
if (!set.isOwnerOfAll(player)) {
return true;
}
return !set.isOwnerOfAll(player);
} else if (group == RegionGroup.NON_MEMBERS) {
if (!set.isMemberOfAll(player)) {
return true;
}
return !set.isMemberOfAll(player);
}
return false;
}

View File

@ -0,0 +1,62 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.flags;
import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.registry.Registry;
import javax.annotation.Nullable;
import java.util.Locale;
import java.util.Optional;
public class RegistryFlag<T extends Keyed> extends Flag<T> {
private final Registry<T> registry;
public RegistryFlag(String name, Registry<T> registry) {
super(name);
this.registry = registry;
}
public RegistryFlag(String name, @Nullable RegionGroup defaultGroup, Registry<T> registry) {
super(name, defaultGroup);
this.registry = registry;
}
@Override
public T parseInput(FlagContext context) throws InvalidFlagFormat {
final String key = context.getUserInput().trim().toLowerCase(Locale.ENGLISH);
return Optional.ofNullable(registry.get(key))
.orElseThrow(() -> new InvalidFlagFormat("Unknown " + registry.getName() + ": " + key));
}
public Registry<T> getRegistry() {
return registry;
}
@Override
public T unmarshal(@Nullable Object o) {
return registry.get(String.valueOf(o));
}
@Override
public Object marshal(T o) {
return o.getId();
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldguard.protection.flags.registry;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@ -80,7 +79,7 @@ public void registerAll(Collection<Flag<?>> flags) {
private Flag<?> forceRegister(Flag<?> flag) throws FlagConflictException {
checkNotNull(flag, "flag");
Preconditions.checkNotNull(flag.getName(), "flag.getName()");
checkNotNull(flag.getName(), "flag.getName()");
synchronized (lock) {
String name = flag.getName().toLowerCase();