Copy paste/merge FAWE classes to this WorldEdit fork

- so certain people can look at the diff and complain about my sloppy code :(

Signed-off-by: Jesse Boyd <jessepaleg@gmail.com>
This commit is contained in:
Jesse Boyd
2018-08-13 00:03:07 +10:00
parent a920c77cb8
commit a629d15c74
994 changed files with 117583 additions and 10745 deletions

View File

@ -19,43 +19,97 @@
package com.sk89q.worldedit.util;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import javax.annotation.Nullable;
import java.util.HashMap;
/**
* A collection of cardinal, ordinal, and secondary-ordinal directions.
*/
public enum Direction {
NORTH(new Vector(0, 0, -1), Flag.CARDINAL),
EAST(new Vector(1, 0, 0), Flag.CARDINAL),
SOUTH(new Vector(0, 0, 1), Flag.CARDINAL),
WEST(new Vector(-1, 0, 0), Flag.CARDINAL),
NORTH(new Vector(0, 0, -1), Flag.CARDINAL, 3, 1),
EAST(new Vector(1, 0, 0), Flag.CARDINAL, 0, 2),
SOUTH(new Vector(0, 0, 1), Flag.CARDINAL, 1, 3),
WEST(new Vector(-1, 0, 0), Flag.CARDINAL, 2, 0),
UP(new Vector(0, 1, 0), Flag.UPRIGHT),
DOWN(new Vector(0, -1, 0), Flag.UPRIGHT),
UP(new Vector(0, 1, 0), Flag.UPRIGHT, -1, -1),
DOWN(new Vector(0, -1, 0), Flag.UPRIGHT, -1, -1),
NORTHEAST(new Vector(1, 0, -1), Flag.ORDINAL),
NORTHWEST(new Vector(-1, 0, -1), Flag.ORDINAL),
SOUTHEAST(new Vector(1, 0, 1), Flag.ORDINAL),
SOUTHWEST(new Vector(-1, 0, 1), Flag.ORDINAL),
NORTHEAST(new Vector(1, 0, -1), Flag.ORDINAL, 7, 8),
NORTHWEST(new Vector(-1, 0, -1), Flag.ORDINAL, 9, 6),
SOUTHEAST(new Vector(1, 0, 1), Flag.ORDINAL, 6, 9),
SOUTHWEST(new Vector(-1, 0, 1), Flag.ORDINAL, 8, 7),
WEST_NORTHWEST(new Vector(-Math.cos(Math.PI / 8), 0, -Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL),
WEST_SOUTHWEST(new Vector(-Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL),
NORTH_NORTHWEST(new Vector(-Math.sin(Math.PI / 8), 0, -Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL),
NORTH_NORTHEAST(new Vector(Math.sin(Math.PI / 8), 0, -Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL),
EAST_NORTHEAST(new Vector(Math.cos(Math.PI / 8), 0, -Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL),
EAST_SOUTHEAST(new Vector(Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL),
SOUTH_SOUTHEAST(new Vector(Math.sin(Math.PI / 8), 0, Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL),
SOUTH_SOUTHWEST(new Vector(-Math.sin(Math.PI / 8), 0, Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL);
WEST_NORTHWEST(new Vector(-Math.cos(Math.PI / 8), 0, -Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL, 9, 6),
WEST_SOUTHWEST(new Vector(-Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL, 8, 7),
NORTH_NORTHWEST(new Vector(-Math.sin(Math.PI / 8), 0, -Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL, 9, 6),
NORTH_NORTHEAST(new Vector(Math.sin(Math.PI / 8), 0, -Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL, 7, 8),
EAST_NORTHEAST(new Vector(Math.cos(Math.PI / 8), 0, -Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL, 7, 8),
EAST_SOUTHEAST(new Vector(Math.cos(Math.PI / 8), 0, Math.sin(Math.PI / 8)), Flag.SECONDARY_ORDINAL, 6, 9),
SOUTH_SOUTHEAST(new Vector(Math.sin(Math.PI / 8), 0, Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL, 6, 9),
SOUTH_SOUTHWEST(new Vector(-Math.sin(Math.PI / 8), 0, Math.cos(Math.PI / 8)), Flag.SECONDARY_ORDINAL, 8, 7);
private final Vector direction;
private final int flags;
private final BlockVector blockVector;
private final int flags, left, right;
Direction(Vector vector, int flags) {
private static HashMap<String, Direction> map = new HashMap<>();
public static final Direction[] values = values();
public static final Direction[] cardinal = new Direction[]{ NORTH, EAST, SOUTH, WEST };
static {
for (Direction dir : Direction.values()) {
map.put(dir.name(), dir);
map.put(dir.name().toLowerCase(), dir);
}
}
private Direction(Vector vector, int flags, int left, int right) {
this.direction = vector.normalize();
this.blockVector = new BlockVector(Math.signum(vector.getX()), Math.signum(vector.getY()), Math.signum(vector.getZ()));
this.flags = flags;
this.left = left;
this.right = right;
}
public static Direction get(CharSequence sequence) {
return map.get(sequence);
}
public Direction getLeft() {
return left != -1 ? values[left] : null;
}
public Direction getRight() {
return right != -1 ? values[right] : null;
}
public double getX() {
return direction.getX();
}
public double getY() {
return direction.getY();
}
public double getZ() {
return direction.getZ();
}
public int getBlockX() {
return blockVector.getBlockX();
}
public int getBlockY() {
return blockVector.getBlockY();
}
public int getBlockZ() {
return blockVector.getBlockZ();
}
/**
@ -109,6 +163,15 @@ public enum Direction {
return direction;
}
public BlockVector toBlockVector() {
return this.blockVector;
}
@Override
public String toString() {
return name().toLowerCase();
}
/**
* Find the closest direction to the given direction vector.
*

View File

@ -19,10 +19,10 @@
package com.sk89q.worldedit.util;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Helper methods for enums.
*/

View File

@ -21,14 +21,13 @@ package com.sk89q.worldedit.util;
import com.sk89q.util.StringUtil;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
public final class FileDialogUtil {
private FileDialogUtil() {
}

View File

@ -19,10 +19,10 @@
package com.sk89q.worldedit.util;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
public final class GuavaUtil {
private GuavaUtil() {}

View File

@ -19,10 +19,11 @@
package com.sk89q.worldedit.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.NullWorld;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Represents a location in a world with has a direction.
@ -34,10 +35,9 @@ import com.sk89q.worldedit.extent.Extent;
* {@link #equals(Object)} are subject to minor differences caused by
* floating point errors.</p>
*/
public class Location {
public class Location extends Vector {
private final Extent extent;
private final Vector position;
private final float pitch;
private final float yaw;
@ -126,10 +126,9 @@ public class Location {
* @param pitch the pitch, in degrees
*/
public Location(Extent extent, Vector position, float yaw, float pitch) {
super(position);
checkNotNull(extent);
checkNotNull(position);
this.extent = extent;
this.position = position;
this.pitch = pitch;
this.yaw = yaw;
}
@ -150,7 +149,7 @@ public class Location {
* @return the new instance
*/
public Location setExtent(Extent extent) {
return new Location(extent, position, getDirection());
return new Location(extent, this, getDirection());
}
/**
@ -169,7 +168,7 @@ public class Location {
* @return the new instance
*/
public Location setYaw(float yaw) {
return new Location(extent, position, yaw, pitch);
return new Location(extent, this, yaw, pitch);
}
/**
@ -188,7 +187,7 @@ public class Location {
* @return the new instance
*/
public Location setPitch(float pitch) {
return new Location(extent, position, yaw, pitch);
return new Location(extent, this, yaw, pitch);
}
/**
@ -199,7 +198,7 @@ public class Location {
* @return the new instance
*/
public Location setDirection(float yaw, float pitch) {
return new Location(extent, position, yaw, pitch);
return new Location(extent, this, yaw, pitch);
}
/**
@ -233,7 +232,7 @@ public class Location {
* @return the new instance
*/
public Location setDirection(Vector direction) {
return new Location(extent, position, direction.toYaw(), direction.toPitch());
return new Location(extent, this, direction.toYaw(), direction.toPitch());
}
/**
@ -242,25 +241,7 @@ public class Location {
* @return a vector
*/
public Vector toVector() {
return position;
}
/**
* Get the X component of the position vector.
*
* @return the X component
*/
public double getX() {
return position.getX();
}
/**
* Get the rounded X component of the position vector.
*
* @return the rounded X component
*/
public int getBlockX() {
return position.getBlockX();
return this;
}
/**
@ -271,7 +252,7 @@ public class Location {
* @return a new immutable instance
*/
public Location setX(double x) {
return new Location(extent, position.setX(x), yaw, pitch);
return new Location(extent, super.setX(x), yaw, pitch);
}
/**
@ -282,25 +263,7 @@ public class Location {
* @return a new immutable instance
*/
public Location setX(int x) {
return new Location(extent, position.setX(x), yaw, pitch);
}
/**
* Get the Y component of the position vector.
*
* @return the Y component
*/
public double getY() {
return position.getY();
}
/**
* Get the rounded Y component of the position vector.
*
* @return the rounded Y component
*/
public int getBlockY() {
return position.getBlockY();
return new Location(extent, super.setX(x), yaw, pitch);
}
/**
@ -311,7 +274,7 @@ public class Location {
* @return a new immutable instance
*/
public Location setY(double y) {
return new Location(extent, position.setY(y), yaw, pitch);
return new Location(extent, super.setY(y), yaw, pitch);
}
/**
@ -322,25 +285,7 @@ public class Location {
* @return a new immutable instance
*/
public Location setY(int y) {
return new Location(extent, position.setY(y), yaw, pitch);
}
/**
* Get the Z component of the position vector.
*
* @return the Z component
*/
public double getZ() {
return position.getZ();
}
/**
* Get the rounded Z component of the position vector.
*
* @return the rounded Z component
*/
public int getBlockZ() {
return position.getBlockZ();
return new Location(extent, super.setY(y), yaw, pitch);
}
/**
@ -351,7 +296,7 @@ public class Location {
* @return a new immutable instance
*/
public Location setZ(double z) {
return new Location(extent, position.setZ(z), yaw, pitch);
return new Location(extent, super.setZ(z), yaw, pitch);
}
/**
@ -362,7 +307,7 @@ public class Location {
* @return a new immutable instance
*/
public Location setZ(int z) {
return new Location(extent, position.setZ(z), yaw, pitch);
return new Location(extent, super.setZ(z), yaw, pitch);
}
/**
@ -384,7 +329,9 @@ public class Location {
if (Double.doubleToLongBits(pitch) != Double.doubleToLongBits(location.pitch)) return false;
if (Double.doubleToLongBits(yaw) != Double.doubleToLongBits(location.yaw)) return false;
if (!position.equals(location.position)) return false;
if (this.getX() != location.getX()) return false;
if (this.getZ() != location.getZ()) return false;
if (this.getY() != location.getY()) return false;
if (!extent.equals(location.extent)) return false;
return true;
@ -393,7 +340,7 @@ public class Location {
@Override
public int hashCode() {
int result = extent.hashCode();
result = 31 * result + position.hashCode();
result = 31 * result + this.hashCode();
result = 31 * result + Float.floatToIntBits(this.pitch);
result = 31 * result + Float.floatToIntBits(this.yaw);
return result;

View File

@ -21,9 +21,12 @@
package com.sk89q.worldedit.util;
import com.google.common.collect.Lists;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
@ -40,6 +43,7 @@ import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* Simple LocalConfiguration that loads settings using
@ -75,7 +79,13 @@ public class PropertiesConfiguration extends LocalConfiguration {
loadExtra();
profile = getBool("profile", profile);
disallowedBlocks = getStringSet("disallowed-blocks", defaultDisallowedBlocks);
disallowedBlocks =
new HashSet<>(getStringSet("limits.disallowed-blocks", defaultDisallowedBlocks))
.stream().map(e -> BlockTypes.parse(e)).collect(Collectors.toSet());
allowedDataCycleBlocks =
new HashSet<>(getStringSet("limits.allowed-data-cycle-blocks", null))
.stream().map(e -> BlockTypes.parse(e)).collect(Collectors.toSet());
defaultChangeLimit = getInt("default-max-changed-blocks", defaultChangeLimit);
maxChangeLimit = getInt("max-changed-blocks", maxChangeLimit);
defaultMaxPolygonalPoints = getInt("default-max-polygon-points", defaultMaxPolygonalPoints);
@ -90,22 +100,14 @@ public class PropertiesConfiguration extends LocalConfiguration {
logFile = getString("log-file", logFile);
logFormat = getString("log-format", logFormat);
registerHelp = getBool("register-help", registerHelp);
wandItem = getString("wand-item", wandItem);
try {
wandItem = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(wandItem)).getId();
} catch (Throwable e) {
}
wandItem = ItemTypes.parse(getString("wand-item", wandItem.getId()));
superPickaxeDrop = getBool("super-pickaxe-drop-items", superPickaxeDrop);
superPickaxeManyDrop = getBool("super-pickaxe-many-drop-items", superPickaxeManyDrop);
noDoubleSlash = getBool("no-double-slash", noDoubleSlash);
useInventory = getBool("use-inventory", useInventory);
useInventoryOverride = getBool("use-inventory-override", useInventoryOverride);
useInventoryCreativeOverride = getBool("use-inventory-creative-override", useInventoryCreativeOverride);
navigationWand = getString("nav-wand-item", navigationWand);
try {
navigationWand = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(navigationWand)).getId();
} catch (Throwable e) {
}
navigationWand = ItemTypes.parse(getString("navigation-wand.item", navigationWand.getId()));
navigationWandMaxDistance = getInt("nav-wand-distance", navigationWandMaxDistance);
navigationUseGlass = getBool("nav-use-glass", navigationUseGlass);
scriptTimeout = getInt("scripting-timeout", scriptTimeout);

View File

@ -19,15 +19,14 @@
package com.sk89q.worldedit.util;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockTypes;
/**
* This class uses an inefficient method to figure out what block a player
* is looking towards.
*
*
* <p>Originally written by toi. It was ported to WorldEdit and trimmed down by
* sk89q. Thanks to Raphfrk for optimization of toi's original class.</p>
*/
@ -43,13 +42,12 @@ public class TargetBlock {
/**
* Constructor requiring a player, uses default values
*
*
* @param player player to work with
*/
public TargetBlock(Player player) {
this.world = player.getWorld();
this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(),
300, 1.65, 0.2);
this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), 300, 1.65, 0.2);
}
/**
@ -66,7 +64,7 @@ public class TargetBlock {
/**
* Set the values, all constructors uses this function
*
*
* @param loc location of the view
* @param xRotation the X rotation
* @param yRotation the Y rotation
@ -74,7 +72,8 @@ public class TargetBlock {
* @param viewHeight where the view is positioned in y-axis
* @param checkDistance how often to check for blocks, the smaller the more precise
*/
private void setValues(Vector loc, double xRotation, double yRotation, int maxDistance, double viewHeight, double checkDistance) {
private void setValues(Vector loc, double xRotation, double yRotation,
int maxDistance, double viewHeight, double checkDistance) {
this.maxDistance = maxDistance;
this.checkDistance = checkDistance;
this.curDistance = 0;
@ -84,8 +83,8 @@ public class TargetBlock {
double h = (checkDistance * Math.cos(Math.toRadians(yRotation)));
offset = new Vector((h * Math.cos(Math.toRadians(xRotation))),
(checkDistance * Math.sin(Math.toRadians(yRotation))),
(h * Math.sin(Math.toRadians(xRotation))));
(checkDistance * Math.sin(Math.toRadians(yRotation))),
(h * Math.sin(Math.toRadians(xRotation))));
targetPosDouble = loc.add(0, viewHeight, 0);
targetPos = targetPosDouble.toBlockPoint();
@ -95,14 +94,14 @@ public class TargetBlock {
/**
* Returns any block at the sight. Returns null if out of range or if no
* viable target was found. Will try to return the last valid air block it finds.
*
*
* @return Block
*/
public Location getAnyTargetBlock() {
boolean searchForLastBlock = true;
Location lastBlock = null;
while (getNextBlock() != null) {
if (world.getBlock(getCurrentBlock().toVector()).getBlockType() == BlockTypes.AIR) {
if (world.getLazyBlock(getCurrentBlock().toVector()).getBlockType().getMaterial().isAir()) {
if (searchForLastBlock) {
lastBlock = getCurrentBlock();
if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= world.getMaxY()) {
@ -120,18 +119,18 @@ public class TargetBlock {
/**
* Returns the block at the sight. Returns null if out of range or if no
* viable target was found
*
*
* @return Block
*/
public Location getTargetBlock() {
while (getNextBlock() != null && world.getBlock(getCurrentBlock().toVector()).getBlockType() == BlockTypes.AIR) ;
while (getNextBlock() != null && world.getLazyBlock(getCurrentBlock().toVector()).getBlockType().getMaterial().isAir()) ;
return getCurrentBlock();
}
/**
* Returns the block at the sight. Returns null if out of range or if no
* viable target was found
*
*
* @return Block
*/
public Location getSolidTargetBlock() {
@ -141,7 +140,7 @@ public class TargetBlock {
/**
* Get next block
*
*
* @return next block position
*/
public Location getNextBlock() {
@ -150,8 +149,8 @@ public class TargetBlock {
curDistance += checkDistance;
targetPosDouble = offset.add(targetPosDouble.getX(),
targetPosDouble.getY(),
targetPosDouble.getZ());
targetPosDouble.getY(),
targetPosDouble.getZ());
targetPos = targetPosDouble.toBlockPoint();
} while (curDistance <= maxDistance
&& targetPos.getBlockX() == prevPos.getBlockX()
@ -167,7 +166,7 @@ public class TargetBlock {
/**
* Returns the current block along the line of vision
*
*
* @return block position
*/
public Location getCurrentBlock() {
@ -180,7 +179,7 @@ public class TargetBlock {
/**
* Returns the previous block in the aimed path
*
*
* @return block position
*/
public Location getPreviousBlock() {

View File

@ -23,8 +23,8 @@ import com.google.common.collect.Sets;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Collections;
@ -179,8 +179,8 @@ public class TreeGenerator {
int trunkHeight = (int) Math.floor(Math.random() * 2) + 3;
int height = (int) Math.floor(Math.random() * 5) + 8;
BlockState logBlock = BlockTypes.OAK_LOG.getDefaultState();
BlockState leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState();
BlockStateHolder logBlock = BlockTypes.OAK_LOG.getDefaultState();
BlockStateHolder leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState();
// Create trunk
for (int i = 0; i < trunkHeight; ++i) {

View File

@ -24,12 +24,15 @@ import com.sk89q.util.yaml.YAMLProcessor;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.session.SessionManager;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
import java.io.IOException;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* A less simple implementation of {@link LocalConfiguration}
@ -49,12 +52,13 @@ public class YAMLConfiguration extends LocalConfiguration {
public void load() {
try {
config.load();
} catch (IOException e) {
} catch (Throwable e) {
logger.log(Level.WARNING, "Error loading WorldEdit configuration", e);
}
// TODO FIXME use Config class with comments / bindings
profile = config.getBoolean("debug", profile);
wandItem = convertLegacyItem(config.getString("wand-item", wandItem));
wandItem = ItemTypes.parse(config.getString("wand-item", wandItem.getId()));
defaultChangeLimit = Math.max(-1, config.getInt(
"limits.max-blocks-changed.default", defaultChangeLimit));
@ -77,8 +81,12 @@ public class YAMLConfiguration extends LocalConfiguration {
butcherDefaultRadius = Math.max(-1, config.getInt("limits.butcher-radius.default", butcherDefaultRadius));
butcherMaxRadius = Math.max(-1, config.getInt("limits.butcher-radius.maximum", butcherMaxRadius));
disallowedBlocks = new HashSet<>(config.getStringList("limits.disallowed-blocks", Lists.newArrayList(defaultDisallowedBlocks)));
allowedDataCycleBlocks = new HashSet<>(config.getStringList("limits.allowed-data-cycle-blocks", null));
disallowedBlocks =
new HashSet<>(config.getStringList("limits.disallowed-blocks", Lists.newArrayList(defaultDisallowedBlocks)))
.stream().map(e -> BlockTypes.parse(e)).collect(Collectors.toSet());
allowedDataCycleBlocks =
new HashSet<>(config.getStringList("limits.allowed-data-cycle-blocks", null))
.stream().map(e -> BlockTypes.parse(e)).collect(Collectors.toSet());
registerHelp = config.getBoolean("register-help", true);
logCommands = config.getBoolean("logging.log-commands", logCommands);
@ -98,7 +106,7 @@ public class YAMLConfiguration extends LocalConfiguration {
useInventoryCreativeOverride = config.getBoolean("use-inventory.creative-mode-overrides",
useInventoryCreativeOverride);
navigationWand = convertLegacyItem(config.getString("navigation-wand.item", navigationWand));
navigationWand = ItemTypes.parse(config.getString("navigation-wand.item", navigationWand.getId()));
navigationWandMaxDistance = config.getInt("navigation-wand.max-distance", navigationWandMaxDistance);
navigationUseGlass = config.getBoolean("navigation.use-glass", navigationUseGlass);

View File

@ -19,11 +19,11 @@
package com.sk89q.worldedit.util.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.ArrayList;
import java.util.Map;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**

View File

@ -19,13 +19,13 @@
package com.sk89q.worldedit.util.collection;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A fast iterator for lists that uses an internal index integer
* and caches the size of the list. The size of the list cannot change

View File

@ -0,0 +1,12 @@
package com.sk89q.worldedit.util.command;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.WorldEditException;
public interface CallableProcessor<T> {
public Object process(CommandLocals locals, T value) throws CommandException, WorldEditException;
}

View File

@ -0,0 +1,37 @@
package com.sk89q.worldedit.util.command;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import java.util.List;
public class DelegateCallable implements CommandCallable {
private final CommandCallable parent;
public CommandCallable getParent() {
return parent;
}
public DelegateCallable(CommandCallable parent) {
this.parent = parent;
}
@Override
public Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException {
return parent.call(arguments, locals, parentCommands);
}
@Override
public Description getDescription() {
return parent.getDescription();
}
@Override
public boolean testPermission(CommandLocals locals) {
return parent.testPermission(locals);
}
@Override
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
return parent.getSuggestions(arguments, locals);
}
}

View File

@ -19,11 +19,10 @@
package com.sk89q.worldedit.util.command;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Executes a command based on user input.
*/

View File

@ -19,12 +19,12 @@
package com.sk89q.worldedit.util.command;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.minecraft.util.commands.CommandException;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Thrown when a command is not used properly.
*

View File

@ -19,11 +19,10 @@
package com.sk89q.worldedit.util.command;
import javax.annotation.Nullable;
import java.util.Comparator;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
/**
* Compares the primary aliases of two {@link CommandMapping} using
* {@link String#compareTo(String)}.

View File

@ -0,0 +1,27 @@
package com.sk89q.worldedit.util.command;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.WorldEditException;
import static com.google.common.base.Preconditions.checkNotNull;
public class ProcessedCallable extends DelegateCallable {
private final CallableProcessor processor;
public ProcessedCallable(CommandCallable parent, CallableProcessor processor) {
super(parent);
checkNotNull(processor);
this.processor = processor;
}
@Override
public Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException {
try {
return processor.process(locals, super.call(arguments, locals, parentCommands));
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -19,19 +19,21 @@
package com.sk89q.worldedit.util.command;
import com.sk89q.worldedit.util.command.parametric.ParametricCallable;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Tracks a command registration.
*/
public class SimpleCommandMapping implements CommandMapping {
private final String[] aliases;
private final CommandCallable callable;
/**
* Create a new instance.
*
*
* @param callable the command callable
* @param alias a list of all aliases, where the first one is the primary one
*/
@ -45,12 +47,12 @@ public class SimpleCommandMapping implements CommandMapping {
public String getPrimaryAlias() {
return aliases[0];
}
@Override
public String[] getAllAliases() {
return aliases;
}
@Override
public CommandCallable getCallable() {
return callable;
@ -61,6 +63,30 @@ public class SimpleCommandMapping implements CommandMapping {
return getCallable().getDescription();
}
@Override
public int hashCode() {
return getPrimaryAlias().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof CommandMapping)) {
return false;
}
CommandMapping other = (CommandMapping) obj;
if (other.getCallable() != getCallable()) {
if (other.getCallable().getClass() != getCallable().getClass() || !(getCallable() instanceof ParametricCallable)) {
return false;
}
Method oMeth = ((ParametricCallable) other.getCallable()).getMethod();
Method meth = ((ParametricCallable) getCallable()).getMethod();
if (!oMeth.equals(meth)) {
return false;
}
}
return other.getPrimaryAlias().equals(getPrimaryAlias());
}
@Override
public String toString() {
return "CommandMapping{" +
@ -69,4 +95,8 @@ public class SimpleCommandMapping implements CommandMapping {
'}';
}
public static Class<?> inject() {
return SimpleCommandMapping.class;
}
}

View File

@ -19,13 +19,13 @@
package com.sk89q.worldedit.util.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.util.StringMan;
import com.google.common.base.Joiner;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.minecraft.util.commands.WrappedCommandException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -40,7 +40,7 @@ import java.util.Set;
*/
public class SimpleDispatcher implements Dispatcher {
private final Map<String, CommandMapping> commands = new HashMap<>();
private final Map<String, CommandMapping> commands = new HashMap<String, CommandMapping>();
private final SimpleDescription description = new SimpleDescription();
/**
@ -56,35 +56,42 @@ public class SimpleDispatcher implements Dispatcher {
@Override
public void registerCommand(CommandCallable callable, String... alias) {
CommandMapping mapping = new SimpleCommandMapping(callable, alias);
// Check for replacements
for (String a : alias) {
String lower = a.toLowerCase();
if (commands.containsKey(lower)) {
throw new IllegalArgumentException(
"Replacing commands is currently undefined behavior");
CommandMapping existing = commands.get(lower);
if (existing != null) {
CommandCallable existingCallable = existing.getCallable();
if (existingCallable instanceof Dispatcher && callable instanceof Dispatcher) {
Dispatcher existingDispatcher = (Dispatcher) existingCallable;
Dispatcher newDispatcher = (Dispatcher) callable;
for (CommandMapping add : newDispatcher.getCommands()) {
existingDispatcher.registerCommand(add.getCallable(), add.getAllAliases());
}
continue;
} else {
Fawe.debug("Replacing commands is currently undefined behavior: " + StringMan.getString(alias));
continue;
}
}
}
for (String a : alias) {
String lower = a.toLowerCase();
commands.put(lower, mapping);
commands.putIfAbsent(lower, mapping);
}
}
@Override
public Set<CommandMapping> getCommands() {
return Collections.unmodifiableSet(new HashSet<>(commands.values()));
return Collections.unmodifiableSet(new HashSet<CommandMapping>(commands.values()));
}
@Override
public Set<String> getAliases() {
return Collections.unmodifiableSet(commands.keySet());
}
@Override
public Set<String> getPrimaryAliases() {
Set<String> aliases = new HashSet<>();
Set<String> aliases = new HashSet<String>();
for (CommandMapping mapping : getCommands()) {
aliases.add(mapping.getPrimaryAlias());
}
@ -108,7 +115,7 @@ public class SimpleDispatcher implements Dispatcher {
throw new CommandPermissionsException();
}
String[] split = CommandContext.split(arguments);
String[] split = arguments.split(" ", -1);
Set<String> aliases = getPrimaryAliases();
if (aliases.isEmpty()) {
@ -138,12 +145,12 @@ public class SimpleDispatcher implements Dispatcher {
@Override
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
String[] split = CommandContext.split(arguments);
String[] split = arguments.split(" ", -1);
if (split.length <= 1) {
String prefix = split.length > 0 ? split[0] : "";
List<String> suggestions = new ArrayList<>();
List<String> suggestions = new ArrayList<String>();
for (CommandMapping mapping : getCommands()) {
if (mapping.getCallable().testPermission(locals)) {
@ -177,13 +184,12 @@ public class SimpleDispatcher implements Dispatcher {
@Override
public boolean testPermission(CommandLocals locals) {
for (CommandMapping mapping : getCommands()) {
if (mapping.getCallable().testPermission(locals)) {
return true;
}
}
return false;
// Checking every perm in the class here was unnecessarily stupid
return true;
}
}
public static Class<SimpleDispatcher> inject() {
return SimpleDispatcher.class;
}
}

View File

@ -28,9 +28,8 @@ import com.sk89q.worldedit.util.command.parametric.BindingHelper;
import com.sk89q.worldedit.util.command.parametric.BindingMatch;
import com.sk89q.worldedit.util.command.parametric.ParameterException;
import java.lang.annotation.Annotation;
import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
/**
* Handles basic Java types such as {@link String}s, {@link Byte}s, etc.

View File

@ -25,16 +25,15 @@ import com.google.common.collect.Maps;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.util.command.argument.CommandArgs;
import com.sk89q.worldedit.util.command.argument.MissingArgumentException;
import com.sk89q.worldedit.util.command.composition.FlagParser.FlagData;
import com.sk89q.worldedit.util.command.argument.MissingArgumentException;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
public class FlagParser implements CommandExecutor<FlagData> {
private final Map<Character, CommandExecutor<?>> flags = Maps.newHashMap();

View File

@ -19,10 +19,15 @@
package com.sk89q.worldedit.util.command.fluent;
import com.boydti.fawe.config.Commands;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.worldedit.util.command.CallableProcessor;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.SimpleDispatcher;
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
/**
* A collection of commands.
@ -32,27 +37,27 @@ public class DispatcherNode {
private final CommandGraph graph;
private final DispatcherNode parent;
private final SimpleDispatcher dispatcher;
/**
* Create a new instance.
*
* @param graph the root fluent graph object
* @param parent the parent node, or null
*
* @param graph the root fluent graph object
* @param parent the parent node, or null
* @param dispatcher the dispatcher for this node
*/
DispatcherNode(CommandGraph graph, DispatcherNode parent,
SimpleDispatcher dispatcher) {
public DispatcherNode(CommandGraph graph, DispatcherNode parent,
SimpleDispatcher dispatcher) {
this.graph = graph;
this.parent = parent;
this.dispatcher = dispatcher;
}
/**
* Set the description.
*
* <p>
* <p>This can only be used on {@link DispatcherNode}s returned by
* {@link #group(String...)}.</p>
*
*
* @param description the description
* @return this object
*/
@ -63,9 +68,9 @@ public class DispatcherNode {
/**
* Register a command with this dispatcher.
*
*
* @param callable the executor
* @param alias the list of aliases, where the first alias is the primary one
* @param alias the list of aliases, where the first alias is the primary one
*/
public DispatcherNode register(CommandCallable callable, String... alias) {
dispatcher.registerCommand(callable, alias);
@ -73,40 +78,90 @@ public class DispatcherNode {
}
/**
* Build and register a command with this dispatcher using the
* Build and register a command with this dispatcher using the
* {@link ParametricBuilder} assigned on the root {@link CommandGraph}.
*
*
* @param object the object provided to the {@link ParametricBuilder}
* @return this object
* @see ParametricBuilder#registerMethodsAsCommands(com.sk89q.worldedit.util.command.Dispatcher, Object)
*/
public DispatcherNode registerMethods(Object object) {
return registerMethods(object, null);
}
/**
* Build and register a command with this dispatcher using the
* {@link ParametricBuilder} assigned on the root {@link CommandGraph}.
*
* @param object the object provided to the {@link ParametricBuilder}
* @return this object
* @see ParametricBuilder#registerMethodsAsCommands(com.sk89q.worldedit.util.command.Dispatcher, Object)
*/
public DispatcherNode registerMethods(Object object, @Nullable CallableProcessor processor) {
ParametricBuilder builder = graph.getBuilder();
if (builder == null) {
throw new RuntimeException("No ParametricBuilder set");
}
builder.registerMethodsAsCommands(getDispatcher(), object);
builder.registerMethodsAsCommands(getDispatcher(), object, processor);
return this;
}
/**
* Build and register sub commands with this dispatcher using the
* {@link ParametricBuilder} assigned on the objects registered command aliases {@link com.sk89q.minecraft.util.commands.Command}.
*
* @param object the object provided to the {@link ParametricBuilder}
* @return this object
*/
public DispatcherNode registerSubMethods(Object object) {
return registerSubMethods(object, null);
}
/**
* Build and register sub commands with this dispatcher using the
* {@link ParametricBuilder} assigned on the objects registered command aliases {@link com.sk89q.minecraft.util.commands.Command}.
*
* @param object the object provided to the {@link ParametricBuilder}
* @param processor the command processor
* @return this object
*/
public DispatcherNode registerSubMethods(Object object, @Nullable CallableProcessor processor) {
Class<? extends Object> clazz = object.getClass();
return groupAndDescribe(clazz).registerMethods(object, processor).parent();
}
public DispatcherNode groupAndDescribe(Class clazz) {
Command cmd = (Command) clazz.getAnnotation(Command.class);
if (cmd == null) {
throw new RuntimeException("This class does not have any command annotations");
}
cmd = Commands.translate(clazz, cmd);
DispatcherNode res = group(cmd.aliases());
if (cmd.desc() != null && !cmd.desc().isEmpty()) {
res = res.describeAs(cmd.desc());
}
return res;
}
/**
* Create a new command that will contain sub-commands.
*
* <p>
* <p>The object returned by this method can be used to add sub-commands. To
* return to this "parent" context, use {@link DispatcherNode#graph()}.</p>
*
*
* @param alias the list of aliases, where the first alias is the primary one
* @return an object to place sub-commands
*/
public DispatcherNode group(String... alias) {
SimpleDispatcher command = new SimpleDispatcher();
getDispatcher().registerCommand(command, alias);
return new DispatcherNode(graph, this, command);
DispatcherNode res = new DispatcherNode(graph, this, command);
return res;
}
/**
* Return the parent node.
*
*
* @return the parent node
* @throws RuntimeException if there is no parent node.
*/
@ -114,26 +169,29 @@ public class DispatcherNode {
if (parent != null) {
return parent;
}
throw new RuntimeException("This node does not have a parent");
}
/**
* Get the root command graph.
*
*
* @return the root command graph
*/
public CommandGraph graph() {
return graph;
}
/**
* Get the underlying dispatcher of this object.
*
*
* @return the dispatcher
*/
public Dispatcher getDispatcher() {
return dispatcher;
}
public static Class<?> inject() {
return DispatcherNode.class;
}
}

View File

@ -0,0 +1,296 @@
package com.sk89q.worldedit.util.command.parametric;
import com.boydti.fawe.command.SuggestInputParseException;
import com.sk89q.minecraft.util.commands.*;
import com.sk89q.worldedit.util.command.*;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public abstract class AParametricCallable implements CommandCallable {
// private final ParametricBuilder builder;
// private ParameterData[] parameters;
// private Set<Character> valueFlags = new HashSet<Character>();
// private boolean anyFlags;
// private Set<Character> legacyFlags = new HashSet<Character>();
// private SimpleDescription description = new SimpleDescription();
// private String permission;
// private Command command;
public abstract ParameterData[] getParameters();
public abstract Set<Character> getValueFlags();
public abstract Set<Character> getLegacyFlags();
public abstract SimpleDescription getDescription();
public abstract String[] getPermissions();
public abstract ParametricBuilder getBuilder();
public abstract boolean anyFlags();
public abstract Command getCommand();
public abstract String getGroup();
@Override
public abstract String toString();
/**
* Get the right {@link ArgumentStack}.
*
* @param parameter the parameter
* @param existing the existing scoped context
* @return the context to use
*/
public static ArgumentStack getScopedContext(Parameter parameter, ArgumentStack existing) {
if (parameter.getFlag() != null) {
CommandContext context = existing.getContext();
if (parameter.isValueFlag()) {
return new StringArgumentStack(context, context.getFlag(parameter.getFlag()), false);
} else {
String v = context.hasFlag(parameter.getFlag()) ? "true" : "false";
return new StringArgumentStack(context, v, true);
}
}
return existing;
}
/**
* Get whether a parameter is allowed to consume arguments.
*
* @param i the index of the parameter
* @param scoped the scoped context
* @return true if arguments may be consumed
*/
public boolean mayConsumeArguments(int i, ContextArgumentStack scoped) {
CommandContext context = scoped.getContext();
ParameterData parameter = getParameters()[i];
// Flag parameters: Always consume
// Required non-flag parameters: Always consume
// Optional non-flag parameters:
// - Before required parameters: Consume if there are 'left over' args
// - At the end: Always consumes
if (parameter.isOptional()) {
if (parameter.getFlag() != null) {
return !parameter.isValueFlag() || context.hasFlag(parameter.getFlag());
} else {
int numberFree = context.argsLength() - scoped.position();
for (int j = i; j < getParameters().length; j++) {
if (getParameters()[j].isNonFlagConsumer() && !getParameters()[j].isOptional()) {
// We already checked if the consumed count was > -1
// when we created this object
numberFree -= getParameters()[j].getConsumedCount();
}
}
// Skip this optional parameter
if (numberFree < 1) {
return false;
}
}
}
return true;
}
/**
* Get the default value for a parameter.
*
* @param i the index of the parameter
* @param scoped the scoped context
* @return a value
* @throws ParameterException on an error
* @throws CommandException on an error
*/
public Object getDefaultValue(int i, ContextArgumentStack scoped) throws ParameterException, CommandException, InvocationTargetException {
CommandContext context = scoped.getContext();
ParameterData parameter = getParameters()[i];
String[] defaultValue = parameter.getDefaultValue();
if (defaultValue != null) {
try {
return parameter.getBinding().bind(parameter, new StringArgumentStack(context, defaultValue, false), false);
} catch (MissingParameterException e) {
throw new ParametricException(
"The default value of the parameter using the binding " +
parameter.getBinding().getClass() + " in the method\n" +
toString() + "\nis invalid");
}
}
return null;
}
/**
* Check to see if all arguments, including flag arguments, were consumed.
*
* @param scoped the argument scope
* @throws UnconsumedParameterException thrown if parameters were not consumed
*/
public void checkUnconsumed(ContextArgumentStack scoped) throws UnconsumedParameterException {
CommandContext context = scoped.getContext();
String unconsumed;
String unconsumedFlags = getUnusedFlags(context);
if ((unconsumed = scoped.getUnconsumed()) != null) {
throw new UnconsumedParameterException(unconsumed + " " + unconsumedFlags);
}
if (unconsumedFlags != null) {
throw new UnconsumedParameterException(unconsumedFlags);
}
}
/**
* Get any unused flag arguments.
*
* @param context the command context
*/
public String getUnusedFlags(CommandContext context) {
if (!anyFlags()) {
Set<Character> unusedFlags = null;
for (char flag : context.getFlags()) {
boolean found = false;
if (getLegacyFlags().contains(flag)) {
break;
}
for (ParameterData parameter : getParameters()) {
Character paramFlag = parameter.getFlag();
if (paramFlag != null && flag == paramFlag) {
found = true;
break;
}
}
if (!found) {
if (unusedFlags == null) {
unusedFlags = new HashSet<Character>();
}
unusedFlags.add(flag);
}
}
if (unusedFlags != null) {
StringBuilder builder = new StringBuilder();
for (Character flag : unusedFlags) {
builder.append("-").append(flag).append(" ");
}
return builder.toString().trim();
}
}
return null;
}
@Override
public boolean testPermission(CommandLocals locals) {
String[] perms = getPermissions();
if (perms != null && perms.length != 0) {
for (String perm : perms) {
if (getBuilder().getAuthorizer().testPermission(locals, perm)) {
return true;
}
}
return false;
} else {
return true;
}
}
@Override
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
String[] split = ("ignored" + " " + arguments).split(" ", -1);
CommandContext context = new CommandContext(split, getValueFlags(), !arguments.endsWith(" "), locals);
ContextArgumentStack scoped = new ContextArgumentStack(context);
SuggestionContext suggestable = context.getSuggestionContext();
// For /command -f |
// For /command -f flag|
if (suggestable.forFlag()) {
for (int i = 0; i < getParameters().length; i++) {
ParameterData parameter = getParameters()[i];
if (parameter.getFlag() == suggestable.getFlag()) {
String prefix = context.getFlag(parameter.getFlag());
if (prefix == null) {
prefix = "";
}
return parameter.getBinding().getSuggestions(parameter, prefix);
}
}
// This should not happen
return new ArrayList<String>();
}
int consumerIndex = 0;
ParameterData lastConsumer = null;
String lastConsumed = null;
for (int i = 0; i < getParameters().length; i++) {
ParameterData parameter = getParameters()[i];
if (parameter.getFlag() != null) {
continue; // We already handled flags
}
try {
scoped.mark();
parameter.getBinding().bind(parameter, scoped, true);
if (scoped.wasConsumed()) {
lastConsumer = parameter;
lastConsumed = context.getString(scoped.position() - 1);
consumerIndex++;
}
} catch (MissingParameterException e) {
// For /command value1 |value2
// For /command |value1 value2
if (suggestable.forHangingValue()) {
return parameter.getBinding().getSuggestions(parameter, "");
} else {
// For /command value1| value2
if (lastConsumer != null) {
return lastConsumer.getBinding().getSuggestions(lastConsumer, lastConsumed);
// For /command| value1 value2
// This should never occur
} else {
throw new RuntimeException("Invalid suggestion context");
}
}
} catch (ParameterException | InvocationTargetException e) {
SuggestInputParseException suggestion = SuggestInputParseException.get(e);
if (suggestion != null) {
return suggestion.getSuggestions();
}
if (suggestable.forHangingValue()) {
String name = getDescription().getParameters().get(consumerIndex).getName();
throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this);
} else {
return parameter.getBinding().getSuggestions(parameter, "");
}
}
}
// For /command value1 value2 |
if (suggestable.forHangingValue()) {
// There's nothing that we can suggest because there's no more parameters
// to add on, and we can't change the previous parameter
return new ArrayList<String>();
} else {
// For /command value1 value2|
if (lastConsumer != null) {
return lastConsumer.getBinding().getSuggestions(lastConsumer, lastConsumed);
// This should never occur
} else {
throw new RuntimeException("Invalid suggestion context");
}
}
}
}

View File

@ -25,7 +25,7 @@ public interface ArgumentStack {
/**
* Get the next string, which may come from the stack or a value flag.
*
*
* @return the value
* @throws ParameterException on a parameter error
*/
@ -33,7 +33,7 @@ public interface ArgumentStack {
/**
* Get the next integer, which may come from the stack or a value flag.
*
*
* @return the value
* @throws ParameterException on a parameter error
*/
@ -41,7 +41,7 @@ public interface ArgumentStack {
/**
* Get the next double, which may come from the stack or a value flag.
*
*
* @return the value
* @throws ParameterException on a parameter error
*/
@ -49,7 +49,7 @@ public interface ArgumentStack {
/**
* Get the next boolean, which may come from the stack or a value flag.
*
*
* @return the value
* @throws ParameterException on a parameter error
*/
@ -57,7 +57,7 @@ public interface ArgumentStack {
/**
* Get all remaining string values, which will consume the rest of the stack.
*
*
* @return the value
* @throws ParameterException on a parameter error
*/
@ -70,9 +70,29 @@ public interface ArgumentStack {
/**
* Get the underlying context.
*
*
* @return the context
*/
CommandContext getContext();
/**
* Mark the current position of the stack.
*
* <p>The marked position initially starts at 0.</p>
*/
void mark();
/**
* Reset to the previously {@link #mark()}ed position of the stack, and return
* the arguments that were consumed between this point and that previous point.
*
* <p>The marked position initially starts at 0.</p>
*
* @return the consumed arguments
*/
String reset();
static Class<ArgumentStack> inject0() {
return ArgumentStack.class;
}
}

View File

@ -25,24 +25,24 @@ import com.sk89q.worldedit.util.command.MissingParameterException;
/**
* Makes an instance of a {@link CommandContext} into a stack of arguments
* that can be consumed.
*
*
* @see ParametricBuilder a user of this class
*/
public class ContextArgumentStack implements ArgumentStack {
private final CommandContext context;
private int index = 0;
private int markedIndex = 0;
/**
* Create a new instance using the given context.
*
*
* @param context the context
*/
public ContextArgumentStack(CommandContext context) {
this.context = context;
}
@Override
public String next() throws ParameterException {
try {
@ -94,14 +94,14 @@ public class ContextArgumentStack implements ArgumentStack {
/**
* Get the unconsumed arguments left over, without touching the stack.
*
*
* @return the unconsumed arguments
*/
public String getUnconsumed() {
if (index >= context.argsLength()) {
return null;
}
return context.getJoinedStrings(index);
}
@ -112,42 +112,44 @@ public class ContextArgumentStack implements ArgumentStack {
/**
* Return the current position.
*
*
* @return the position
*/
public int position() {
return index;
}
/**
* Mark the current position of the stack.
*
*
* <p>The marked position initially starts at 0.</p>
*/
@Override
public void mark() {
markedIndex = index;
}
/**
* Reset to the previously {@link #mark()}ed position of the stack, and return
* the arguments that were consumed between this point and that previous point.
*
*
* <p>The marked position initially starts at 0.</p>
*
*
* @return the consumed arguments
*/
@Override
public String reset() {
String value = context.getString(markedIndex, index);
String value = context.getString(markedIndex, index - 1);
index = markedIndex;
return value;
}
/**
* Return whether any arguments were consumed between the marked position
* and the current position.
*
*
* <p>The marked position initially starts at 0.</p>
*
*
* @return true if values were consumed.
*/
public boolean wasConsumed() {
@ -156,18 +158,18 @@ public class ContextArgumentStack implements ArgumentStack {
/**
* Return the arguments that were consumed between this point and that marked point.
*
*
* <p>The marked position initially starts at 0.</p>
*
*
* @return the consumed arguments
*/
public String getConsumed() {
return context.getString(markedIndex, index);
}
/**
* Get the underlying context.
*
*
* @return the context
*/
@Override
@ -175,4 +177,8 @@ public class ContextArgumentStack implements ArgumentStack {
return context;
}
public static Class<?> inject() {
return ContextArgumentStack.class;
}
}

View File

@ -0,0 +1,76 @@
/***
*
* Copyright (c) 2007 Paul Hammant
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.thoughtworks.paranamer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Parameter;
/**
* Default implementation of Paranamer reads from a post-compile added field called '__PARANAMER_DATA'
*
* @author Paul Hammant
* @author Mauro Talevi
* @author Guilherme Silveira
*/
public class FaweParanamer extends CachingParanamer {
@Override
public String[] lookupParameterNames(AccessibleObject methodOrConstructor, boolean throwExceptionIfMissing) {
Parameter[] params;
if (methodOrConstructor instanceof Constructor) {
params = ((Constructor) methodOrConstructor).getParameters();
} else if (methodOrConstructor instanceof Method) {
params = ((Method) methodOrConstructor).getParameters();
} else {
return super.lookupParameterNames(methodOrConstructor, throwExceptionIfMissing);
}
String[] names = new String[params.length];
String[] defNames = null;
for (int i = 0; i < names.length; i++) {
Parameter param = params[i];
if (param.isNamePresent()) {
names[i] = param.getName();
} else {
if (defNames == null) {
defNames = super.lookupParameterNames(methodOrConstructor, throwExceptionIfMissing);
if (defNames.length == 0)
return defNames;
}
names[i] = defNames[i];
}
}
return names;
}
}

View File

@ -0,0 +1,310 @@
package com.sk89q.worldedit.util.command.parametric;
import com.boydti.fawe.util.StringMan;
import com.google.common.primitives.Chars;
import com.sk89q.minecraft.util.commands.*;
import com.sk89q.worldedit.util.command.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Function;
public class FunctionParametricCallable extends AParametricCallable {
private final ParametricBuilder builder;
private final ParameterData[] parameters;
private final Set<Character> valueFlags = new HashSet<Character>();
private final boolean anyFlags;
private final Set<Character> legacyFlags = new HashSet<Character>();
private final SimpleDescription description = new SimpleDescription();
private final String permission;
private final Command command;
private final Function<Object[], ?> function;
private final String group;
public FunctionParametricCallable(ParametricBuilder builder, String group, Command command, String permission, List<String> arguments, Function<Object[], ?> function) {
this.command = command;
this.permission = permission;
this.builder = builder;
this.function = function;
this.group = group;
List<String> paramNames = new ArrayList<>();
List<String> typeStrings = new ArrayList<>();
List<Type> types = new ArrayList<>();
{
boolean checkType = false;
for (String argument : arguments) {
if (checkType) {
typeStrings.set(typeStrings.size() - 1, argument);
} else {
checkType = false;
if (argument.equals("=")) {
checkType = true;
} else if (argument.length() == 1 && command.flags().contains(argument)) {
typeStrings.add("java.lang.Boolean");
paramNames.add(argument);
} else {
typeStrings.add("java.lang.String");
paramNames.add(argument);
}
}
}
Map<Type, Binding> bindings = builder.getBindings();
Map<String, Type> unqualified = new HashMap<>();
for (Map.Entry<Type, Binding> entry : bindings.entrySet()) {
Type type = entry.getKey();
String typeStr = type.getTypeName();
unqualified.put(typeStr, type);
unqualified.put(typeStr.substring(typeStr.lastIndexOf('.') + 1), type);
}
for (String typeStr : typeStrings) {
Type type = unqualified.get(typeStr);
if (type == null) type = unqualified.get("java.lang.String");
types.add(type);
}
}
parameters = new ParameterData[paramNames.size()];
List<Parameter> userParameters = new ArrayList<Parameter>();
// This helps keep tracks of @Nullables that appear in the middle of a list
// of parameters
int numOptional = 0;
//
// Go through each parameter
for (int i = 0; i < types.size(); i++) {
Type type = types.get(i);
ParameterData parameter = new ParameterData();
parameter.setType(type);
parameter.setModifiers(new Annotation[0]);
String paramName = paramNames.get(i);
boolean flag = paramName.length() == 1 && command.flags().contains(paramName);
if (flag) {
parameter.setFlag(paramName.charAt(0), type != boolean.class && type != Boolean.class);
}
// TODO switch / Optional / Search for annotations /
parameter.setName(paramName);
// Track all value flags
if (parameter.isValueFlag()) {
valueFlags.add(parameter.getFlag());
}
// No special @annotation binding... let's check for the type
if (parameter.getBinding() == null) {
parameter.setBinding(builder.getBindings().get(type));
// Don't know how to parse for this type of value
if (parameter.getBinding() == null) {
throw new ParametricException("Don't know how to handle the parameter type '" + type + "' in\n" + StringMan.getString(command.aliases()));
}
}
// Do some validation of this parameter
parameter.validate(() -> StringMan.getString(command.aliases()), i + 1);
// Keep track of optional parameters
if (parameter.isOptional() && parameter.getFlag() == null) {
numOptional++;
} else {
if (numOptional > 0 && parameter.isNonFlagConsumer()) {
if (parameter.getConsumedCount() < 0) {
throw new ParametricException(
"Found an parameter using the binding " +
parameter.getBinding().getClass().getCanonicalName() +
"\nthat does not know how many arguments it consumes, but " +
"it follows an optional parameter\nMethod: " + StringMan.getString(command.aliases()));
}
}
}
parameters[i] = parameter;
// Make a list of "real" parameters
if (parameter.isUserInput()) {
userParameters.add(parameter);
}
}
// Gather legacy flags
anyFlags = command.anyFlags();
legacyFlags.addAll(Chars.asList(command.flags().toCharArray()));
// Finish description
description.setDescription(!command.desc().isEmpty() ? command.desc() : null);
description.setHelp(!command.help().isEmpty() ? command.help() : null);
description.overrideUsage(!command.usage().isEmpty() ? command.usage() : null);
description.setPermissions(Arrays.asList(permission));
if (command.usage().isEmpty() && (command.min() > 0 || command.max() > 0)) {
boolean hasUserParameters = false;
for (ParameterData parameter : parameters) {
if (parameter.getBinding().getBehavior(parameter) != BindingBehavior.PROVIDES) {
hasUserParameters = true;
break;
}
}
if (!hasUserParameters) {
description.overrideUsage("(unknown usage information)");
}
}
// Set parameters
description.setParameters(userParameters);
}
@Override
public String getGroup() {
return group;
}
@Override
public Command getCommand() {
return command;
}
@Override
public ParameterData[] getParameters() {
return parameters;
}
public Set<Character> getValueFlags() {
return valueFlags;
}
@Override
public Set<Character> getLegacyFlags() {
return legacyFlags;
}
@Override
public Object call(String stringArguments, CommandLocals locals, String[] parentCommands) throws CommandException {
// Test permission
if (!testPermission(locals)) {
throw new CommandPermissionsException();
}
String calledCommand = parentCommands.length > 0 ? parentCommands[parentCommands.length - 1] : "_";
String[] split = (calledCommand + " " + stringArguments).split(" ", -1);
CommandContext context = new CommandContext(split, getValueFlags(), false, locals);
// Provide help if -? is specified
if (context.hasFlag('?')) {
throw new InvalidUsageException(null, this, true);
}
Object[] args = new Object[parameters.length];
ContextArgumentStack arguments = new ContextArgumentStack(context);
ParameterData parameter = null;
try {
// preProcess handlers
{
}
// Collect parameters
for (int i = 0; i < parameters.length; i++) {
parameter = parameters[i];
if (mayConsumeArguments(i, arguments)) {
// Parse the user input into a method argument
ArgumentStack usedArguments = getScopedContext(parameter, arguments);
try {
usedArguments.mark();
args[i] = parameter.getBinding().bind(parameter, usedArguments, false);
} catch (ParameterException e) {
// Not optional? Then we can't execute this command
if (!parameter.isOptional()) {
throw e;
}
usedArguments.reset();
args[i] = getDefaultValue(i, arguments);
}
} else {
args[i] = getDefaultValue(i, arguments);
}
}
// Check for unused arguments
checkUnconsumed(arguments);
// preInvoke handlers
{
if (context.argsLength() < command.min()) {
throw new MissingParameterException();
}
if (command.max() != -1 && context.argsLength() > command.max()) {
throw new UnconsumedParameterException(context.getRemainingString(command.max()));
}
}
// Execute!
Object result = function.apply(args);
// postInvoke handlers
{
}
return result;
} catch (MissingParameterException e) {
throw new InvalidUsageException("Too few parameters!", this, true);
} catch (UnconsumedParameterException e) {
throw new InvalidUsageException("Too many parameters! Unused parameters: " + e.getUnconsumed(), this, true);
} catch (ParameterException e) {
assert parameter != null;
String name = parameter.getName();
throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this, true);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof CommandException) {
throw (CommandException) e.getCause();
}
throw new WrappedCommandException(e);
} catch (Throwable t) {
throw new WrappedCommandException(t);
}
}
@Override
public boolean testPermission(CommandLocals locals) {
return permission != null ? (builder.getAuthorizer().testPermission(locals, permission)) : true;
}
@Override
public SimpleDescription getDescription() {
return description;
}
@Override
public String[] getPermissions() {
return new String[]{permission};
}
@Override
public ParametricBuilder getBuilder() {
return builder;
}
@Override
public boolean anyFlags() {
return anyFlags;
}
@Override
public String toString() {
return command.aliases()[0];
}
}

View File

@ -24,9 +24,12 @@ import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
import com.sk89q.worldedit.util.command.binding.Range;
import com.sk89q.worldedit.util.command.binding.Text;
import javax.xml.ws.Provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
/**
* Describes a parameter in detail.
@ -37,10 +40,10 @@ public class ParameterData extends SimpleParameter {
private Annotation classifier;
private Annotation[] modifiers;
private Type type;
/**
* Get the binding associated with this parameter.
*
*
* @return the binding
*/
public Binding getBinding() {
@ -49,67 +52,67 @@ public class ParameterData extends SimpleParameter {
/**
* Set the binding associated with this parameter.
*
*
* @param binding the binding
*/
void setBinding(Binding binding) {
public void setBinding(Binding binding) {
this.binding = binding;
}
/**
* Set the main type of this parameter.
*
* <p>
* <p>The type is normally that is used to determine which binding is used
* for a particular method's parameter.</p>
*
*
* @return the main type
* @see #getClassifier() which can override the type
*/
public Type getType() {
return type;
}
/**
* Set the main type of this parameter.
*
*
* @param type the main type
*/
void setType(Type type) {
public void setType(Type type) {
this.type = type;
}
/**
* Get the classifier annotation.
*
* <p>
* <p>Normally, the type determines what binding is called, but classifiers
* take precedence if one is found (and registered with
* {@link ParametricBuilder#addBinding(Binding, Type...)}).
* take precedence if one is found (and registered with
* {@link ParametricBuilder#addBinding(Binding, Type...)}).
* An example of a classifier annotation is {@link Text}.</p>
*
*
* @return the classifier annotation, null is possible
*/
public Annotation getClassifier() {
return classifier;
}
/**
* Set the classifier annotation.
*
*
* @param classifier the classifier annotation, null is possible
*/
void setClassifier(Annotation classifier) {
public void setClassifier(Annotation classifier) {
this.classifier = classifier;
}
/**
* Get a list of modifier annotations.
*
* <p>
* <p>Modifier annotations are not considered in the process of choosing a binding
* for a method parameter, but they can be used to modify the behavior of a binding.
* An example of a modifier annotation is {@link Range}, which can restrict
* numeric values handled by {@link PrimitiveBindings} to be within a range. The list
* of annotations may contain a classifier and other unrelated annotations.</p>
*
*
* @return a list of annotations
*/
public Annotation[] getModifiers() {
@ -118,44 +121,48 @@ public class ParameterData extends SimpleParameter {
/**
* Set the list of modifiers.
*
*
* @param modifiers a list of annotations
*/
void setModifiers(Annotation[] modifiers) {
public void setModifiers(Annotation[] modifiers) {
this.modifiers = modifiers;
}
/**
* Return the number of arguments this binding consumes.
*
*
* @return -1 if unknown or unavailable
*/
int getConsumedCount() {
public int getConsumedCount() {
return getBinding().getConsumedCount(this);
}
/**
* Get whether this parameter is entered by the user.
*
*
* @return true if this parameter is entered by the user.
*/
boolean isUserInput() {
public boolean isUserInput() {
return getBinding().getBehavior(this) != BindingBehavior.PROVIDES;
}
/**
* Get whether this parameter consumes non-flag arguments.
*
*
* @return true if this parameter consumes non-flag arguments
*/
boolean isNonFlagConsumer() {
public boolean isNonFlagConsumer() {
return getBinding().getBehavior(this) != BindingBehavior.PROVIDES && !isValueFlag();
}
/**
* Validate this parameter and its binding.
*/
void validate(Method method, int parameterIndex) throws ParametricException {
public void validate(Method method, int parameterIndex) throws ParametricException {
validate(() -> method.toGenericString(), parameterIndex);
}
public void validate(Supplier<String> method, int parameterIndex) throws ParametricException {
// We can't have indeterminate consumers without @Switches otherwise
// it may screw up parameter processing for later bindings
BindingBehavior behavior = getBinding().getBehavior(this);
@ -163,32 +170,35 @@ public class ParameterData extends SimpleParameter {
if (!isValueFlag() && indeterminate) {
throw new ParametricException(
"@Switch missing for indeterminate consumer\n\n" +
"Notably:\nFor the type " + type + ", the binding " +
getBinding().getClass().getCanonicalName() +
"\nmay or may not consume parameters (isIndeterminateConsumer(" + type + ") = true)" +
"\nand therefore @Switch(flag) is required for parameter #" + parameterIndex + " of \n" +
method.toGenericString());
"Notably:\nFor the type " + type + ", the binding " +
getBinding().getClass().getCanonicalName() +
"\nmay or may not consume parameters (isIndeterminateConsumer(" + type + ") = true)" +
"\nand therefore @Switch(flag) is required for parameter #" + parameterIndex + " of \n" +
method.get());
}
// getConsumedCount() better return -1 if the BindingBehavior is not CONSUMES
if (behavior != BindingBehavior.CONSUMES && binding.getConsumedCount(this) != -1) {
throw new ParametricException(
"getConsumedCount() does not return -1 for binding " +
getBinding().getClass().getCanonicalName() +
"\neven though its behavior type is " + behavior.name() +
"\nfor parameter #" + parameterIndex + " of \n" +
method.toGenericString());
"getConsumedCount() does not return -1 for binding " +
getBinding().getClass().getCanonicalName() +
"\neven though its behavior type is " + behavior.name() +
"\nfor parameter #" + parameterIndex + " of \n" +
method.get());
}
// getConsumedCount() should not return 0 if the BindingBehavior is not PROVIDES
if (behavior != BindingBehavior.PROVIDES && binding.getConsumedCount(this) == 0) {
throw new ParametricException(
"getConsumedCount() must not return 0 for binding " +
getBinding().getClass().getCanonicalName() +
"\nwhen its behavior type is " + behavior.name() + " and not PROVIDES " +
"\nfor parameter #" + parameterIndex + " of \n" +
method.toGenericString());
"getConsumedCount() must not return 0 for binding " +
getBinding().getClass().getCanonicalName() +
"\nwhen its behavior type is " + behavior.name() + " and not PROVIDES " +
"\nfor parameter #" + parameterIndex + " of \n" +
method.get());
}
}
public static Class<?> inject() {
return ParameterData.class;
}
}

View File

@ -19,25 +19,34 @@
package com.sk89q.worldedit.util.command.parametric;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.command.FawePrimitiveBinding;
import com.boydti.fawe.command.MaskBinding;
import com.boydti.fawe.command.PatternBinding;
import com.boydti.fawe.config.Commands;
import com.google.common.collect.ImmutableBiMap.Builder;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.MethodCommands;
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
import com.sk89q.worldedit.internal.command.UserCommandCompleter;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.util.auth.Authorizer;
import com.sk89q.worldedit.util.auth.NullAuthorizer;
import com.sk89q.worldedit.util.command.CallableProcessor;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.CommandCompleter;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.NullCompleter;
import com.sk89q.worldedit.util.command.ProcessedCallable;
import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
import com.sk89q.worldedit.util.command.binding.StandardBindings;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.thoughtworks.paranamer.CachingParanamer;
import com.thoughtworks.paranamer.FaweParanamer;
import com.thoughtworks.paranamer.Paranamer;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
@ -45,40 +54,44 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Creates commands using annotations placed on methods and individual parameters of
* such methods.
*
*
* @see Command defines a command
* @see Switch defines a flag
*/
public class ParametricBuilder {
private final Map<Type, Binding> bindings = new HashMap<>();
private final Paranamer paranamer = new CachingParanamer();
private final List<InvokeListener> invokeListeners = new ArrayList<>();
private final Map<Type, Binding> bindings = new HashMap<Type, Binding>();
private final Paranamer paranamer = new FaweParanamer();
private final List<InvokeListener> invokeListeners = new ArrayList<InvokeListener>();
private final List<ExceptionConverter> exceptionConverters = new ArrayList<ExceptionConverter>();
private Authorizer authorizer = new NullAuthorizer();
private CommandCompleter defaultCompleter = new NullCompleter();
/**
* Create a new builder.
*
* <p>This method will install {@link PrimitiveBindings} and
* <p>
* <p>This method will install {@link PrimitiveBindings} and
* {@link StandardBindings} and default bindings.</p>
*/
public ParametricBuilder() {
addBinding(new PrimitiveBindings());
addBinding(new FawePrimitiveBinding());
addBinding(new StandardBindings());
}
/**
* Add a binding for a given type or classifier (annotation).
*
* <p>
* <p>Whenever a method parameter is encountered, a binding must be found for it
* so that it can be called later to consume the stack of arguments provided by
* the user and return an object that is later passed to
* the user and return an object that is later passed to
* {@link Method#invoke(Object, Object...)}.</p>
*
* <p>
* <p>Normally, a {@link Type} is used to discern between different bindings, but
* if this is not specific enough, an annotation can be defined and used. This
* makes it a "classifier" and it will take precedence over the base type. For
@ -87,59 +100,95 @@ public class ParametricBuilder {
* parameter, which will cause the {@link Builder} to consult the {@link Binding}
* associated with {@code @MyArg} rather than with the binding for
* the {@link String} type.</p>
*
*
* @param binding the binding
* @param type a list of types (if specified) to override the binding's types
* @param type a list of types (if specified) to override the binding's types
*/
public void addBinding(Binding binding, Type... type) {
if (type == null || type.length == 0) {
type = binding.getTypes();
}
for (Type t : type) {
bindings.put(t, binding);
}
}
/**
* Attach an invocation listener.
*
* <p>
* <p>Invocation handlers are called in order that their listeners are
* registered with a {@link ParametricBuilder}. It is not guaranteed that
* a listener may be called, in the case of a {@link CommandException} being
* thrown at any time before the appropriate listener or handler is called.
* It is possible for a
* {@link InvokeHandler#preInvoke(Object, Method, ParameterData[], Object[], CommandContext)} to
* It is possible for a
* {@link com.sk89q.worldedit.util.command.parametric.InvokeHandler#preInvoke(Object, Method, com.sk89q.worldedit.util.command.parametric.ParameterData[], Object[], CommandContext)} to
* be called for a invocation handler, but not the associated
* {@link InvokeHandler#postInvoke(Object, Method, ParameterData[], Object[], CommandContext)}.</p>
*
* {@link com.sk89q.worldedit.util.command.parametric.InvokeHandler#postInvoke(Object, Method, com.sk89q.worldedit.util.command.parametric.ParameterData[], Object[], CommandContext)}.</p>
* <p>
* <p>An example of an invocation listener is one to handle
* {@link CommandPermissions}, by first checking to see if permission is available
* in a {@link InvokeHandler#preInvoke(Object, Method, ParameterData[], Object[], CommandContext)}
* in a {@link com.sk89q.worldedit.util.command.parametric.InvokeHandler#preInvoke(Object, Method, com.sk89q.worldedit.util.command.parametric.ParameterData[], Object[], CommandContext)}
* call. If permission is not found, then an appropriate {@link CommandException}
* can be thrown to cease invocation.</p>
*
*
* @param listener the listener
* @see InvokeHandler the handler
* @see com.sk89q.worldedit.util.command.parametric.InvokeHandler the handler
*/
public void addInvokeListener(InvokeListener listener) {
invokeListeners.add(listener);
}
/**
* Attach an exception converter to this builder in order to wrap unknown
* {@link Throwable}s into known {@link CommandException}s.
* <p>
* <p>Exception converters are called in order that they are registered.</p>
*
* @param converter the converter
* @see ExceptionConverter for an explanation
*/
public void addExceptionConverter(ExceptionConverter converter) {
exceptionConverters.add(converter);
}
/**
* Build a list of commands from methods specially annotated with {@link Command}
* (and other relevant annotations) and register them all with the given
* {@link Dispatcher}.
*
*
* @param dispatcher the dispatcher to register commands with
* @param object the object contain the methods
* @throws ParametricException thrown if the commands cannot be registered
* @param object the object contain the methods
* @throws com.sk89q.worldedit.util.command.parametric.ParametricException thrown if the commands cannot be registered
*/
public void registerMethodsAsCommands(Dispatcher dispatcher, Object object) throws ParametricException {
registerMethodsAsCommands(dispatcher, object, null);
}
/**
* Build a list of commands from methods specially annotated with {@link Command}
* (and other relevant annotations) and register them all with the given
* {@link Dispatcher}.
*
* @param dispatcher the dispatcher to register commands with
* @param object the object contain the methods
* @throws com.sk89q.worldedit.util.command.parametric.ParametricException thrown if the commands cannot be registered
*/
public void registerMethodsAsCommands(Dispatcher dispatcher, Object object, CallableProcessor processor) throws ParametricException {
for (Method method : object.getClass().getDeclaredMethods()) {
Command definition = method.getAnnotation(Command.class);
if (definition != null) {
definition = Commands.translate(method.getDeclaringClass(), definition);
CommandCallable callable = build(object, method, definition);
if (processor != null) {
callable = new ProcessedCallable(callable, processor);
}
else if (object instanceof CallableProcessor) {
callable = new ProcessedCallable(callable, (CallableProcessor) object);
}
if (object instanceof MethodCommands) {
((MethodCommands) object).register(method, callable, dispatcher);
}
dispatcher.registerCommand(callable, definition.aliases());
}
}
@ -147,46 +196,63 @@ public class ParametricBuilder {
/**
* Build a {@link CommandCallable} for the given method.
*
* @param object the object to be invoked on
* @param method the method to invoke
*
* @param object the object to be invoked on
* @param method the method to invoke
* @param definition the command definition annotation
* @return the command executor
* @throws ParametricException thrown on an error
*/
private CommandCallable build(Object object, Method method, Command definition)
private CommandCallable build(Object object, Method method, Command definition)
throws ParametricException {
return new ParametricCallable(this, object, method, definition);
try {
return new ParametricCallable(this, object, method, definition);
} catch (Throwable e) {
if (e instanceof ParametricException) {
throw (ParametricException) e;
}
e.printStackTrace();
return null;
}
}
/**
* Get the object used to get method names on Java versions before 8 (assuming
* that Java 8 is given the ability to reliably reflect method names at runtime).
*
*
* @return the paranamer
*/
Paranamer getParanamer() {
public Paranamer getParanamer() {
return paranamer;
}
/**
* Get the map of bindings.
*
*
* @return the map of bindings
*/
Map<Type, Binding> getBindings() {
public Map<Type, Binding> getBindings() {
return bindings;
}
/**
* Get a list of invocation listeners.
*
*
* @return a list of invocation listeners
*/
List<InvokeListener> getInvokeListeners() {
public List<InvokeListener> getInvokeListeners() {
return invokeListeners;
}
/**
* Get the list of exception converters.
*
* @return a list of exception converters
*/
public List<ExceptionConverter> getExceptionConverters() {
return exceptionConverters;
}
/**
* Get the authorizer.
*
@ -227,4 +293,8 @@ public class ParametricBuilder {
this.defaultCompleter = defaultCompleter;
}
public static Class<?> inject() {
return ParametricBuilder.class;
}
}

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.util.command.parametric;
import com.boydti.fawe.command.SuggestInputParseException;
import com.google.common.primitives.Chars;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
@ -26,6 +27,7 @@ import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import com.sk89q.minecraft.util.commands.SuggestionContext;
import com.sk89q.minecraft.util.commands.WrappedCommandException;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.InvalidUsageException;
@ -34,7 +36,6 @@ import com.sk89q.worldedit.util.command.Parameter;
import com.sk89q.worldedit.util.command.SimpleDescription;
import com.sk89q.worldedit.util.command.UnconsumedParameterException;
import com.sk89q.worldedit.util.command.binding.Switch;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@ -48,42 +49,43 @@ import java.util.Set;
/**
* The implementation of a {@link CommandCallable} for the {@link ParametricBuilder}.
*/
class ParametricCallable implements CommandCallable {
public class ParametricCallable extends AParametricCallable {
private final ParametricBuilder builder;
private final Object object;
private final Method method;
private final ParameterData[] parameters;
private final Set<Character> valueFlags = new HashSet<>();
private final Set<Character> valueFlags = new HashSet<Character>();
private final boolean anyFlags;
private final Set<Character> legacyFlags = new HashSet<>();
private final Set<Character> legacyFlags = new HashSet<Character>();
private final SimpleDescription description = new SimpleDescription();
private final CommandPermissions commandPermissions;
/**
* Create a new instance.
*
* @param builder the parametric builder
* @param object the object to invoke on
* @param method the method to invoke
*
* @param builder the parametric builder
* @param object the object to invoke on
* @param method the method to invoke
* @param definition the command definition annotation
* @throws ParametricException thrown on an error
*/
ParametricCallable(ParametricBuilder builder, Object object, Method method, Command definition) throws ParametricException {
public ParametricCallable(ParametricBuilder builder, Object object, Method method, Command definition) throws ParametricException {
this.builder = builder;
this.object = object;
this.method = method;
Annotation[][] annotations = method.getParameterAnnotations();
String[] names = builder.getParanamer().lookupParameterNames(method, false);
Type[] types = method.getGenericParameterTypes();
parameters = new ParameterData[types.length];
List<Parameter> userParameters = new ArrayList<>();
List<Parameter> userParameters = new ArrayList<Parameter>();
// This helps keep tracks of @Nullables that appear in the middle of a list
// of parameters
int numOptional = 0;
// Set permission hint
CommandPermissions permHint = method.getAnnotation(CommandPermissions.class);
if (permHint != null) {
@ -93,7 +95,7 @@ class ParametricCallable implements CommandCallable {
// Go through each parameter
for (int i = 0; i < types.length; i++) {
Type type = types[i];
ParameterData parameter = new ParameterData();
parameter.setType(type);
parameter.setModifiers(annotations[i]);
@ -108,7 +110,7 @@ class ParametricCallable implements CommandCallable {
if (value.length > 0) {
parameter.setDefaultValue(value);
}
// Special annotation bindings
// Special annotation bindings
} else if (parameter.getBinding() == null) {
parameter.setBinding(builder.getBindings().get(annotation.annotationType()));
parameter.setClassifier(annotation);
@ -131,10 +133,10 @@ class ParametricCallable implements CommandCallable {
throw new ParametricException("Don't know how to handle the parameter type '" + type + "' in\n" + method.toGenericString());
}
}
// Do some validation of this parameter
parameter.validate(method, i + 1);
// Keep track of optional parameters
if (parameter.isOptional() && parameter.getFlag() == null) {
numOptional++;
@ -142,17 +144,17 @@ class ParametricCallable implements CommandCallable {
if (numOptional > 0 && parameter.isNonFlagConsumer()) {
if (parameter.getConsumedCount() < 0) {
throw new ParametricException(
"Found an parameter using the binding " +
parameter.getBinding().getClass().getCanonicalName() +
"\nthat does not know how many arguments it consumes, but " +
"it follows an optional parameter\nMethod: " +
method.toGenericString());
"Found an parameter using the binding " +
parameter.getBinding().getClass().getCanonicalName() +
"\nthat does not know how many arguments it consumes, but " +
"it follows an optional parameter\nMethod: " +
method.toGenericString());
}
}
}
parameters[i] = parameter;
// Make a list of "real" parameters
if (parameter.isUserInput()) {
userParameters.add(parameter);
@ -171,7 +173,7 @@ class ParametricCallable implements CommandCallable {
for (InvokeListener listener : builder.getInvokeListeners()) {
listener.updateDescription(object, method, parameters, description);
}
// Set parameters
description.setParameters(userParameters);
@ -179,6 +181,16 @@ class ParametricCallable implements CommandCallable {
commandPermissions = method.getAnnotation(CommandPermissions.class);
}
@Override
public Command getCommand() {
return object.getClass().getAnnotation(Command.class);
}
@Override
public String getGroup() {
return object.getClass().getSimpleName().replaceAll("Commands", "").replaceAll("Util$", "");
}
@Override
public Object call(String stringArguments, CommandLocals locals, String[] parentCommands) throws CommandException {
// Test permission
@ -187,7 +199,7 @@ class ParametricCallable implements CommandCallable {
}
String calledCommand = parentCommands.length > 0 ? parentCommands[parentCommands.length - 1] : "_";
String[] split = CommandContext.split(calledCommand + " " + stringArguments);
String[] split = (calledCommand + " " + stringArguments).split(" ", -1);
CommandContext context = new CommandContext(split, getValueFlags(), false, locals);
// Provide help if -? is specified
@ -201,7 +213,7 @@ class ParametricCallable implements CommandCallable {
try {
// preProcess handlers
List<InvokeHandler> handlers = new ArrayList<>();
List<InvokeHandler> handlers = new ArrayList<InvokeHandler>();
for (InvokeListener listener : builder.getInvokeListeners()) {
InvokeHandler handler = listener.createInvokeHandler();
handlers.add(handler);
@ -217,13 +229,15 @@ class ParametricCallable implements CommandCallable {
ArgumentStack usedArguments = getScopedContext(parameter, arguments);
try {
usedArguments.mark();
args[i] = parameter.getBinding().bind(parameter, usedArguments, false);
} catch (MissingParameterException e) {
} catch (ParameterException e) {
// Not optional? Then we can't execute this command
if (!parameter.isOptional()) {
throw e;
}
usedArguments.reset();
args[i] = getDefaultValue(i, arguments);
}
} else {
@ -240,21 +254,22 @@ class ParametricCallable implements CommandCallable {
}
// Execute!
method.invoke(object, args);
Object result = method.invoke(object, args);
// postInvoke handlers
for (InvokeHandler handler : handlers) {
handler.postInvoke(handler, method, parameters, args, context);
}
return result;
} catch (MissingParameterException e) {
throw new InvalidUsageException("Too few parameters!", this);
throw new InvalidUsageException("Too few parameters!", this, true);
} catch (UnconsumedParameterException e) {
throw new InvalidUsageException("Too many parameters! Unused parameters: " + e.getUnconsumed(), this);
throw new InvalidUsageException("Too many parameters! Unused parameters: " + e.getUnconsumed(), this, true);
} catch (ParameterException e) {
assert parameter != null;
String name = parameter.getName();
throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this);
throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this, true);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof CommandException) {
throw (CommandException) e.getCause();
@ -263,13 +278,19 @@ class ParametricCallable implements CommandCallable {
} catch (Throwable t) {
throw new WrappedCommandException(t);
}
}
return true;
public Object getObject() {
return object;
}
public Method getMethod() {
return method;
}
@Override
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
return builder.getDefaultCompleter().getSuggestions(arguments, locals);
public ParameterData[] getParameters() {
return parameters;
}
/**
@ -281,190 +302,45 @@ class ParametricCallable implements CommandCallable {
return valueFlags;
}
@Override
public Set<Character> getLegacyFlags() {
return legacyFlags;
}
@Override
public SimpleDescription getDescription() {
return description;
}
@Override
public boolean testPermission(CommandLocals locals) {
if (commandPermissions != null) {
for (String perm : commandPermissions.value()) {
if (builder.getAuthorizer().testPermission(locals, perm)) {
return true;
}
}
return false;
} else {
return true;
}
public String[] getPermissions() {
return commandPermissions != null ? commandPermissions.value() : new String[0];
}
/**
* Get the right {@link ArgumentStack}.
*
* @param parameter the parameter
* @param existing the existing scoped context
* @return the context to use
*/
private static ArgumentStack getScopedContext(Parameter parameter, ArgumentStack existing) {
if (parameter.getFlag() != null) {
CommandContext context = existing.getContext();
if (parameter.isValueFlag()) {
return new StringArgumentStack(context, context.getFlag(parameter.getFlag()), false);
} else {
String v = context.hasFlag(parameter.getFlag()) ? "true" : "false";
return new StringArgumentStack(context, v, true);
}
}
return existing;
}
/**
* Get whether a parameter is allowed to consume arguments.
*
* @param i the index of the parameter
* @param scoped the scoped context
* @return true if arguments may be consumed
*/
private boolean mayConsumeArguments(int i, ContextArgumentStack scoped) {
CommandContext context = scoped.getContext();
ParameterData parameter = parameters[i];
// Flag parameters: Always consume
// Required non-flag parameters: Always consume
// Optional non-flag parameters:
// - Before required parameters: Consume if there are 'left over' args
// - At the end: Always consumes
if (parameter.isOptional()) {
if (parameter.getFlag() != null) {
return !parameter.isValueFlag() || context.hasFlag(parameter.getFlag());
} else {
int numberFree = context.argsLength() - scoped.position();
for (int j = i; j < parameters.length; j++) {
if (parameters[j].isNonFlagConsumer() && !parameters[j].isOptional()) {
// We already checked if the consumed count was > -1
// when we created this object
numberFree -= parameters[j].getConsumedCount();
}
}
// Skip this optional parameter
if (numberFree < 1) {
return false;
}
}
}
return true;
}
/**
* Get the default value for a parameter.
*
* @param i the index of the parameter
* @param scoped the scoped context
* @return a value
* @throws ParameterException on an error
* @throws CommandException on an error
*/
private Object getDefaultValue(int i, ContextArgumentStack scoped) throws ParameterException, CommandException, InvocationTargetException {
CommandContext context = scoped.getContext();
ParameterData parameter = parameters[i];
String[] defaultValue = parameter.getDefaultValue();
if (defaultValue != null) {
try {
return parameter.getBinding().bind(parameter, new StringArgumentStack(context, defaultValue, false), false);
} catch (MissingParameterException e) {
throw new ParametricException(
"The default value of the parameter using the binding " +
parameter.getBinding().getClass() + " in the method\n" +
method.toGenericString() + "\nis invalid");
}
}
return null;
@Override
public ParametricBuilder getBuilder() {
return builder;
}
/**
* Check to see if all arguments, including flag arguments, were consumed.
*
* @param scoped the argument scope
* @throws UnconsumedParameterException thrown if parameters were not consumed
*/
private void checkUnconsumed(ContextArgumentStack scoped) throws UnconsumedParameterException {
CommandContext context = scoped.getContext();
String unconsumed;
String unconsumedFlags = getUnusedFlags(context);
if ((unconsumed = scoped.getUnconsumed()) != null) {
throw new UnconsumedParameterException(unconsumed + " " + unconsumedFlags);
}
if (unconsumedFlags != null) {
throw new UnconsumedParameterException(unconsumedFlags);
}
@Override
public boolean anyFlags() {
return anyFlags;
}
/**
* Get any unused flag arguments.
*
* @param context the command context
*/
private String getUnusedFlags(CommandContext context) {
if (!anyFlags) {
Set<Character> unusedFlags = null;
for (char flag : context.getFlags()) {
boolean found = false;
if (legacyFlags.contains(flag)) {
break;
}
for (ParameterData parameter : parameters) {
Character paramFlag = parameter.getFlag();
if (paramFlag != null && flag == paramFlag) {
found = true;
break;
}
}
if (!found) {
if (unusedFlags == null) {
unusedFlags = new HashSet<>();
}
unusedFlags.add(flag);
}
}
if (unusedFlags != null) {
StringBuilder builder = new StringBuilder();
for (Character flag : unusedFlags) {
builder.append("-").append(flag).append(" ");
}
return builder.toString().trim();
}
}
return null;
@Override
public String toString() {
return method.toGenericString();
}
/**
* Generate a name for a parameter.
*
* @param type the type
*
* @param type the type
* @param classifier the classifier
* @param index the index
* @param index the index
* @return a generated name
*/
private static String generateName(Type type, Annotation classifier, int index) {
public static String generateName(Type type, Annotation classifier, int index) {
if (classifier != null) {
return classifier.annotationType().getSimpleName().toLowerCase();
} else {
@ -476,4 +352,7 @@ class ParametricCallable implements CommandCallable {
}
}
}
public static Class<?> inject() {
return ParametricCallable.class;
}
}

View File

@ -20,23 +20,24 @@
package com.sk89q.worldedit.util.command.parametric;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.util.command.MissingParameterException;
import com.sk89q.util.StringUtil;
/**
* A virtual scope that does not actually read from the underlying
* A virtual scope that does not actually read from the underlying
* {@link CommandContext}.
*/
public class StringArgumentStack implements ArgumentStack {
private final boolean nonNullBoolean;
private final CommandContext context;
private final String[] arguments;
private int markedIndex = 0;
private int index = 0;
/**
* Create a new instance using the given context.
*
*
* @param context the context
* @param arguments a list of arguments
* @param nonNullBoolean true to have {@link #nextBoolean()} return false instead of null
@ -47,10 +48,10 @@ public class StringArgumentStack implements ArgumentStack {
this.arguments = arguments;
this.nonNullBoolean = nonNullBoolean;
}
/**
* Create a new instance using the given context.
*
*
* @param context the context
* @param arguments an argument string to be parsed
* @param nonNullBoolean true to have {@link #nextBoolean()} return false instead of null
@ -99,7 +100,7 @@ public class StringArgumentStack implements ArgumentStack {
if (nonNullBoolean) { // Special case
return false;
}
throw new MissingParameterException();
}
}
@ -125,4 +126,32 @@ public class StringArgumentStack implements ArgumentStack {
return context;
}
/**
* Mark the current position of the stack.
*
* <p>The marked position initially starts at 0.</p>
*/
@Override
public void mark() {
markedIndex = index;
}
/**
* Reset to the previously {@link #mark()}ed position of the stack, and return
* the arguments that were consumed between this point and that previous point.
*
* <p>The marked position initially starts at 0.</p>
*
* @return the consumed arguments
*/
@Override
public String reset() {
String value = context.getString(markedIndex, index - 1);
index = markedIndex;
return value;
}
public static Class<?> inject() {
return StringArgumentStack.class;
}
}

View File

@ -19,10 +19,10 @@
package com.sk89q.worldedit.util.eventbus;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.InvocationTargetException;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Event handler object for {@link EventBus} that is able to dispatch
* an event.

View File

@ -23,11 +23,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.sk89q.worldedit.internal.annotation.RequiresNewerGuava;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.*;
/**
* Holds a cache of class hierarchy.

View File

@ -19,10 +19,10 @@
package com.sk89q.worldedit.util.eventbus;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Method;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Invokes a {@link Method} to dispatch an event.
*/

View File

@ -19,12 +19,12 @@
package com.sk89q.worldedit.util.eventbus;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* Used to mark methods as event handlers.
*/

View File

@ -25,12 +25,12 @@ package com.sk89q.worldedit.util.formatting;
public class Fragment {
private final StringBuilder builder = new StringBuilder();
Fragment() {
public Fragment() {
}
public Fragment append(String str) {
builder.append(Style.stripColor(str));
builder.append(str);
return this;
}
@ -88,5 +88,8 @@ public class Fragment {
public String toString() {
return builder.toString();
}
public static Class<?> inject() {
return Fragment.class;
}
}

View File

@ -19,14 +19,14 @@
package com.sk89q.worldedit.util.formatting;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* All supported color values for chat.
*

View File

@ -19,7 +19,7 @@
package com.sk89q.worldedit.util.formatting.component;
import com.sk89q.worldedit.util.formatting.Style;
import com.boydti.fawe.config.BBC;
public class CommandListBox extends MessageBox {
@ -35,13 +35,19 @@ public class CommandListBox extends MessageBox {
}
public CommandListBox appendCommand(String alias, String description) {
return appendCommand(alias, description, true);
}
public CommandListBox appendCommand(String alias, String description, boolean allowed) {
if (!first) {
getContents().newLine();
}
getContents().createFragment(Style.YELLOW_DARK).append(alias).append(": ");
getContents().append(description);
getContents().append((allowed ? BBC.HELP_ITEM_ALLOWED : BBC.HELP_ITEM_DENIED).format(alias, description));
first = false;
return this;
}
public static Class<?> inject() {
return CommandListBox.class;
}
}

View File

@ -19,8 +19,7 @@
package com.sk89q.worldedit.util.formatting.component;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.config.BBC;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.util.command.CommandCallable;
@ -28,13 +27,16 @@ import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.Description;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.PrimaryAliasComparator;
import com.sk89q.worldedit.util.formatting.Style;
import com.sk89q.worldedit.util.formatting.StyledFragment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A box to describe usage of a command.
*/
@ -43,7 +45,7 @@ public class CommandUsageBox extends StyledFragment {
/**
* Create a new usage box.
*
* @param command the command to describe
* @param command the command to describe
* @param commandString the command that was used, such as "/we" or "/brush sphere"
*/
public CommandUsageBox(CommandCallable command, String commandString) {
@ -53,9 +55,9 @@ public class CommandUsageBox extends StyledFragment {
/**
* Create a new usage box.
*
* @param command the command to describe
* @param command the command to describe
* @param commandString the command that was used, such as "/we" or "/brush sphere"
* @param locals list of locals to use
* @param locals list of locals to use
*/
public CommandUsageBox(CommandCallable command, String commandString, @Nullable CommandLocals locals) {
checkNotNull(command);
@ -68,34 +70,34 @@ public class CommandUsageBox extends StyledFragment {
}
private void attachDispatcherUsage(Dispatcher dispatcher, String commandString, @Nullable CommandLocals locals) {
CommandListBox box = new CommandListBox("Subcommands");
CommandListBox box = new CommandListBox(BBC.HELP_HEADER_SUBCOMMANDS.f());
String prefix = !commandString.isEmpty() ? commandString + " " : "";
List<CommandMapping> list = new ArrayList<>(dispatcher.getCommands());
list.sort(new PrimaryAliasComparator(CommandManager.COMMAND_CLEAN_PATTERN));
List<CommandMapping> list = new ArrayList<CommandMapping>(dispatcher.getCommands());
Collections.sort(list, new PrimaryAliasComparator(CommandManager.COMMAND_CLEAN_PATTERN));
for (CommandMapping mapping : list) {
if (locals == null || mapping.getCallable().testPermission(locals)) {
box.appendCommand(prefix + mapping.getPrimaryAlias(), mapping.getDescription().getDescription());
}
boolean perm = locals == null || mapping.getCallable().testPermission(locals);
box.appendCommand(prefix + mapping.getPrimaryAlias(), mapping.getDescription().getDescription(), perm);
}
append(box);
}
private void attachCommandUsage(Description description, String commandString) {
MessageBox box = new MessageBox("Help for " + commandString);
MessageBox box = new MessageBox(BBC.HELP_HEADER_COMMAND.f(commandString));
StyledFragment contents = box.getContents();
if (description.getUsage() != null) {
contents.append(new Label().append("Usage: "));
contents.append(description.getUsage());
contents.append(new Label().append(BBC.COMMAND_SYNTAX.f(description.getUsage())));
} else {
contents.createFragment(Style.GRAY);
contents.append(new Subtle().append("Usage information is not available."));
}
contents.newLine();
contents.createFragment(Style.GRAY);
if (description.getHelp() != null) {
contents.append(description.getHelp());
} else if (description.getDescription() != null) {
@ -107,4 +109,8 @@ public class CommandUsageBox extends StyledFragment {
append(box);
}
public static Class<?> inject() {
return CommandUsageBox.class;
}
}

View File

@ -19,12 +19,11 @@
package com.sk89q.worldedit.util.formatting.component;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.util.formatting.ColorCodeBuilder;
import com.sk89q.worldedit.util.formatting.Style;
import com.sk89q.worldedit.util.formatting.StyledFragment;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Makes for a box with a border above and below.
*/
@ -37,38 +36,21 @@ public class MessageBox extends StyledFragment {
*/
public MessageBox(String title) {
checkNotNull(title);
int leftOver = ColorCodeBuilder.GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - title.length() - 2;
int leftSide = (int) Math.floor(leftOver * 1.0/3);
int rightSide = (int) Math.floor(leftOver * 2.0/3);
if (leftSide > 0) {
createFragment(Style.YELLOW).append(createBorder(leftSide));
}
append(" ");
append(title);
append(" ");
if (rightSide > 0) {
createFragment(Style.YELLOW).append(createBorder(rightSide));
}
newLine();
append(contents);
}
private String createBorder(int count) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < count; i++) {
builder.append("-");
}
return builder.toString();
}
/**
* Get the internal contents.
*
*
* @return the contents
*/
public StyledFragment getContents() {
return contents;
}
public static Class<?> inject() {
return MessageBox.class;
}
}

View File

@ -19,13 +19,12 @@
package com.sk89q.worldedit.util.function;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Function;
import javax.annotation.Nullable;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Provides a Levenshtein distance between a given string and each string

View File

@ -19,8 +19,6 @@
package com.sk89q.worldedit.util.io;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
@ -33,6 +31,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipFile;
import static com.google.common.base.Preconditions.checkNotNull;
public final class Closer implements Closeable {
private static final Logger logger = Logger.getLogger(Closer.class.getCanonicalName());

View File

@ -19,15 +19,9 @@
package com.sk89q.worldedit.util.logging;
import java.io.UnsupportedEncodingException;
import java.util.logging.Filter;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import javax.annotation.Nullable;
import java.io.UnsupportedEncodingException;
import java.util.logging.*;
/**
* A {@link StreamHandler} delegate that allows for the swap and disable of

View File

@ -19,11 +19,11 @@
package com.sk89q.worldedit.util.logging;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* A standard logging format for WorldEdit.