Major command changes that don't work yet.

This commit is contained in:
MattBDev
2019-07-05 20:46:48 -04:00
parent ffc2092d93
commit 8108d0a936
399 changed files with 13558 additions and 7985 deletions

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World;
import java.util.Collections;
@ -39,4 +40,8 @@ public abstract class AbstractPlatform implements Platform {
return Collections.emptyList();
}
@Override
public DataFixer getDataFixer() {
return null;
}
}

View File

@ -23,6 +23,7 @@ import com.sk89q.worldedit.NotABlockException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.MutableBlockVector3;
@ -44,6 +45,7 @@ import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import javax.annotation.Nullable;
import java.io.File;
/**
@ -107,7 +109,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
byte free = 0;
BlockVector3 mutablePos = MutableBlockVector3.at(0, 0, 0);
BlockVector3 mutablePos = MutableBlockVector3.ZERO;
while (y <= world.getMaximumPoint().getBlockY() + 2) {
if (!world.getBlock(mutablePos.setComponents(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) {
++free;
@ -118,7 +120,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
if (free == 2) {
final BlockVector3 pos = mutablePos.setComponents(x, y - 2, z);
final BlockStateHolder state = world.getBlock(pos);
setPosition(new Location(world, Vector3.at(x + 0.5, y - 2 + BlockTypeUtil.centralTopLimit(state), z + 0.5)));
setPosition(Vector3.at(x + 0.5, y - 2 + BlockTypeUtil.centralTopLimit(state), z + 0.5));
return;
}
@ -137,7 +139,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
final BlockVector3 pos = BlockVector3.at(x, y, z);
final BlockState id = world.getBlock(pos);
if (id.getBlockType().getMaterial().isMovementBlocker()) {
setPosition(new Location(world, Vector3.at(x + 0.5, y + + BlockTypeUtil.centralTopLimit(id), z + 0.5)));
setPosition(Vector3.at(x + 0.5, y + + BlockTypeUtil.centralTopLimit(id), z + 0.5));
return;
}
@ -161,7 +163,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
int maxY = world.getMaxY();
if (y >= maxY) return false;
BlockMaterial initialMaterial = world.getBlockType(BlockVector3.at(x, y, z)).getMaterial();
BlockMaterial initialMaterial = world.getBlock(BlockVector3.at(x, y, z)).getMaterial();
boolean lastState = initialMaterial.isMovementBlocker() && initialMaterial.isFullCube();
@ -199,6 +201,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
lastState = true;
}
}
return false;
}
@ -206,20 +209,19 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
public boolean descendLevel() {
final Location pos = getBlockIn();
final int x = pos.getBlockX();
int y = Math.max(0, pos.getBlockY());
int y = Math.max(0, pos.getBlockY() - 1);
final int z = pos.getBlockZ();
final Extent world = pos.getExtent();
BlockMaterial initialMaterial = world.getBlockType(BlockVector3.at(x, y, z)).getMaterial();
BlockMaterial initialMaterial = world.getBlock(BlockVector3.at(x, y, z)).getMaterial();
boolean lastState = initialMaterial.isMovementBlocker() && initialMaterial.isFullCube();
double height = 1.85;
double freeEnd = -1;
int maxY = world.getMaxY();
if (y <= 2) return false;
double freeEnd = -1;
double height = 1.85;
for (int level = y + 1; level > 0; level--) {
BlockState state;
if (level >= maxY) state = BlockTypes.VOID_AIR.getDefaultState();
@ -252,6 +254,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
freeEnd = -1;
}
}
return false;
}
@ -344,13 +347,29 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public Location getBlockTrace(int range, boolean useLastBlock) {
TargetBlock tb = new TargetBlock(this, range, 0.2);
return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock());
return getBlockTrace(range, useLastBlock, null);
}
@Override
public Location getBlockTraceFace(int range, boolean useLastBlock) {
return getBlockTraceFace(range, useLastBlock, null);
}
@Override
public Location getBlockTrace(int range, boolean useLastBlock, @Nullable Mask stopMask) {
TargetBlock tb = new TargetBlock(this, range, 0.2);
if (stopMask != null) {
tb.setStopMask(stopMask);
}
return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock());
}
@Override
public Location getBlockTraceFace(int range, boolean useLastBlock, @Nullable Mask stopMask) {
TargetBlock tb = new TargetBlock(this, range, 0.2);
if (stopMask != null) {
tb.setStopMask(stopMask);
}
return (useLastBlock ? tb.getAnyTargetBlockFace() : tb.getTargetBlockFace());
}
@ -393,7 +412,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
if (typeId.hasBlockType()) {
return typeId.getBlockType().getDefaultState().toBaseBlock();
} else {
return BlockTypes.AIR.getDefaultState().toBaseBlock();
throw new NotABlockException();
}
}

View File

@ -23,6 +23,7 @@ import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionOwner;
import com.sk89q.worldedit.util.Identifiable;
import com.sk89q.worldedit.util.auth.Subject;
import com.sk89q.worldedit.util.formatting.text.Component;
import java.io.File;
@ -75,6 +76,13 @@ public interface Actor extends Identifiable, SessionOwner, Subject {
*/
void printError(String msg);
/**
* Print a {@link Component}.
*
* @param component The component to print
*/
void print(Component component);
/**
* Returns true if the actor can destroy bedrock.
*

View File

@ -50,12 +50,12 @@ public enum Capability {
USER_COMMANDS {
@Override
void initialize(PlatformManager platformManager, Platform platform) {
platformManager.getCommandManager().register(platform);
platformManager.getPlatformCommandManager().registerCommandsWith(platform);
}
@Override
void unload(PlatformManager platformManager, Platform platform) {
platformManager.getCommandManager().unregister();
platformManager.getPlatformCommandManager().removeCommands();
}
},

View File

@ -1,574 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extension.platform;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.command.AnvilCommands;
import com.boydti.fawe.command.CFICommand;
import com.boydti.fawe.command.MaskBinding;
import com.boydti.fawe.command.PatternBinding;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.task.ThrowableSupplier;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.chat.UsageMessage;
import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper;
import com.google.common.base.Joiner;
import com.sk89q.minecraft.util.commands.*;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.*;
import com.sk89q.worldedit.command.argument.ReplaceParser;
import com.sk89q.worldedit.command.argument.TreeGeneratorParser;
import com.sk89q.worldedit.command.composition.ApplyCommand;
import com.sk89q.worldedit.command.composition.DeformCommand;
import com.sk89q.worldedit.command.composition.PaintCommand;
import com.sk89q.worldedit.command.composition.ShapedBrushCommand;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.factory.Deform;
import com.sk89q.worldedit.function.factory.Deform.Mode;
import com.sk89q.worldedit.internal.command.*;
import com.sk89q.worldedit.scripting.CommandScriptLoader;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.command.*;
import com.sk89q.worldedit.util.command.composition.ProvidedValue;
import com.sk89q.worldedit.util.command.fluent.CommandGraph;
import com.sk89q.worldedit.util.command.fluent.DispatcherNode;
import com.sk89q.worldedit.util.command.parametric.AParametricCallable;
import com.sk89q.worldedit.util.command.parametric.ExceptionConverter;
import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler;
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.util.logging.DynamicStreamHandler;
import com.sk89q.worldedit.util.logging.LogFormat;
import com.sk89q.worldedit.world.World;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.util.command.composition.LegacyCommandAdapter.adapt;
/**
* Handles the registration and invocation of commands.
*
* <p>This class is primarily for internal usage.</p>
*/
public final class CommandManager {
public static final Pattern COMMAND_CLEAN_PATTERN = Pattern.compile("^[/]+");
private static final Logger log = LoggerFactory.getLogger(CommandManager.class);
private static final java.util.logging.Logger commandLog =
java.util.logging.Logger.getLogger(CommandManager.class.getCanonicalName() + ".CommandLog");
private static final Pattern numberFormatExceptionPattern = Pattern.compile("^For input string: \"(.*)\"$");
private final WorldEdit worldEdit;
private final PlatformManager platformManager;
private volatile Dispatcher dispatcher;
private volatile Platform platform;
private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler();
private final ExceptionConverter exceptionConverter;
private ParametricBuilder builder;
private Map<Object, String[]> methodMap;
private Map<CommandCallable, String[][]> commandMap;
private static CommandManager INSTANCE;
/**
* Create a new instance.
*
* @param worldEdit the WorldEdit instance
*/
public CommandManager(final WorldEdit worldEdit, PlatformManager platformManager) {
checkNotNull(worldEdit);
checkNotNull(platformManager);
INSTANCE = this;
this.worldEdit = worldEdit;
this.platformManager = platformManager;
this.exceptionConverter = new WorldEditExceptionConverter(worldEdit);
// Register this instance for command events
worldEdit.getEventBus().register(this);
// Setup the logger
commandLog.addHandler(dynamicHandler);
dynamicHandler.setFormatter(new LogFormat());
// Set up the commands manager
builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
builder.setDefaultCompleter(new UserCommandCompleter(platformManager));
builder.addBinding(new WorldEditBinding(worldEdit));
builder.addBinding(new PatternBinding(worldEdit), com.sk89q.worldedit.function.pattern.Pattern.class);
builder.addBinding(new MaskBinding(worldEdit), com.sk89q.worldedit.function.mask.Mask.class);
builder.addInvokeListener(new LegacyCommandsHandler());
builder.addInvokeListener(new CommandLoggingHandler(worldEdit, commandLog));
this.methodMap = new ConcurrentHashMap<>();
this.commandMap = new ConcurrentHashMap<>();
}
/**
* Register all the methods in the class as commands<br>
* - You should try to register commands during startup
*
* @param clazz The class containing all the commands
*/
public void registerCommands(Object clazz) {
registerCommands(clazz, new String[0]);
}
/**
* Create a command with the provided aliases and register all methods of the class as sub commands.<br>
* - You should try to register commands during startup
*
* @param clazz The class containing all the sub command methods
* @param aliases The aliases to give the command
*/
public synchronized void registerCommands(Object clazz, String... aliases) {
if (dispatcher != null) {
if (aliases.length == 0) {
builder.registerMethodsAsCommands(dispatcher, clazz);
} else {
DispatcherNode graph = new CommandGraph().builder(builder).commands();
graph = graph.registerMethods(clazz);
dispatcher.registerCommand(graph.graph().getDispatcher(), aliases);
}
platform.registerCommands(dispatcher);
} else {
methodMap.put(clazz, aliases);
}
}
/**
* Create a command with the provided aliases and register all methods of the class as sub commands.<br>
* - You should try to register commands during startup
*
* @param clazz The class containing all the sub command methods
* @param aliases The aliases to give the command
*/
public synchronized void registerCommands(Object clazz, CallableProcessor processor, String... aliases) {
if (dispatcher != null) {
if (aliases.length == 0) {
builder.registerMethodsAsCommands(dispatcher, clazz, processor);
} else {
DispatcherNode graph = new CommandGraph().builder(builder).commands();
graph = graph.registerMethods(clazz, processor);
dispatcher.registerCommand(graph.graph().getDispatcher(), aliases);
}
platform.registerCommands(dispatcher);
} else {
methodMap.put(clazz, aliases);
}
}
public synchronized void registerCommand(String[] aliases, Command command, CommandCallable callable) {
if (dispatcher != null) {
if (aliases.length == 0) {
dispatcher.registerCommand(callable, command.aliases());
} else {
DispatcherNode graph = new CommandGraph().builder(builder).commands();
graph = graph.register(callable, command.aliases());
dispatcher.registerCommand(graph.graph().getDispatcher(), aliases);
}
platform.registerCommands(dispatcher);
} else {
commandMap.putIfAbsent(callable, new String[][] {aliases, command.aliases()});
}
}
public ParametricBuilder getBuilder() {
return builder;
}
/**
* Initialize the dispatcher
*/
public synchronized void setupDispatcher() {
if (Settings.IMP.ENABLED_COMPONENTS.COMMANDS) {
DispatcherNode graph = new CommandGraph().builder(builder).commands();
for (Map.Entry<Object, String[]> entry : methodMap.entrySet()) {
// add command
String[] aliases = entry.getValue();
if (aliases.length == 0) {
graph = graph.registerMethods(entry.getKey());
} else {
graph = graph.group(aliases).registerMethods(entry.getKey()).parent();
}
}
for (Map.Entry<CommandCallable, String[][]> entry : commandMap.entrySet()) {
String[][] aliases = entry.getValue();
CommandCallable callable = entry.getKey();
if (aliases[0].length == 0) {
graph = graph.register(callable, aliases[1]);
} else {
graph = graph.group(aliases[0]).register(callable, aliases[1]).parent();
}
}
commandMap.clear();
methodMap.clear();
dispatcher = graph
.group("/anvil")
.describeAs("Anvil command")
.registerMethods(new AnvilCommands(worldEdit)).parent()
.registerMethods(new CFICommand(worldEdit, builder))
.registerMethods(new BiomeCommands(worldEdit))
.registerMethods(new ChunkCommands(worldEdit))
.registerMethods(new ClipboardCommands(worldEdit))
.registerMethods(new OptionsCommands(worldEdit))
.registerMethods(new GenerationCommands(worldEdit))
.registerMethods(new HistoryCommands(worldEdit))
.registerMethods(new NavigationCommands(worldEdit))
.registerMethods(new RegionCommands(worldEdit))
.registerMethods(new ScriptingCommands(worldEdit))
.registerMethods(new SelectionCommands(worldEdit))
.registerMethods(new SnapshotUtilCommands(worldEdit))
.registerMethods(new BrushOptionsCommands(worldEdit))
.registerMethods(new ToolCommands(worldEdit))
.registerMethods(new UtilityCommands(worldEdit))
.registerSubMethods(new WorldEditCommands(worldEdit))
.registerSubMethods(new SchematicCommands(worldEdit))
.registerSubMethods(new SnapshotCommands(worldEdit))
.groupAndDescribe(BrushCommands.class)
.registerMethods(new BrushCommands(worldEdit))
.registerMethods(new ToolCommands(worldEdit))
.registerMethods(new BrushOptionsCommands(worldEdit))
.register(adapt(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform")), "deform")
.register(adapt(new ShapedBrushCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within region"), "worldedit.brush.set")), "set")
.register(adapt(new ShapedBrushCommand(new PaintCommand(), "worldedit.brush.paint")), "paint")
.register(adapt(new ShapedBrushCommand(new ApplyCommand(), "worldedit.brush.apply")), "apply")
.register(adapt(new ShapedBrushCommand(new PaintCommand(new TreeGeneratorParser("treeType")), "worldedit.brush.forest")), "forest")
.register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y-=1", Mode.RAW_COORD), "Raise one block"), "worldedit.brush.raise")), "raise")
.register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower")
.parent()
.group("superpickaxe", "pickaxe", "sp").describeAs("Super-pickaxe commands")
.registerMethods(new SuperPickaxeCommands(worldEdit))
.parent().graph().getDispatcher();
if (platform != null) {
platform.registerCommands(dispatcher);
}
}
}
public static CommandManager getInstance() {
return INSTANCE;
}
public ExceptionConverter getExceptionConverter() {
return exceptionConverter;
}
public void register(Platform platform) {
log.info("Registering commands with " + platform.getClass().getCanonicalName());
this.platform = platform;
// Delay command registration to allow time for other plugins to hook into FAWE
try {
new CommandScriptLoader().load();
} catch (Throwable e) {
e.printStackTrace();
}
LocalConfiguration config = platform.getConfiguration();
boolean logging = config.logCommands;
String path = config.logFile;
// Register log
if (!logging || path.isEmpty()) {
dynamicHandler.setHandler(null);
commandLog.setLevel(Level.OFF);
} else {
File file = new File(config.getWorkingDirectory(), path);
commandLog.setLevel(Level.ALL);
log.info("Logging WorldEdit commands to " + file.getAbsolutePath());
try {
dynamicHandler.setHandler(new FileHandler(file.getAbsolutePath(), true));
} catch (IOException e) {
log.warn("Could not use command log file " + path + ": " + e.getMessage());
}
}
setupDispatcher();
}
void unregister() {
dynamicHandler.setHandler(null);
}
public String[] commandDetection(String[] split) {
// Quick script shortcut
if (split[0].matches("^[^/].*\\.js$")) {
String[] newSplit = new String[split.length + 1];
System.arraycopy(split, 0, newSplit, 1, split.length);
newSplit[0] = "cs";
newSplit[1] = newSplit[1];
split = newSplit;
}
String searchCmd = split[0].toLowerCase();
// Try to detect the command
if (!dispatcher.contains(searchCmd)) {
if (worldEdit.getConfiguration().noDoubleSlash && dispatcher.contains("/" + searchCmd)) {
split[0] = "/" + split[0];
} else if (searchCmd.length() >= 2 && searchCmd.charAt(0) == '/' && dispatcher.contains(searchCmd.substring(1))) {
split[0] = split[0].substring(1);
}
}
return split;
}
public void handleCommandOnCurrentThread(CommandEvent event) {
Actor actor = platformManager.createProxyActor(event.getActor());
String[] split = commandDetection(event.getArguments().split(" "));
// No command found!
if (!dispatcher.contains(split[0])) {
return;
}
LocalSession session = worldEdit.getSessionManager().get(actor);
Request.request().setSession(session);
if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {
Request.request().setWorld(((World) extent));
}
}
LocalConfiguration config = worldEdit.getConfiguration();
CommandLocals locals = new CommandLocals();
final FawePlayer fp = FawePlayer.wrap(actor);
if (fp == null) {
throw new IllegalArgumentException("FAWE doesn't support: " + actor);
}
final Set<String> failedPermissions = new LinkedHashSet<>();
locals.put("failed_permissions", failedPermissions);
locals.put(LocalSession.class, session);
if (actor instanceof Player) {
Player player = (Player) actor;
Player unwrapped = LocationMaskedPlayerWrapper.unwrap(player);
actor = new LocationMaskedPlayerWrapper(unwrapped, player.getLocation(), true) {
@Override
public boolean hasPermission(String permission) {
if (!super.hasPermission(permission)) {
failedPermissions.add(permission);
return false;
}
return true;
}
@Override
public void checkPermission(String permission) throws AuthorizationException {
try {
super.checkPermission(permission);
} catch (AuthorizationException e) {
failedPermissions.add(permission);
throw e;
}
}
};
}
locals.put(Actor.class, actor);
locals.put("arguments", event.getArguments());
ThrowableSupplier<Throwable> task =
() -> dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
handleCommandTask(task, locals, actor, session, failedPermissions, fp);
}
public Object handleCommandTask(ThrowableSupplier<Throwable> task, CommandLocals locals) {
return handleCommandTask(task, locals, null, null, null, null);
}
private Object handleCommandTask(ThrowableSupplier<Throwable> task, CommandLocals locals, @Nullable
Actor actor, @Nullable LocalSession session, @Nullable Set<String> failedPermissions, @Nullable FawePlayer fp) {
Request.reset();
if (actor == null) actor = locals.get(Actor.class);
if (session == null) session = locals.get(LocalSession.class);
long start = System.currentTimeMillis();
try {
// This is a bit of a hack, since the call method can only throw CommandExceptions
// everything needs to be wrapped at least once. Which means to handle all WorldEdit
// exceptions without writing a hook into every dispatcher, we need to unwrap these
// exceptions and rethrow their converted form, if their is one.
try {
Request.request().setActor(actor);
return task.get();
} catch (Throwable t) {
// Use the exception converter to convert the exception if any of its causes
// can be converted, otherwise throw the original exception
Throwable next = t;
exceptionConverter.convert(next);
while (next.getCause() != null) {
next = next.getCause();
exceptionConverter.convert(next);
}
throw next;
}
} catch (CommandPermissionsException e) {
if (failedPermissions == null) failedPermissions = (Set<String>) locals.get("failed_permissions");
if (failedPermissions != null) BBC.NO_PERM.send(actor, StringMan.join(failedPermissions, " "));
} catch (InvalidUsageException e) {
if (e.isFullHelpSuggested()) {
CommandCallable cmd = e.getCommand();
if (cmd instanceof Dispatcher) {
try {
String args = locals.get("arguments") + "";
CommandContext context = new CommandContext(("ignoreThis " + args).split(" "), new HashSet<>(), false, locals);
UtilityCommands.help(context, worldEdit, actor);
} catch (CommandException e1) {
e1.printStackTrace();
}
} else {
if (fp == null) fp = FawePlayer.wrap(actor);
new UsageMessage(cmd, e.getCommandUsed((WorldEdit.getInstance().getConfiguration().noDoubleSlash ? "" : "/"), ""), locals).send(fp);
}
String message = e.getMessage();
if (message != null) {
actor.printError(message);
}
} else {
String message = e.getMessage();
actor.printRaw((message != null ? message : "The command was not used properly (no more help available)."));
BBC.COMMAND_SYNTAX.send(actor, e.getSimpleUsageString("/"));
}
} catch (CommandException e) {
String message = e.getMessage();
if (message != null) {
actor.printError(e.getMessage());
} else {
actor.printError("An unknown FAWE error has occurred! Please see console.");
log.error("An unknown FAWE error occurred", e);
}
} catch (Throwable e) {
Exception faweException = FaweException.get(e);
if (faweException != null) {
BBC.WORLDEDIT_CANCEL_REASON.send(actor, faweException.getMessage());
} else {
actor.printError("There was an error handling a FAWE command: [See console]");
actor.printRaw(e.getClass().getName() + ": " + e.getMessage());
log.error("An unexpected error occurred while handling a FAWE command", e);
}
} finally {
final EditSession editSession = locals.get(EditSession.class);
if (editSession != null) {
editSession.flushQueue();
worldEdit.flushBlockBag(locals.get(Actor.class), editSession);
session.remember(editSession);
long time = System.currentTimeMillis() - start;
if (time > 1000) {
BBC.ACTION_COMPLETE.send(actor, (time / 1000d));
}
}
Request.reset();
}
return null;
}
@Subscribe
public void handleCommand(CommandEvent event) {
Request.reset();
Actor actor = event.getActor();
if (actor instanceof Player) {
actor = LocationMaskedPlayerWrapper.wrap((Player) actor);
}
String args = event.getArguments();
CommandEvent finalEvent = new CommandEvent(actor, args);
final FawePlayer<Object> fp = FawePlayer.wrap(actor);
TaskManager.IMP.taskNow(() -> {
int space0 = args.indexOf(' ');
String arg0 = space0 == -1 ? args : args.substring(0, space0);
CommandMapping cmd = dispatcher.get(arg0);
if (cmd != null && cmd.getCallable() instanceof AParametricCallable) {
Command info = ((AParametricCallable) cmd.getCallable()).getDefinition();
if (!info.queued()) {
handleCommandOnCurrentThread(finalEvent);
return;
}
}
if (!fp.runAction(new Runnable() {
@Override public void run() {
CommandManager.this.handleCommandOnCurrentThread(finalEvent);
}
}, false, true)) {
BBC.WORLDEDIT_COMMAND_LIMIT.send(fp);
}
finalEvent.setCancelled(true);
}, Fawe.isMainThread());
}
@Subscribe
public void handleCommandSuggestion(CommandSuggestionEvent event) {
try {
CommandLocals locals = new CommandLocals();
locals.put(Actor.class, event.getActor());
locals.put("arguments", event.getArguments());
event.setSuggestions(dispatcher.getSuggestions(event.getArguments(), locals));
} catch (CommandException e) {
event.getActor().printError(e.getMessage());
}
}
/**
* Get the command dispatcher instance.
*
* @return the command dispatcher
*/
public Dispatcher getDispatcher() {
return dispatcher;
}
public static java.util.logging.Logger getLogger() {
return commandLog;
}
}

View File

@ -21,14 +21,14 @@ package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries;
import java.util.List;
import java.util.Map;
import org.enginehub.piston.CommandManager;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
/**
* Represents a platform that WorldEdit has been implemented for.
@ -45,11 +45,25 @@ public interface Platform {
*/
Registries getRegistries();
/**
* Gets the Minecraft data version being used by the platform.
*
* @return the data version
*/
int getDataVersion();
/**
* Get a DataFixer capable of upgrading old data.
*
* @return a data fixer, or null if not supported by this platform
*/
DataFixer getDataFixer();
/**
* Checks if a mob type is valid.
*
* @param type The mob type name to check
* @return Whether the name is a valid mod bype
* @return Whether the name is a valid mod type
*/
boolean isValidMobType(String type);
@ -97,11 +111,11 @@ public interface Platform {
@Nullable World matchWorld(World world);
/**
* Register the commands contained within the given command dispatcher.
* Register the commands contained within the given command manager.
*
* @param dispatcher the dispatcher
* @param commandManager the command manager
*/
void registerCommands(Dispatcher dispatcher);
void registerCommands(CommandManager commandManager);
/**
* Register game hooks.

View File

@ -0,0 +1,734 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extension.platform;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.command.AnvilCommands;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.task.ThrowableSupplier;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.reflect.TypeToken;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.ApplyBrushCommands;
import com.sk89q.worldedit.command.BiomeCommands;
import com.sk89q.worldedit.command.BiomeCommandsRegistration;
import com.sk89q.worldedit.command.BrushCommands;
import com.sk89q.worldedit.command.ChunkCommands;
import com.sk89q.worldedit.command.ClipboardCommands;
import com.sk89q.worldedit.command.GeneralCommands;
import com.sk89q.worldedit.command.GenerationCommands;
import com.sk89q.worldedit.command.HistoryCommands;
import com.sk89q.worldedit.command.NavigationCommands;
import com.sk89q.worldedit.command.RegionCommands;
import com.sk89q.worldedit.command.SchematicCommands;
import com.sk89q.worldedit.command.SchematicCommandsRegistration;
import com.sk89q.worldedit.command.ScriptingCommands;
import com.sk89q.worldedit.command.SelectionCommands;
import com.sk89q.worldedit.command.SnapshotCommands;
import com.sk89q.worldedit.command.SnapshotCommandsRegistration;
import com.sk89q.worldedit.command.SnapshotUtilCommands;
import com.sk89q.worldedit.command.SuperPickaxeCommands;
import com.sk89q.worldedit.command.SuperPickaxeCommandsRegistration;
import com.sk89q.worldedit.command.ToolCommands;
import com.sk89q.worldedit.command.ToolUtilCommands;
import com.sk89q.worldedit.command.UtilityCommands;
import com.sk89q.worldedit.command.WorldEditCommands;
import com.sk89q.worldedit.command.WorldEditCommandsRegistration;
import com.sk89q.worldedit.command.argument.Arguments;
import com.sk89q.worldedit.command.argument.BooleanConverter;
import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter;
import com.sk89q.worldedit.command.argument.DirectionConverter;
import com.sk89q.worldedit.command.argument.DirectionVectorConverter;
import com.sk89q.worldedit.command.argument.EntityRemoverConverter;
import com.sk89q.worldedit.command.argument.EnumConverter;
import com.sk89q.worldedit.command.argument.FactoryConverter;
import com.sk89q.worldedit.command.argument.RegionFactoryConverter;
import com.sk89q.worldedit.command.argument.RegistryConverter;
import com.sk89q.worldedit.command.argument.VectorConverter;
import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.command.util.SubCommandPermissionCondition;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.command.CommandArgParser;
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
import com.sk89q.worldedit.internal.command.exception.ExceptionConverter;
import com.sk89q.worldedit.internal.command.exception.WorldEditExceptionConverter;
import com.sk89q.worldedit.internal.util.Substring;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.scripting.CommandScriptLoader;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.parametric.AParametricCallable;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.logging.DynamicStreamHandler;
import com.sk89q.worldedit.util.logging.LogFormat;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.TextConfig;
import org.enginehub.piston.converter.ArgumentConverters;
import org.enginehub.piston.exception.CommandException;
import org.enginehub.piston.exception.CommandExecutionException;
import org.enginehub.piston.exception.ConditionFailedException;
import org.enginehub.piston.exception.UsageException;
import org.enginehub.piston.gen.CommandRegistration;
import org.enginehub.piston.impl.CommandManagerServiceImpl;
import org.enginehub.piston.inject.InjectedValueStore;
import org.enginehub.piston.inject.Key;
import org.enginehub.piston.inject.MapBackedValueStore;
import org.enginehub.piston.inject.MemoizingValueAccess;
import org.enginehub.piston.inject.MergedValueAccess;
import org.enginehub.piston.part.SubCommandPart;
import org.enginehub.piston.suggestion.Suggestion;
import org.enginehub.piston.util.HelpGenerator;
import org.enginehub.piston.util.ValueProvider;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Handles the registration and invocation of commands.
*
* <p>This class is primarily for internal usage.</p>
*/
public final class PlatformCommandManager {
public static final Pattern COMMAND_CLEAN_PATTERN = Pattern.compile("^[/]+");
private static final Logger log = LoggerFactory.getLogger(PlatformCommandManager.class);
private static final java.util.logging.Logger COMMAND_LOG =
java.util.logging.Logger.getLogger("com.sk89q.worldedit.CommandLog");
static {
TextConfig.setCommandPrefix("/");
}
private final WorldEdit worldEdit;
private final PlatformManager platformManager;
private final CommandManagerServiceImpl commandManagerService;
private final CommandManager commandManager;
private final InjectedValueStore globalInjectedValues;
private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler();
private final WorldEditExceptionConverter exceptionConverter;
private final CommandRegistrationHandler registration;
private static PlatformCommandManager INSTANCE;
/**
* Create a new instance.
*
* @param worldEdit the WorldEdit instance
*/
public PlatformCommandManager(final WorldEdit worldEdit, PlatformManager platformManager) {
checkNotNull(worldEdit);
checkNotNull(platformManager);
INSTANCE = this;
this.worldEdit = worldEdit;
this.platformManager = platformManager;
this.exceptionConverter = new WorldEditExceptionConverter(worldEdit);
this.commandManagerService = new CommandManagerServiceImpl();
this.commandManager = commandManagerService.newCommandManager();
this.globalInjectedValues = MapBackedValueStore.create();
this.registration = new CommandRegistrationHandler(
ImmutableList.of(
new CommandLoggingHandler(worldEdit, COMMAND_LOG)
));
// setup separate from main constructor
// ensures that everything is definitely assigned
initialize();
}
private void initialize() {
// Register this instance for command events
worldEdit.getEventBus().register(this);
// Setup the logger
COMMAND_LOG.addHandler(dynamicHandler);
// Set up the commands manager
registerAlwaysInjectedValues();
registerArgumentConverters();
registerAllCommands();
}
private void registerArgumentConverters() {
DirectionVectorConverter.register(worldEdit, commandManager);
DirectionConverter.register(worldEdit, commandManager);
FactoryConverter.register(worldEdit, commandManager);
for (int count = 2; count <= 3; count++) {
commandManager.registerConverter(Key.of(double.class, Annotations.radii(count)),
CommaSeparatedValuesConverter.wrapAndLimit(ArgumentConverters.get(
TypeToken.of(double.class)
), count)
);
}
VectorConverter.register(commandManager);
EnumConverter.register(commandManager);
RegistryConverter.register(commandManager);
ZonedDateTimeConverter.register(commandManager);
BooleanConverter.register(commandManager);
EntityRemoverConverter.register(commandManager);
RegionFactoryConverter.register(commandManager);
}
private void registerAlwaysInjectedValues() {
globalInjectedValues.injectValue(Key.of(Region.class, Selection.class),
context -> {
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("No LocalSession"));
return context.injectedValue(Key.of(Player.class))
.map(player -> {
try {
return localSession.getSelection(player.getWorld());
} catch (IncompleteRegionException e) {
exceptionConverter.convert(e);
throw new AssertionError("Should have thrown a new exception.");
}
});
});
globalInjectedValues.injectValue(Key.of(EditSession.class),
context -> {
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("No LocalSession"));
return context.injectedValue(Key.of(Player.class))
.map(player -> {
EditSession editSession = localSession.createEditSession(player);
editSession.enableStandardMode();
return editSession;
});
});
}
private <CI> void registerSubCommands(String name, List<String> aliases, String desc,
CommandRegistration<CI> registration, CI instance) {
registerSubCommands(name, aliases, desc, registration, instance, m -> {});
}
private <CI> void registerSubCommands(String name, List<String> aliases, String desc,
CommandRegistration<CI> registration, CI instance,
Consumer<CommandManager> additionalConfig) {
commandManager.register(name, cmd -> {
cmd.aliases(aliases);
cmd.description(TextComponent.of(desc));
cmd.action(Command.Action.NULL_ACTION);
CommandManager manager = commandManagerService.newCommandManager();
this.registration.register(
manager,
registration,
instance
);
additionalConfig.accept(manager);
final List<Command> subCommands = manager.getAllCommands().collect(Collectors.toList());
cmd.addPart(SubCommandPart.builder(TranslatableComponent.of("worldedit.argument.action"),
TextComponent.of("Sub-command to run."))
.withCommands(subCommands)
.required()
.build());
cmd.condition(new SubCommandPermissionCondition.Generator(subCommands).build());
});
}
private void registerAllCommands() {
if (Settings.IMP.ENABLED_COMPONENTS.COMMANDS) {
registerSubCommands(
"schematic",
ImmutableList.of("schem", "/schematic", "/schem"),
"Schematic commands for saving/loading areas",
SchematicCommandsRegistration.builder(),
new SchematicCommands(worldEdit)
);
registerSubCommands(
"snapshot",
ImmutableList.of("snap"),
"Snapshot commands for restoring backups",
SnapshotCommandsRegistration.builder(),
new SnapshotCommands(worldEdit)
);
registerSubCommands(
"superpickaxe",
ImmutableList.of("pickaxe", "sp"),
"Super-pickaxe commands",
SuperPickaxeCommandsRegistration.builder(),
new SuperPickaxeCommands(worldEdit)
);
registerSubCommands(
"brush",
ImmutableList.of("br", "/brush", "/br"),
"Brushing commands",
BrushCommandsRegistration.builder(),
new BrushCommands(worldEdit),
manager -> {
PaintBrushCommands.register(commandManagerService, manager, registration);
ApplyBrushCommands.register(commandManagerService, manager, registration);
}
);
registerSubCommands(
"worldedit",
ImmutableList.of("we"),
"WorldEdit commands",
WorldEditCommandsRegistration.builder(),
new WorldEditCommands(worldEdit)
);
this.registration.register(
commandManager,
BiomeCommandsRegistration.builder(),
new BiomeCommands()
);
this.registration.register(
commandManager,
ChunkCommandsRegistration.builder(),
new ChunkCommands(worldEdit)
);
this.registration.register(
commandManager,
ClipboardCommandsRegistration.builder(),
new ClipboardCommands(worldEdit)
);
this.registration.register(
commandManager,
GeneralCommandsRegistration.builder(),
new GeneralCommands(worldEdit)
);
this.registration.register(
commandManager,
GenerationCommandsRegistration.builder(),
new GenerationCommands(worldEdit)
);
this.registration.register(
commandManager,
HistoryCommandsRegistration.builder(),
new HistoryCommands(worldEdit)
);
this.registration.register(
commandManager,
NavigationCommandsRegistration.builder(),
new NavigationCommands(worldEdit)
);
this.registration.register(
commandManager,
RegionCommandsRegistration.builder(),
new RegionCommands(worldEdit)
);
this.registration.register(
commandManager,
ScriptingCommandsRegistration.builder(),
new ScriptingCommands(worldEdit)
);
this.registration.register(
commandManager,
SelectionCommandsRegistration.builder(),
new SelectionCommands(worldEdit)
);
ExpandCommands.register(registration, commandManager, commandManagerService);
this.registration.register(
commandManager,
SnapshotUtilCommandsRegistration.builder(),
new SnapshotUtilCommands(worldEdit)
);
this.registration.register(
commandManager,
ToolCommandsRegistration.builder(),
new ToolCommands(worldEdit)
);
this.registration.register(
commandManager,
ToolUtilCommandsRegistration.builder(),
new ToolUtilCommands(worldEdit)
);
this.registration.register(
commandManager,
UtilityCommandsRegistration.builder(),
new UtilityCommands(worldEdit)
);
this.registration.register(
commandManager,
AnvilCommandsRegistration.builder(),
new AnvilCommands(worldEdit)
);
}
}
// /**
// * Initialize the dispatcher
// */
// public synchronized void setupDispatcher() {
// if (Settings.IMP.ENABLED_COMPONENTS.COMMANDS) {
// DispatcherNode graph = new CommandGraph().builder(builder).commands();
//
// for (Map.Entry<Object, String[]> entry : methodMap.entrySet()) {
// // add command
// String[] aliases = entry.getValue();
// if (aliases.length == 0) {
// graph = graph.registerMethods(entry.getKey());
// } else {
// graph = graph.group(aliases).registerMethods(entry.getKey()).parent();
// }
// }
//
// for (Map.Entry<CommandCallable, String[][]> entry : commandMap.entrySet()) {
// String[][] aliases = entry.getValue();
// CommandCallable callable = entry.getKey();
// if (aliases[0].length == 0) {
// graph = graph.register(callable, aliases[1]);
// } else {
// graph = graph.group(aliases[0]).register(callable, aliases[1]).parent();
// }
// }
//
// commandMap.clear();
// methodMap.clear();
//
// dispatcher = graph
// .group("/anvil")
// .describeAs("Anvil command")
// .registerMethods(new AnvilCommands(worldEdit)).parent()
// .registerMethods(new CFICommand(worldEdit, builder))
// .registerMethods(new OptionsCommands(worldEdit))
// .registerMethods(new BrushOptionsCommands(worldEdit))
// .registerMethods(new BrushOptionsCommands(worldEdit))
// .register(adapt(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform")), "deform")
// .register(adapt(new ShapedBrushCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within region"), "worldedit.brush.set")), "set")
// .register(adapt(new ShapedBrushCommand(new PaintCommand(), "worldedit.brush.paint")), "paint")
// .register(adapt(new ShapedBrushCommand(new ApplyCommand(), "worldedit.brush.apply")), "apply")
// .register(adapt(new ShapedBrushCommand(new PaintCommand(new TreeGeneratorParser("treeType")), "worldedit.brush.forest")), "forest")
// .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y-=1", Mode.RAW_COORD), "Raise one block"), "worldedit.brush.raise")), "raise")
// .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower")
// .parent()
// .group("superpickaxe", "pickaxe", "sp").describeAs("Super-pickaxe commands")
// .registerMethods(new SuperPickaxeCommands(worldEdit))
// .parent().graph().getDispatcher();
//
// if (platform != null) {
// platform.registerCommands(dispatcher);
// }
// }
// }
public static PlatformCommandManager getInstance() {
return INSTANCE;
}
public ExceptionConverter getExceptionConverter() {
return exceptionConverter;
}
void registerCommandsWith(Platform platform) {
log.info("Registering commands with " + platform.getClass().getCanonicalName());
// Delay command registration to allow time for other plugins to hook into FAWE
try {
new CommandScriptLoader().load();
} catch (Throwable e) {
e.printStackTrace();
}
LocalConfiguration config = platform.getConfiguration();
boolean logging = config.logCommands;
String path = config.logFile;
// Register log
if (!logging || path.isEmpty()) {
dynamicHandler.setHandler(null);
COMMAND_LOG.setLevel(Level.OFF);
} else {
File file = new File(config.getWorkingDirectory(), path);
COMMAND_LOG.setLevel(Level.ALL);
log.info("Logging WorldEdit commands to " + file.getAbsolutePath());
try {
dynamicHandler.setHandler(new FileHandler(file.getAbsolutePath(), true));
} catch (IOException e) {
log.warn("Could not use command log file " + path + ": " + e.getMessage());
}
dynamicHandler.setFormatter(new LogFormat(config.logFormat));
}
platform.registerCommands(commandManager);
}
void removeCommands() {
dynamicHandler.setHandler(null);
}
private Stream<Substring> parseArgs(String input) {
return new CommandArgParser(CommandArgParser.spaceSplit(input.substring(1))).parseArgs();
}
@Subscribe
public void handleCommand(CommandEvent event) {
Request.reset();
Actor actor = event.getActor();
if (actor instanceof Player) {
actor = LocationMaskedPlayerWrapper.wrap((Player) actor);
}
String args = event.getArguments();
CommandEvent finalEvent = new CommandEvent(actor, args);
final FawePlayer<Object> fp = FawePlayer.wrap(actor);
TaskManager.IMP.taskNow(() -> {
int space0 = args.indexOf(' ');
String arg0 = space0 == -1 ? args : args.substring(0, space0);
Optional<Command> cmd = commandManager.getCommand(arg0);
if (cmd.isPresent()) {
if (!cmd.queued()) {
handleCommandOnCurrentThread(finalEvent);
return;
}
}
if (!fp.runAction(
() -> PlatformCommandManager.this.handleCommandOnCurrentThread(finalEvent), false, true)) {
BBC.WORLDEDIT_COMMAND_LIMIT.send(fp);
}
finalEvent.setCancelled(true);
}, Fawe.isMainThread());
}
public void handleCommandOnCurrentThread(CommandEvent event) {
Actor actor = platformManager.createProxyActor(event.getActor());
String[] split = parseArgs(event.getArguments())
.map(Substring::getSubstring)
.toArray(String[]::new);
// No command found!
if (!commandManager.containsCommand(split[0])) {
return;
}
LocalSession session = worldEdit.getSessionManager().get(actor);
Request.request().setSession(session);
if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {
Request.request().setWorld(((World) extent));
}
}
LocalConfiguration config = worldEdit.getConfiguration();
MemoizingValueAccess context = initializeInjectedValues(event::getArguments, actor);
final FawePlayer fp = FawePlayer.wrap(actor);
if (fp == null) {
throw new IllegalArgumentException("FAWE doesn't support: " + actor);
}
ThrowableSupplier<Throwable> task =
() -> commandManager.execute(context,Lists.newArrayList(split));
handleCommandTask(task, context, actor, session, event);
}
public Object handleCommandTask(ThrowableSupplier<Throwable> task,
MemoizingValueAccess context, @NotNull
Actor actor, @Nullable LocalSession session, CommandEvent event) {
String[] split = parseArgs(event.getArguments())
.map(Substring::getSubstring)
.toArray(String[]::new);
Request.reset();
long start = System.currentTimeMillis();
try {
// This is a bit of a hack, since the call method can only throw CommandExceptions
// everything needs to be wrapped at least once. Which means to handle all WorldEdit
// exceptions without writing a hook into every dispatcher, we need to unwrap these
// exceptions and rethrow their converted form, if their is one.
try {
commandManager.execute(context, ImmutableList.copyOf(split));
} catch (Throwable t) {
// Use the exception converter to convert the exception if any of its causes
// can be converted, otherwise throw the original exception
Throwable next = t;
do {
exceptionConverter.convert(next);
next = next.getCause();
} while (next != null);
throw t;
}
} catch (ConditionFailedException e) {
if (e.getCondition() instanceof PermissionCondition) {
actor.printError("You are not permitted to do that. Are you in the right mode?");
} else {
actor.print(e.getRichMessage());
}
} catch (UsageException e) {
actor.print(TextComponent.builder("")
.color(TextColor.RED)
.append(e.getRichMessage())
.build());
ImmutableList<Command> cmd = e.getCommands();
if (!cmd.isEmpty()) {
actor.print(TextComponent.builder("Usage: ")
.color(TextColor.RED)
.append(HelpGenerator.create(e.getCommandParseResult()).getUsage())
.build());
}
} catch (CommandExecutionException e) {
handleUnknownException(actor, e.getCause());
} catch (CommandException e) {
actor.print(TextComponent.builder("")
.color(TextColor.RED)
.append(e.getRichMessage())
.build());
} catch (Throwable t) {
handleUnknownException(actor, t);
} finally {
Optional<EditSession> editSessionOpt =
context.snapshotMemory().injectedValue(Key.of(EditSession.class));
if (editSessionOpt.isPresent()) {
EditSession editSession = editSessionOpt.get();
session.remember(editSession);
editSession.flushQueue();
long time = System.currentTimeMillis() - start;
if (time > 1000) {
BBC.ACTION_COMPLETE.send(actor, time / 1000D);
}
worldEdit.flushBlockBag(actor, editSession);
}
Request.reset();
}
event.setCancelled(true);
return null;
}
private MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor actor) {
InjectedValueStore store = MapBackedValueStore.create();
store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor));
if (actor instanceof Player) {
store.injectValue(Key.of(Player.class), ValueProvider.constant((Player) actor));
} else {
store.injectValue(Key.of(Player.class), context -> {
throw new CommandException(TextComponent.of("This command must be used with a player."), ImmutableList.of());
});
}
store.injectValue(Key.of(Arguments.class), ValueProvider.constant(arguments));
store.injectValue(Key.of(LocalSession.class),
context -> {
LocalSession localSession = worldEdit.getSessionManager().get(actor);
localSession.tellVersion(actor);
return Optional.of(localSession);
});
return MemoizingValueAccess.wrap(
MergedValueAccess.of(store, globalInjectedValues)
);
}
private void handleUnknownException(Actor actor, Throwable t) {
actor.printError("Please report this error: [See console]");
actor.printRaw(t.getClass().getName() + ": " + t.getMessage());
log.error("An unexpected error while handling a WorldEdit command", t);
}
@Subscribe
public void handleCommandSuggestion(CommandSuggestionEvent event) {
try {
String arguments = event.getArguments();
List<Substring> split = parseArgs(arguments).collect(Collectors.toList());
List<String> argStrings = split.stream()
.map(Substring::getSubstring)
.collect(Collectors.toList());
MemoizingValueAccess access = initializeInjectedValues(() -> arguments, event.getActor());
ImmutableSet<Suggestion> suggestions;
try {
suggestions = commandManager.getSuggestions(access, argStrings);
} catch (Throwable t) { // catch errors which are *not* command exceptions generated by parsers/suggesters
if (!(t instanceof CommandException)) {
log.debug("Unexpected error occurred while generating suggestions for input: " + arguments, t);
return;
}
throw t;
}
event.setSuggestions(suggestions.stream()
.map(suggestion -> {
int noSlashLength = arguments.length() - 1;
Substring original = suggestion.getReplacedArgument() == split.size()
? Substring.from(arguments, noSlashLength, noSlashLength)
: split.get(suggestion.getReplacedArgument());
// increase original points by 1, for removed `/` in `parseArgs`
return Substring.wrap(
suggestion.getSuggestion(),
original.getStart() + 1,
original.getEnd() + 1
);
}).collect(Collectors.toList()));
} catch (ConditionFailedException e) {
if (e.getCondition() instanceof PermissionCondition) {
event.setSuggestions(new ArrayList<>());
}
}
}
/**
* Get the command manager instance.
*
* @return the command manager
*/
public CommandManager getCommandManager() {
return commandManager;
}
}

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.extension.platform;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
@ -37,7 +39,12 @@ import com.sk89q.worldedit.command.tool.DoubleActionTraceTool;
import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.command.tool.TraceTool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.*;
import com.sk89q.worldedit.event.platform.BlockInteractEvent;
import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
import com.sk89q.worldedit.event.platform.Interaction;
import com.sk89q.worldedit.event.platform.PlatformInitializeEvent;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.event.platform.PlayerInputEvent;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
@ -47,10 +54,6 @@ import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.world.World;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Iterator;
@ -58,8 +61,9 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manages registered {@link Platform}s for WorldEdit. Platforms are
@ -72,7 +76,7 @@ public class PlatformManager {
private static final Logger logger = LoggerFactory.getLogger(PlatformManager.class);
private final WorldEdit worldEdit;
private final CommandManager commandManager;
private final PlatformCommandManager platformCommandManager;
private final List<Platform> platforms = new ArrayList<>();
private final Map<Capability, Platform> preferences = new EnumMap<>(Capability.class);
private @Nullable String firstSeenVersion;
@ -87,7 +91,7 @@ public class PlatformManager {
public PlatformManager(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
this.commandManager = new CommandManager(worldEdit, this);
this.platformCommandManager = new PlatformCommandManager(worldEdit, this);
// Register this instance for events
worldEdit.getEventBus().register(this);
@ -110,7 +114,7 @@ public class PlatformManager {
// Make sure that versions are in sync
if (firstSeenVersion != null) {
if (!firstSeenVersion.equals(platform.getVersion())) {
logger.warn("Multiple ports of WorldEdit are installed but they report different versions ({0} and {1}). " +
logger.warn("Multiple ports of WorldEdit are installed but they report different versions ({} and {}). " +
"If these two versions are truly different, then you may run into unexpected crashes and errors.",
new Object[]{ firstSeenVersion, platform.getVersion() });
}
@ -272,8 +276,8 @@ public class PlatformManager {
*
* @return the command manager
*/
public CommandManager getCommandManager() {
return commandManager;
public PlatformCommandManager getPlatformCommandManager() {
return platformCommandManager;
}
/**
@ -301,7 +305,6 @@ public class PlatformManager {
return tool;
}
@SuppressWarnings("deprecation")
@Subscribe
public void handleBlockInteract(BlockInteractEvent event) {
// Create a proxy actor with a potentially different world for
@ -310,112 +313,106 @@ public class PlatformManager {
Location location = event.getLocation();
// At this time, only handle interaction from players
if (!(actor instanceof Player)) {
return;
}
Player player = (Player) actor;
LocalSession session = worldEdit.getSessionManager().get(actor);
Request.reset();
try {
Vector3 vector = location.toVector();
// At this time, only handle interaction from players
if (actor instanceof Player) {
Player player = (Player) actor;
LocalSession session = worldEdit.getSessionManager().get(actor);
Request.reset();
VirtualWorld virtual = session.getVirtualWorld();
if (virtual != null) {
virtual.handleBlockInteract(player, vector.toBlockPoint(), event);
if (event.isCancelled()) return;
}
VirtualWorld virtual = session.getVirtualWorld();
if (virtual != null) {
virtual.handleBlockInteract(player, vector.toBlockPoint(), event);
if (event.isCancelled()) return;
if (event.getType() == Interaction.HIT) {
// superpickaxe is special because its primary interaction is a left click, not a right click
// in addition, it is implicitly bound to all pickaxe items, not just a single tool item
if (player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) {
if (!actor.hasPermission("worldedit.selection.pos")) {
return;
}
FawePlayer<?> fp = FawePlayer.wrap(player);
RegionSelector selector = session.getRegionSelector(player.getWorld());
final Player maskedPlayerWrapper =
new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor),
((Player) actor).getLocation());
BlockVector3 blockPoint = vector.toBlockPoint();
fp.runAction(() -> {
if (selector.selectPrimary(blockPoint,
ActorSelectorLimits.forActor(maskedPlayerWrapper))) {
selector
.explainPrimarySelection(actor, session, blockPoint);
}
}, false, true);
event.setCancelled(true);
return;
}
if (event.getType() == Interaction.HIT) {
if (session.isToolControlEnabled() && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) {
if (!actor.hasPermission("worldedit.selection.pos")) {
return;
}
if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) {
final BlockTool superPickaxe = session.getSuperPickaxe();
if (superPickaxe != null && superPickaxe.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
final Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
fp.runAction(() -> reset(superPickaxe).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), maskedPlayerWrapper, session, location), false, true);
event.setCancelled(true);
return;
}
}
Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
if (tool instanceof DoubleActionBlockTool && tool.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
final Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
fp.runAction(() -> reset(((DoubleActionBlockTool) tool)).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), maskedPlayerWrapper, session, location), false, true);
event.setCancelled(true);
}
} else if (event.getType() == Interaction.OPEN) {
if (player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) {
if (!actor.hasPermission("worldedit.selection.pos")) {
return;
}
FawePlayer<?> fp = FawePlayer.wrap(player);
if (fp.checkAction()) {
RegionSelector selector = session.getRegionSelector(player.getWorld());
final Player maskedPlayerWrapper =
new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor),
((Player) actor).getLocation());
Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(
PlayerWrapper.wrap((Player) actor),
((Player) actor).getLocation());
BlockVector3 blockPoint = vector.toBlockPoint();
fp.runAction(() -> {
if (selector.selectPrimary(blockPoint,
if (selector.selectSecondary(blockPoint,
ActorSelectorLimits.forActor(maskedPlayerWrapper))) {
selector
.explainPrimarySelection(actor, session, blockPoint);
selector.explainSecondarySelection(actor, session,
blockPoint);
}
}, false, true);
event.setCancelled(true);
return;
}
if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) {
final BlockTool superPickaxe = session.getSuperPickaxe();
if (superPickaxe != null && superPickaxe.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
final Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
fp.runAction(() -> reset(superPickaxe).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), maskedPlayerWrapper, session, location), false, true);
event.setCancelled(true);
return;
}
}
Tool tool = session.getTool(player);
if (tool instanceof DoubleActionBlockTool) {
if (tool.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
final Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
fp.runAction(new Runnable() {
@Override
public void run() {
reset(((DoubleActionBlockTool) tool)).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), maskedPlayerWrapper, session, location);
}
}, false, true);
event.setCancelled(true);
return;
}
}
event.setCancelled(true);
return;
}
} else if (event.getType() == Interaction.OPEN) {
if (session.isToolControlEnabled() && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) {
if (!actor.hasPermission("worldedit.selection.pos")) {
return;
}
FawePlayer<?> fp = FawePlayer.wrap(player);
if (fp.checkAction()) {
RegionSelector selector = session.getRegionSelector(player.getWorld());
Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(
PlayerWrapper.wrap((Player) actor),
((Player) actor).getLocation());
BlockVector3 blockPoint = vector.toBlockPoint();
fp.runAction(() -> {
if (selector.selectSecondary(blockPoint,
ActorSelectorLimits.forActor(maskedPlayerWrapper))) {
selector.explainSecondarySelection(actor, session,
blockPoint);
}
}, false, true);
}
event.setCancelled(true);
return;
}
Tool tool = session.getTool(player);
if (tool instanceof BlockTool) {
if (tool.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
if (fp.checkAction()) {
final Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
fp.runAction(() -> {
if (tool instanceof BrushTool) {
((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), maskedPlayerWrapper, session, location);
} else {
reset((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), maskedPlayerWrapper, session, location);
}
}, false, true);
event.setCancelled(true);
return;
Tool tool = session.getTool(player);
if (tool instanceof BlockTool && tool.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
if (fp.checkAction()) {
final Player maskedPlayerWrapper = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
fp.runAction(() -> {
if (tool instanceof BrushTool) {
((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), maskedPlayerWrapper, session, location);
} else {
reset((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), maskedPlayerWrapper, session, location);
}
}
}, false, true);
event.setCancelled(true);
}
}
}
@ -452,9 +449,10 @@ public class PlatformManager {
}
try {
Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
switch (event.getInputType()) {
case PRIMARY: {
if ((getConfiguration().navigationWandMaxDistance > 0) && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) {
if (getConfiguration().navigationWandMaxDistance > 0 && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) {
if (!player.hasPermission("worldedit.navigation.jumpto.tool")) {
return;
}
@ -470,14 +468,11 @@ public class PlatformManager {
return;
}
Tool tool = session.getTool(player);
if (tool instanceof DoubleActionTraceTool) {
if (tool.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
fp.runAsyncIfFree(() -> reset((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session));
event.setCancelled(true);
return;
}
if (tool instanceof DoubleActionTraceTool && tool.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
fp.runAsyncIfFree(() -> reset((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session));
event.setCancelled(true);
return;
}
break;
@ -497,14 +492,12 @@ public class PlatformManager {
return;
}
Tool tool = session.getTool(player);
if (tool instanceof TraceTool) {
if (tool.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
fp.runAction(() -> reset((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session), false, true);
event.setCancelled(true);
return;
}
if (tool instanceof TraceTool && tool.canUse(player)) {
FawePlayer<?> fp = FawePlayer.wrap(player);
//todo this needs to be fixed so the event is canceled after actPrimary is used and returns true
fp.runAction(() -> reset((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session), false, true);
event.setCancelled(true);
return;
}
break;

View File

@ -31,6 +31,7 @@ import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -143,6 +144,11 @@ public class PlayerProxy extends AbstractPlayerActor {
basePlayer.printError(msg);
}
@Override
public void print(Component component) {
basePlayer.print(component);
}
@Override
public String[] getGroups() {
return permActor.getGroups();