Merge pull request #1981 from EngineHub/feature/pos-command

Add a //pos command to set multiple positions at once
This commit is contained in:
Maddy Miller 2021-12-23 21:28:25 +10:00 committed by GitHub
commit 105f7a439a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 283 additions and 107 deletions

View File

@ -26,6 +26,7 @@
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.command.argument.SelectorChoice;
import com.sk89q.worldedit.command.argument.SelectorChoiceOrList;
import com.sk89q.worldedit.command.tool.NavigationWand;
import com.sk89q.worldedit.command.tool.SelectionWand;
import com.sk89q.worldedit.command.tool.Tool;
@ -49,14 +50,9 @@
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.CylinderRegionSelector;
import com.sk89q.worldedit.regions.selector.EllipsoidRegionSelector;
import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
import com.sk89q.worldedit.regions.selector.RegionSelectorType;
import com.sk89q.worldedit.regions.selector.SphereRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location;
@ -85,8 +81,8 @@
import org.enginehub.piston.exception.StopExecutionException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
@ -105,6 +101,66 @@ public SelectionCommands(WorldEdit we) {
this.we = we;
}
@Nullable
private BlockVector3 getLocatablePosition(Actor actor) {
if (actor instanceof Locatable locatable) {
return locatable.getLocation().toVector().toBlockPoint();
}
actor.printError(TranslatableComponent.of("worldedit.pos.console-require-coords"));
return null;
}
@Command(
name = "/pos",
desc = "Set positions"
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.pos")
public void pos(Actor actor, World world, LocalSession session,
@Arg(desc = "Coordinates to set the primary position to. Defaults to the player position if not passed.", def = "")
BlockVector3 pos1,
@Arg(desc = "Coordinates to add as secondary positions. Defaults to the player position if not passed.", def = "", variable = true)
List<BlockVector3> pos2,
@ArgFlag(name = 's', desc = "Selector to switch to")
SelectorChoice selectorChoice) throws WorldEditException {
if (pos1 == null) {
pos1 = getLocatablePosition(actor);
if (pos1 == null) {
return;
}
}
if (pos2.isEmpty()) {
var newPos2 = getLocatablePosition(actor);
if (newPos2 == null) {
return;
}
pos2 = List.of(newPos2);
}
RegionSelector regionSelector = session.getRegionSelector(world);
if (selectorChoice != null) {
var newSelector = selectorChoice.createNewSelector(world);
session.setRegionSelector(world, newSelector);
selectorChoice.explainNewSelector(actor);
regionSelector = newSelector;
}
regionSelector.selectPrimary(pos1, ActorSelectorLimits.forActor(actor));
for (BlockVector3 vector : pos2) {
regionSelector.selectSecondary(vector, ActorSelectorLimits.forActor(actor));
}
session.dispatchCUISelection(actor);
for (Component line : regionSelector.getSelectionInfoLines()) {
actor.printInfo(line);
}
actor.printInfo(TranslatableComponent.of("worldedit.selection.updated"));
}
@Command(
name = "/pos1",
desc = "Set position 1"
@ -113,24 +169,20 @@ public SelectionCommands(WorldEdit we) {
@CommandPermissions("worldedit.selection.pos")
public void pos1(Actor actor, World world, LocalSession session,
@Arg(desc = "Coordinates to set position 1 to", def = "")
BlockVector3 coordinates) throws WorldEditException {
Location pos;
if (coordinates != null) {
pos = new Location(world, coordinates.toVector3());
} else if (actor instanceof Locatable) {
pos = ((Locatable) actor).getBlockLocation();
} else {
actor.printError(TranslatableComponent.of("worldedit.pos.console-require-coords"));
return;
BlockVector3 coordinates) {
if (coordinates == null) {
coordinates = getLocatablePosition(actor);
if (coordinates == null) {
return;
}
}
if (!session.getRegionSelector(world).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) {
if (!session.getRegionSelector(world).selectPrimary(coordinates, ActorSelectorLimits.forActor(actor))) {
actor.printError(TranslatableComponent.of("worldedit.pos.already-set"));
return;
}
session.getRegionSelector(world)
.explainPrimarySelection(actor, session, pos.toVector().toBlockPoint());
session.getRegionSelector(world).explainPrimarySelection(actor, session, coordinates);
}
@Command(
@ -141,24 +193,20 @@ public void pos1(Actor actor, World world, LocalSession session,
@CommandPermissions("worldedit.selection.pos")
public void pos2(Actor actor, World world, LocalSession session,
@Arg(desc = "Coordinates to set position 2 to", def = "")
BlockVector3 coordinates) throws WorldEditException {
Location pos;
if (coordinates != null) {
pos = new Location(world, coordinates.toVector3());
} else if (actor instanceof Locatable) {
pos = ((Locatable) actor).getBlockLocation();
} else {
actor.printError(TranslatableComponent.of("worldedit.pos.console-require-coords"));
return;
BlockVector3 coordinates) {
if (coordinates == null) {
coordinates = getLocatablePosition(actor);
if (coordinates == null) {
return;
}
}
if (!session.getRegionSelector(world).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) {
if (!session.getRegionSelector(world).selectSecondary(coordinates, ActorSelectorLimits.forActor(actor))) {
actor.printError(TranslatableComponent.of("worldedit.pos.already-set"));
return;
}
session.getRegionSelector(world)
.explainSecondarySelection(actor, session, pos.toVector().toBlockPoint());
session.getRegionSelector(world).explainSecondarySelection(actor, session, coordinates);
}
@Command(
@ -166,7 +214,7 @@ public void pos2(Actor actor, World world, LocalSession session,
desc = "Set position 1 to targeted block"
)
@CommandPermissions("worldedit.selection.hpos")
public void hpos1(Player player, LocalSession session) throws WorldEditException {
public void hpos1(Player player, LocalSession session) {
Location pos = player.getBlockTrace(300);
@ -188,7 +236,7 @@ public void hpos1(Player player, LocalSession session) throws WorldEditException
desc = "Set position 2 to targeted block"
)
@CommandPermissions("worldedit.selection.hpos")
public void hpos2(Player player, LocalSession session) throws WorldEditException {
public void hpos2(Player player, LocalSession session) {
Location pos = player.getBlockTrace(300);
@ -561,74 +609,37 @@ public void distr(Actor actor, World world, LocalSession session,
)
public void select(Actor actor, World world, LocalSession session,
@Arg(desc = "Selector to switch to", def = "")
SelectorChoice selector,
SelectorChoiceOrList selectorChoiceOrList,
@Switch(name = 'd', desc = "Set default selector")
boolean setDefaultSelector) throws WorldEditException {
if (selector == null) {
if (selectorChoiceOrList == null) {
session.getRegionSelector(world).clear();
session.dispatchCUISelection(actor);
actor.printInfo(TranslatableComponent.of("worldedit.select.cleared"));
return;
}
if (!(selectorChoiceOrList instanceof SelectorChoice selectorChoice)) {
CommandListBox box = new CommandListBox("Selection modes", null, null);
box.setHidingHelp(true);
TextComponentProducer contents = box.getContents();
contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline();
box.appendCommand("cuboid", TranslatableComponent.of("worldedit.select.cuboid.description"), "//sel cuboid");
box.appendCommand("extend", TranslatableComponent.of("worldedit.select.extend.description"), "//sel extend");
box.appendCommand("poly", TranslatableComponent.of("worldedit.select.poly.description"), "//sel poly");
box.appendCommand("ellipsoid", TranslatableComponent.of("worldedit.select.ellipsoid.description"), "//sel ellipsoid");
box.appendCommand("sphere", TranslatableComponent.of("worldedit.select.sphere.description"), "//sel sphere");
box.appendCommand("cyl", TranslatableComponent.of("worldedit.select.cyl.description"), "//sel cyl");
box.appendCommand("convex", TranslatableComponent.of("worldedit.select.convex.description"), "//sel convex");
actor.print(box.create(1));
return;
}
final RegionSelector oldSelector = session.getRegionSelector(world);
final RegionSelector newSelector;
switch (selector) {
case CUBOID:
newSelector = new CuboidRegionSelector(oldSelector);
actor.printInfo(TranslatableComponent.of("worldedit.select.cuboid.message"));
break;
case EXTEND:
newSelector = new ExtendingCuboidRegionSelector(oldSelector);
actor.printInfo(TranslatableComponent.of("worldedit.select.extend.message"));
break;
case POLY: {
newSelector = new Polygonal2DRegionSelector(oldSelector);
actor.printInfo(TranslatableComponent.of("worldedit.select.poly.message"));
Optional<Integer> limit = ActorSelectorLimits.forActor(actor).getPolygonVertexLimit();
limit.ifPresent(integer -> actor.printInfo(TranslatableComponent.of("worldedit.select.poly.limit-message", TextComponent.of(integer))));
break;
}
case ELLIPSOID:
newSelector = new EllipsoidRegionSelector(oldSelector);
actor.printInfo(TranslatableComponent.of("worldedit.select.ellipsoid.message"));
break;
case SPHERE:
newSelector = new SphereRegionSelector(oldSelector);
actor.printInfo(TranslatableComponent.of("worldedit.select.sphere.message"));
break;
case CYL:
newSelector = new CylinderRegionSelector(oldSelector);
actor.printInfo(TranslatableComponent.of("worldedit.select.cyl.message"));
break;
case CONVEX:
case HULL:
case POLYHEDRON: {
newSelector = new ConvexPolyhedralRegionSelector(oldSelector);
actor.printInfo(TranslatableComponent.of("worldedit.select.convex.message"));
Optional<Integer> limit = ActorSelectorLimits.forActor(actor).getPolyhedronVertexLimit();
limit.ifPresent(integer -> actor.printInfo(TranslatableComponent.of("worldedit.select.convex.limit-message", TextComponent.of(integer))));
break;
}
case LIST:
default:
CommandListBox box = new CommandListBox("Selection modes", null, null);
box.setHidingHelp(true);
TextComponentProducer contents = box.getContents();
contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline();
box.appendCommand("cuboid", TranslatableComponent.of("worldedit.select.cuboid.description"), "//sel cuboid");
box.appendCommand("extend", TranslatableComponent.of("worldedit.select.extend.description"), "//sel extend");
box.appendCommand("poly", TranslatableComponent.of("worldedit.select.poly.description"), "//sel poly");
box.appendCommand("ellipsoid", TranslatableComponent.of("worldedit.select.ellipsoid.description"), "//sel ellipsoid");
box.appendCommand("sphere", TranslatableComponent.of("worldedit.select.sphere.description"), "//sel sphere");
box.appendCommand("cyl", TranslatableComponent.of("worldedit.select.cyl.description"), "//sel cyl");
box.appendCommand("convex", TranslatableComponent.of("worldedit.select.convex.description"), "//sel convex");
actor.print(box.create(1));
return;
}
final RegionSelector newSelector = selectorChoice.createNewSelector(oldSelector);
selectorChoice.explainNewSelector(actor);
if (setDefaultSelector) {
RegionSelectorType found = null;

View File

@ -39,8 +39,6 @@
public final class EnumConverter {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(SelectorChoice.class),
basic(SelectorChoice.class));
commandManager.registerConverter(Key.of(TreeGenerator.TreeType.class),
full(TreeGenerator.TreeType.class,
t -> ImmutableSet.copyOf(t.lookupKeys),
@ -64,10 +62,6 @@ private static <E extends Enum<E>> ArgumentConverter<E> basic(Class<E> enumClass
return full(enumClass, e -> ImmutableSet.of(e.name().toLowerCase(Locale.ROOT)), null);
}
private static <E extends Enum<E>> ArgumentConverter<E> basic(Class<E> enumClass, @Nullable E unknownValue) {
return full(enumClass, e -> ImmutableSet.of(e.name().toLowerCase(Locale.ROOT)), unknownValue);
}
private static <E extends Enum<E>> ArgumentConverter<E> full(Class<E> enumClass,
Function<E, Set<String>> lookupKeys,
@Nullable E unknownValue) {

View File

@ -19,15 +19,73 @@
package com.sk89q.worldedit.command.argument;
public enum SelectorChoice {
CUBOID,
EXTEND,
POLY,
ELLIPSOID,
SPHERE,
CYL,
CONVEX,
HULL,
POLYHEDRON,
LIST
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.CylinderRegionSelector;
import com.sk89q.worldedit.regions.selector.EllipsoidRegionSelector;
import com.sk89q.worldedit.regions.selector.ExtendingCuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
import com.sk89q.worldedit.regions.selector.SphereRegionSelector;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.World;
import java.util.Optional;
import java.util.function.Function;
public enum SelectorChoice implements SelectorChoiceOrList {
CUBOID(CuboidRegionSelector::new, CuboidRegionSelector::new, "worldedit.select.cuboid.message"),
EXTEND(ExtendingCuboidRegionSelector::new, ExtendingCuboidRegionSelector::new, "worldedit.select.extend.message"),
POLY(Polygonal2DRegionSelector::new, Polygonal2DRegionSelector::new, "worldedit.select.poly.message") {
@Override
public void explainNewSelector(Actor actor) {
super.explainNewSelector(actor);
Optional<Integer> limit = ActorSelectorLimits.forActor(actor).getPolygonVertexLimit();
limit.ifPresent(integer -> actor.printInfo(TranslatableComponent.of(
"worldedit.select.poly.limit-message", TextComponent.of(integer)
)));
}
},
ELLIPSOID(EllipsoidRegionSelector::new, EllipsoidRegionSelector::new, "worldedit.select.ellipsoid.message"),
SPHERE(SphereRegionSelector::new, SphereRegionSelector::new, "worldedit.select.sphere.message"),
CYL(CylinderRegionSelector::new, CylinderRegionSelector::new, "worldedit.select.cyl.message"),
CONVEX(ConvexPolyhedralRegionSelector::new, ConvexPolyhedralRegionSelector::new, "worldedit.select.convex.message") {
@Override
public void explainNewSelector(Actor actor) {
super.explainNewSelector(actor);
Optional<Integer> limit = ActorSelectorLimits.forActor(actor).getPolyhedronVertexLimit();
limit.ifPresent(integer -> actor.printInfo(TranslatableComponent.of(
"worldedit.select.convex.limit-message", TextComponent.of(integer)
)));
}
},
;
private final Function<World, RegionSelector> newFromWorld;
private final Function<RegionSelector, RegionSelector> newFromOld;
private final Component messageComponent;
SelectorChoice(Function<World, RegionSelector> newFromWorld,
Function<RegionSelector, RegionSelector> newFromOld,
String message) {
this.newFromWorld = newFromWorld;
this.newFromOld = newFromOld;
this.messageComponent = TranslatableComponent.of(message);
}
public RegionSelector createNewSelector(World world) {
return this.newFromWorld.apply(world);
}
public RegionSelector createNewSelector(RegionSelector oldSelector) {
return this.newFromOld.apply(oldSelector);
}
public void explainNewSelector(Actor actor) {
actor.printInfo(messageComponent);
}
}

View File

@ -0,0 +1,60 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.SetMultimap;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.MultiKeyConverter;
import org.enginehub.piston.inject.Key;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
public class SelectorChoiceConverter {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(SelectorChoice.class), MultiKeyConverter.from(getBasicItems()));
commandManager.registerConverter(Key.of(SelectorChoiceOrList.class), orListConverter());
}
private static ArgumentConverter<SelectorChoiceOrList> orListConverter() {
SetMultimap<SelectorChoiceOrList, String> items = LinkedHashMultimap.create(getBasicItems());
items.put(SelectorChoiceList.INSTANCE, "list");
return MultiKeyConverter.from(
ImmutableSetMultimap.copyOf(items),
SelectorChoiceList.INSTANCE
);
}
@NotNull
private static SetMultimap<SelectorChoice, String> getBasicItems() {
SetMultimap<SelectorChoice, String> items = LinkedHashMultimap.create();
for (var item : SelectorChoice.values()) {
items.put(item, item.name().toLowerCase(Locale.ROOT));
}
items.put(SelectorChoice.CONVEX, "hull");
items.put(SelectorChoice.CONVEX, "polyhedron");
return items;
}
}

View File

@ -0,0 +1,27 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
public final class SelectorChoiceList implements SelectorChoiceOrList {
public static final SelectorChoiceList INSTANCE = new SelectorChoiceList();
private SelectorChoiceList() {
}
}

View File

@ -0,0 +1,23 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
public sealed interface SelectorChoiceOrList permits SelectorChoice, SelectorChoiceList {
}

View File

@ -82,6 +82,7 @@
import com.sk89q.worldedit.command.argument.OffsetConverter;
import com.sk89q.worldedit.command.argument.RegionFactoryConverter;
import com.sk89q.worldedit.command.argument.RegistryConverter;
import com.sk89q.worldedit.command.argument.SelectorChoiceConverter;
import com.sk89q.worldedit.command.argument.SideEffectConverter;
import com.sk89q.worldedit.command.argument.SideEffectSetConverter;
import com.sk89q.worldedit.command.argument.VectorConverter;
@ -230,6 +231,7 @@ private void registerArgumentConverters() {
OffsetConverter.register(worldEdit, commandManager);
ClipboardFormatConverter.register(commandManager);
ClipboardShareDestinationConverter.register(commandManager);
SelectorChoiceConverter.register(commandManager);
}
private void registerAlwaysInjectedValues() {

View File

@ -428,6 +428,7 @@
"worldedit.selection.transform.error.cannot-expand": "Cannot expand a TransformedRegion.",
"worldedit.selection.transform.error.cannot-contract": "Cannot contract a TransformedRegion.",
"worldedit.selection.transform.error.cannot-change": "Cannot change a TransformedRegion.",
"worldedit.selection.updated": "Positions updated.",
"worldedit.sideeffect.lighting": "Lighting",
"worldedit.sideeffect.lighting.description": "Updates block lighting",