Plex-FAWE/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java

530 lines
22 KiB
Java
Raw Normal View History

/*
2014-04-04 22:03:18 +00:00
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
2014-04-04 22:03:18 +00:00
* 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.
*
2014-04-04 22:03:18 +00:00
* 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.
*
2014-04-04 22:03:18 +00:00
* 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/>.
2014-04-04 22:03:18 +00:00
*/
package com.sk89q.worldedit.command;
2019-04-28 07:05:37 +00:00
import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
import com.sk89q.worldedit.EditSession;
2019-04-26 02:36:22 +00:00
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
2019-04-26 02:36:22 +00:00
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
2019-04-26 02:36:22 +00:00
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.CreatureButcher;
import com.sk89q.worldedit.command.util.EntityRemover;
import com.sk89q.worldedit.command.util.Logging;
2019-04-26 02:36:22 +00:00
import com.sk89q.worldedit.command.util.PrintCommandHelp;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
2019-04-26 02:36:22 +00:00
import com.sk89q.worldedit.function.EntityFunction;
import com.sk89q.worldedit.function.mask.BlockTypeMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.CylinderRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockTypes;
2019-04-26 02:36:22 +00:00
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
2019-04-26 02:36:22 +00:00
import java.util.function.Supplier;
/**
* Utility commands.
*/
2019-04-26 02:36:22 +00:00
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class UtilityCommands {
2014-07-29 18:04:04 +00:00
private final WorldEdit we;
public UtilityCommands(WorldEdit we) {
this.we = we;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "/fill",
desc = "Fill a hole"
)
@CommandPermissions("worldedit.fill")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int fill(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with")
Pattern pattern,
@Arg(desc = "The radius to fill in")
double radius,
@Arg(desc = "The depth to fill", def = "1")
int depth) throws WorldEditException {
radius = Math.max(1, radius);
we.checkMaxRadius(radius);
2019-04-26 02:36:22 +00:00
depth = Math.max(1, depth);
BlockVector3 pos = session.getPlacementPosition(player);
2018-07-22 05:36:50 +00:00
int affected = editSession.fillXZ(pos, pattern, radius, depth, false);
player.print(affected + " block(s) have been created.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "/fillr",
desc = "Fill a hole recursively"
)
@CommandPermissions("worldedit.fill.recursive")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int fillr(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with")
Pattern pattern,
@Arg(desc = "The radius to fill in")
double radius,
@Arg(desc = "The depth to fill", def = "")
Integer depth) throws WorldEditException {
radius = Math.max(1, radius);
we.checkMaxRadius(radius);
depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth);
we.checkMaxRadius(radius);
BlockVector3 pos = session.getPlacementPosition(player);
2019-04-26 02:36:22 +00:00
int affected = editSession.fillXZ(pos, pattern, radius, depth, true);
player.print(affected + " block(s) have been created.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "/drain",
desc = "Drain a pool"
)
@CommandPermissions("worldedit.drain")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int drain(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to drain")
double radius,
@Switch(name = 'w', desc = "Also un-waterlog blocks")
boolean waterlogged) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius);
int affected = editSession.drainArea(
2019-04-26 02:36:22 +00:00
session.getPlacementPosition(player), radius, waterlogged);
player.print(affected + " block(s) have been changed.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "fixlava",
aliases = { "/fixlava" },
desc = "Fix lava to be stationary"
)
@CommandPermissions("worldedit.fixlava")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int fixLava(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to fix in")
double radius) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.LAVA);
player.print(affected + " block(s) have been changed.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "fixwater",
aliases = { "/fixwater" },
desc = "Fix water to be stationary"
)
@CommandPermissions("worldedit.fixwater")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int fixWater(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to fix in")
double radius) throws WorldEditException {
radius = Math.max(0, radius);
we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.WATER);
player.print(affected + " block(s) have been changed.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "removeabove",
aliases = { "/removeabove" },
desc = "Remove blocks above your head."
)
@CommandPermissions("worldedit.removeabove")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int removeAbove(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The apothem of the square to remove from", def = "1")
int size,
@Arg(desc = "The maximum height above you to remove from", def = "")
Integer height) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size);
World world = player.getWorld();
2019-04-26 02:36:22 +00:00
height = height != null ? Math.min((world.getMaxY() + 1), height + 2) : (world.getMaxY() + 1);
int affected = editSession.removeAbove(
2019-04-26 02:36:22 +00:00
session.getPlacementPosition(player), size, height);
player.print(affected + " block(s) have been removed.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "removebelow",
aliases = { "/removebelow" },
desc = "Remove blocks below you."
)
@CommandPermissions("worldedit.removebelow")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int removeBelow(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The apothem of the square to remove from", def = "1")
int size,
@Arg(desc = "The maximum height below you to remove from", def = "")
Integer height) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size);
World world = player.getWorld();
2019-04-26 02:36:22 +00:00
height = height != null ? Math.min((-world.getMaxY() + 1), height + 2) : (world.getMaxY() + 1);
int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height);
player.print(affected + " block(s) have been removed.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "removenear",
aliases = { "/removenear" },
desc = "Remove blocks near you."
)
@CommandPermissions("worldedit.removenear")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int removeNear(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The mask of blocks to remove")
Mask mask,
@Arg(desc = "The radius of the square to remove from", def = "50")
int radius) throws WorldEditException {
radius = Math.max(1, radius);
we.checkMaxRadius(radius);
2019-04-26 02:36:22 +00:00
int affected = editSession.removeNear(session.getPlacementPosition(player), mask, radius);
player.print(affected + " block(s) have been removed.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "replacenear",
aliases = { "/replacenear" },
desc = "Replace nearby blocks"
)
@CommandPermissions("worldedit.replacenear")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int replaceNear(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the square to remove in")
int radius,
@Arg(desc = "The mask matching blocks to remove", def = "")
Mask from,
@Arg(desc = "The pattern of blocks to replace with")
Pattern to) throws WorldEditException {
radius = Math.max(1, radius);
we.checkMaxRadius(radius);
BlockVector3 base = session.getPlacementPosition(player);
2019-04-26 02:36:22 +00:00
BlockVector3 min = base.subtract(radius, radius, radius);
BlockVector3 max = base.add(radius, radius, radius);
Region region = new CuboidRegion(player.getWorld(), min, max);
2019-04-26 02:36:22 +00:00
if (from == null) {
from = new ExistingBlockMask(editSession);
}
2019-04-26 02:36:22 +00:00
int affected = editSession.replaceBlocks(region, from, to);
player.print(affected + " block(s) have been replaced.");
2019-04-26 02:36:22 +00:00
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "snow",
aliases = { "/snow" },
desc = "Simulates snow"
)
@CommandPermissions("worldedit.snow")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int snow(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the circle to snow in", def = "10")
double size) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size);
int affected = editSession.simulateSnow(session.getPlacementPosition(player), size);
2019-04-26 02:36:22 +00:00
player.print(affected + " surface(s) covered. Let it snow~");
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "thaw",
aliases = { "/thaw" },
desc = "Thaws the area"
)
@CommandPermissions("worldedit.thaw")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int thaw(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the circle to thaw in", def = "10")
double size) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size);
int affected = editSession.thaw(session.getPlacementPosition(player), size);
2019-04-26 02:36:22 +00:00
player.print(affected + " surface(s) thawed.");
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "green",
aliases = { "/green" },
desc = "Converts dirt to grass blocks in the area"
)
@CommandPermissions("worldedit.green")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int green(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the circle to convert in", def = "10")
double size,
@Switch(name = 'f', desc = "Also convert coarse dirt")
boolean convertCoarse) throws WorldEditException {
size = Math.max(1, size);
we.checkMaxRadius(size);
2019-04-26 02:36:22 +00:00
final boolean onlyNormalDirt = !convertCoarse;
final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt);
2019-04-26 02:36:22 +00:00
player.print(affected + " surface(s) greened.");
return affected;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "extinguish",
aliases = { "/ex", "/ext", "/extinguish", "ex", "ext" },
desc = "Extinguish nearby fire"
)
@CommandPermissions("worldedit.extinguish")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public void extinguish(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the square to remove in", def = "")
Integer radius) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40;
2019-04-26 02:36:22 +00:00
int size = radius != null ? Math.max(1, radius) : defaultRadius;
we.checkMaxRadius(size);
2019-04-26 02:36:22 +00:00
Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE);
int affected = editSession.removeNear(session.getPlacementPosition(player), mask, size);
player.print(affected + " block(s) have been removed.");
}
@Command(
2019-04-26 02:36:22 +00:00
name = "butcher",
desc = "Kill all or nearby mobs"
)
@CommandPermissions("worldedit.butcher")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int butcher(Actor actor,
@Arg(desc = "Radius to kill mobs in", def = "")
Integer radius,
@Switch(name = 'p', desc = "Also kill pets")
boolean killPets,
@Switch(name = 'n', desc = "Also kill NPCs")
boolean killNpcs,
@Switch(name = 'g', desc = "Also kill golems")
boolean killGolems,
@Switch(name = 'a', desc = "Also kill animals")
boolean killAnimals,
@Switch(name = 'b', desc = "Also kill ambient mobs")
boolean killAmbient,
@Switch(name = 't', desc = "Also kill mobs with name tags")
boolean killWithName,
@Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)")
boolean killFriendly,
@Switch(name = 'r', desc = "Also destroy armor stands")
boolean killArmorStands) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
Player player = actor instanceof Player ? (Player) actor : null;
2019-04-26 02:36:22 +00:00
if (radius == null) {
radius = config.butcherDefaultRadius;
} else if (radius < -1) {
actor.printError("Use -1 to remove all mobs in loaded chunks");
return 0;
} else if (radius == -1) {
if (config.butcherMaxRadius != -1) {
radius = config.butcherMaxRadius;
}
}
2019-04-26 02:36:22 +00:00
if (config.butcherMaxRadius != -1) {
radius = Math.min(radius, config.butcherMaxRadius);
}
CreatureButcher flags = new CreatureButcher(actor);
2019-04-26 02:36:22 +00:00
flags.or(CreatureButcher.Flags.FRIENDLY, killFriendly); // No permission check here. Flags will instead be filtered by the subsequent calls.
flags.or(CreatureButcher.Flags.PETS, killPets, "worldedit.butcher.pets");
flags.or(CreatureButcher.Flags.NPCS, killNpcs, "worldedit.butcher.npcs");
flags.or(CreatureButcher.Flags.GOLEMS, killGolems, "worldedit.butcher.golems");
flags.or(CreatureButcher.Flags.ANIMALS, killAnimals, "worldedit.butcher.animals");
flags.or(CreatureButcher.Flags.AMBIENT, killAmbient, "worldedit.butcher.ambient");
flags.or(CreatureButcher.Flags.TAGGED, killWithName, "worldedit.butcher.tagged");
flags.or(CreatureButcher.Flags.ARMOR_STAND, killArmorStands, "worldedit.butcher.armorstands");
2019-04-26 02:36:22 +00:00
int killed = killMatchingEntities(radius, player, flags::createFunction);
actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + ".");
2019-04-26 02:36:22 +00:00
return killed;
}
@Command(
2019-04-26 02:36:22 +00:00
name = "remove",
aliases = { "rem", "rement" },
desc = "Remove all entities of a type"
)
@CommandPermissions("worldedit.remove")
@Logging(PLACEMENT)
2019-04-26 02:36:22 +00:00
public int remove(Actor actor,
@Arg(desc = "The type of entity to remove")
EntityRemover remover,
@Arg(desc = "The radius of the cuboid to remove from")
int radius) throws WorldEditException {
Player player = actor instanceof Player ? (Player) actor : null;
if (radius < -1) {
actor.printError("Use -1 to remove all entities in loaded chunks");
2019-04-26 02:36:22 +00:00
return 0;
}
2019-04-26 02:36:22 +00:00
int removed = killMatchingEntities(radius, player, remover::createFunction);
actor.print("Marked " + removed + (removed != 1 ? " entities" : " entity") + " for removal.");
return removed;
}
2019-04-26 02:36:22 +00:00
private int killMatchingEntities(Integer radius, Player player, Supplier<EntityFunction> func) throws IncompleteRegionException, MaxChangedBlocksException {
2018-06-16 06:36:55 +00:00
List<EntityVisitor> visitors = new ArrayList<>();
LocalSession session = null;
EditSession editSession = null;
if (player != null) {
session = we.getSessionManager().get(player);
BlockVector3 center = session.getPlacementPosition(player);
editSession = session.createEditSession(player);
List<? extends Entity> entities;
if (radius >= 0) {
CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius);
entities = editSession.getEntities(region);
} else {
entities = editSession.getEntities();
}
2019-04-26 02:36:22 +00:00
visitors.add(new EntityVisitor(entities.iterator(), func.get()));
} else {
Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
for (World world : platform.getWorlds()) {
List<? extends Entity> entities = world.getEntities();
2019-04-26 02:36:22 +00:00
visitors.add(new EntityVisitor(entities.iterator(), func.get()));
}
}
2019-04-26 02:36:22 +00:00
int killed = 0;
for (EntityVisitor visitor : visitors) {
Operations.completeLegacy(visitor);
2019-04-26 02:36:22 +00:00
killed += visitor.getAffected();
}
if (editSession != null) {
session.remember(editSession);
2018-10-21 01:54:58 +00:00
editSession.flushSession();
}
2019-04-26 02:36:22 +00:00
return killed;
}
// get the formatter with the system locale. in the future, if we can get a local from a player, we can use that
private static final DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.getDefault());
static {
formatter.applyPattern("#,##0.#####"); // pattern is locale-insensitive. this can translate to "1.234,56789"
}
@Command(
2019-04-26 02:36:22 +00:00
name = "/calculate",
aliases = { "/calc", "/eval", "/evaluate", "/solve" },
desc = "Evaluate a mathematical expression"
)
@CommandPermissions("worldedit.calc")
2019-04-26 02:36:22 +00:00
public void calc(Actor actor,
@Arg(desc = "Expression to evaluate")
String input) {
try {
Expression expression = Expression.compile(input);
double result = expression.evaluate(
new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout());
String formatted = formatter.format(result);
actor.print(SubtleFormat.wrap(input + " = ")
.append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)));
//actor.print(SubtleFormat.wrap(input).append(Component.newline())
// .append(SubtleFormat.wrap("= "))
// .append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)));
} catch (EvaluationException e) {
actor.printError(String.format(
2019-04-26 02:36:22 +00:00
"'%s' could not be evaluated (error: %s)", input, e.getMessage()));
} catch (ExpressionException e) {
actor.printError(String.format(
2019-04-26 02:36:22 +00:00
"'%s' could not be parsed as a valid expression", input));
}
}
@Command(
2019-04-26 02:36:22 +00:00
name = "/help",
desc = "Displays help for WorldEdit commands"
)
@CommandPermissions("worldedit.help")
2019-04-26 02:36:22 +00:00
public void help(Actor actor,
@Arg(desc = "The page to retrieve", def = "1")
int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true)
2019-04-26 04:03:28 +00:00
List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, we, actor);
}
}