feature(cli): Added a CLI version of WorldEdit, and allowed most commands to be run from console (#508)

* Re-do commits to avoid awful rebase

* You can load and save a schematic file now. Still gotta setup ability to use commands as a console actor.

* Add a world override concept to LocalSession, and allow a lot more commands to be performed by actors.

* Fixed commands, and set the loaded schematic as the world override in CLI

* Properly load tags

* Added 1.14.4 data values

* Allow a majority of commands to be performed by the console.

* Fixed a lot of PR requested changes

* Added a Locatable interface and use that for getting the location of the player in commands.

* Added script support. Currently requires a newline at the end of the script.

* Shade everything to allow this to run locally - should probably minimize this to an extent later.

* Actually hook up the version

* Added a //world command to set the override

* Fixed a missed checkstyle issue

* Added CommandBlock support to Bukkit

* Make command block support configurable

* Minor cleanup and implementing a few of the final functions

* Fixed most issues from PR

* Improve UX, saving is now automatic and unknown command messages show

* Better save docs and support any clipboard format

* Include the entire formats list

* Arrays.copyOf

* Clear the world override if the selector is called on another world.

* Update logging extent to allow basic logging with non-player actors
This commit is contained in:
Matthew Miller
2019-08-25 19:58:28 +10:00
committed by GitHub
parent a0b9810c44
commit 0620478763
72 changed files with 2386 additions and 569 deletions

View File

@ -28,6 +28,7 @@ import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.GroundFunction;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace;
@ -54,6 +55,7 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
@ -89,7 +91,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.set")
@Logging(REGION)
public int set(Player player, EditSession editSession,
public int set(Actor actor, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern) {
@ -100,9 +102,9 @@ public class RegionCommands {
List<String> messages = Lists.newArrayList();
visitor.addStatusMessages(messages);
if (messages.isEmpty()) {
player.print("Operation completed.");
actor.print("Operation completed.");
} else {
player.print("Operation completed (" + Joiner.on(", ").join(messages) + ").");
actor.print("Operation completed (" + Joiner.on(", ").join(messages) + ").");
}
return visitor.getAffected();
@ -115,7 +117,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.line")
@Logging(REGION)
public int line(Player player, EditSession editSession,
public int line(Actor actor, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to place")
Pattern pattern,
@ -124,7 +126,7 @@ public class RegionCommands {
@Switch(name = 'h', desc = "Generate only a shell")
boolean shell) throws WorldEditException {
if (!(region instanceof CuboidRegion)) {
player.printError("//line only works with cuboid selections");
actor.printError("//line only works with cuboid selections");
return 0;
}
checkCommandArgument(thickness >= 0, "Thickness must be >= 0");
@ -134,7 +136,7 @@ public class RegionCommands {
BlockVector3 pos2 = cuboidregion.getPos2();
int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell);
player.print(blocksChanged + " block(s) have been changed.");
actor.print(blocksChanged + " block(s) have been changed.");
return blocksChanged;
}
@ -145,7 +147,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.curve")
@Logging(REGION)
public int curve(Player player, EditSession editSession,
public int curve(Actor actor, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to place")
Pattern pattern,
@ -154,7 +156,7 @@ public class RegionCommands {
@Switch(name = 'h', desc = "Generate only a shell")
boolean shell) throws WorldEditException {
if (!(region instanceof ConvexPolyhedralRegion)) {
player.printError("//curve only works with convex polyhedral selections");
actor.printError("//curve only works with convex polyhedral selections");
return 0;
}
checkCommandArgument(thickness >= 0, "Thickness must be >= 0");
@ -164,7 +166,7 @@ public class RegionCommands {
int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell);
player.print(blocksChanged + " block(s) have been changed.");
actor.print(blocksChanged + " block(s) have been changed.");
return blocksChanged;
}
@ -175,7 +177,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.replace")
@Logging(REGION)
public int replace(Player player, EditSession editSession, @Selection Region region,
public int replace(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "The mask representing blocks to replace", def = "")
Mask from,
@Arg(desc = "The pattern of blocks to replace with")
@ -184,7 +186,7 @@ public class RegionCommands {
from = new ExistingBlockMask(editSession);
}
int affected = editSession.replaceBlocks(region, from, to);
player.print(affected + " block(s) have been replaced.");
actor.print(affected + " block(s) have been replaced.");
return affected;
}
@ -194,11 +196,11 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.overlay")
@Logging(REGION)
public int overlay(Player player, EditSession editSession, @Selection Region region,
public int overlay(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "The pattern of blocks to overlay")
Pattern pattern) throws WorldEditException {
int affected = editSession.overlayCuboidBlocks(region, pattern);
player.print(affected + " block(s) have been overlaid.");
actor.print(affected + " block(s) have been overlaid.");
return affected;
}
@ -209,11 +211,11 @@ public class RegionCommands {
)
@Logging(REGION)
@CommandPermissions("worldedit.region.center")
public int center(Player player, EditSession editSession, @Selection Region region,
public int center(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern) throws WorldEditException {
int affected = editSession.center(region, pattern);
player.print("Center set (" + affected + " block(s) changed)");
actor.print("Center set (" + affected + " block(s) changed)");
return affected;
}
@ -223,9 +225,9 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.naturalize")
@Logging(REGION)
public int naturalize(Player player, EditSession editSession, @Selection Region region) throws WorldEditException {
public int naturalize(Actor actor, EditSession editSession, @Selection Region region) throws WorldEditException {
int affected = editSession.naturalizeCuboidBlocks(region);
player.print(affected + " block(s) have been made to look more natural.");
actor.print(affected + " block(s) have been made to look more natural.");
return affected;
}
@ -235,11 +237,11 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.walls")
@Logging(REGION)
public int walls(Player player, EditSession editSession, @Selection Region region,
public int walls(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern) throws WorldEditException {
int affected = editSession.makeWalls(region, pattern);
player.print(affected + " block(s) have been changed.");
actor.print(affected + " block(s) have been changed.");
return affected;
}
@ -250,11 +252,11 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.faces")
@Logging(REGION)
public int faces(Player player, EditSession editSession, @Selection Region region,
public int faces(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern) throws WorldEditException {
int affected = editSession.makeCuboidFaces(region, pattern);
player.print(affected + " block(s) have been changed.");
actor.print(affected + " block(s) have been changed.");
return affected;
}
@ -265,7 +267,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.smooth")
@Logging(REGION)
public int smooth(Player player, EditSession editSession, @Selection Region region,
public int smooth(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "# of iterations to perform", def = "1")
int iterations,
@Arg(desc = "The mask of blocks to use as the height map", def = "")
@ -273,7 +275,7 @@ public class RegionCommands {
HeightMap heightMap = new HeightMap(editSession, region, mask);
HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0));
int affected = heightMap.applyFilter(filter, iterations);
player.print("Terrain's height map smoothed. " + affected + " block(s) changed.");
actor.print("Terrain's height map smoothed. " + affected + " block(s) changed.");
return affected;
}
@ -283,7 +285,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.move")
@Logging(ORIENTATION_REGION)
public int move(Player player, EditSession editSession, LocalSession session,
public int move(Actor actor, World world, EditSession editSession, LocalSession session,
@Selection Region region,
@Arg(desc = "# of blocks to move", def = "1")
int count,
@ -321,14 +323,14 @@ public class RegionCommands {
try {
region.shift(direction.multiply(count));
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
session.getRegionSelector(world).learnChanges();
session.getRegionSelector(world).explainRegionAdjust(actor, session);
} catch (RegionOperationException e) {
player.printError(e.getMessage());
actor.printError(e.getMessage());
}
}
player.print(affected + " block(s) moved.");
actor.print(affected + " block(s) moved.");
return affected;
}
@ -338,7 +340,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.stack")
@Logging(ORIENTATION_REGION)
public int stack(Player player, EditSession editSession, LocalSession session,
public int stack(Actor actor, World world, EditSession editSession, LocalSession session,
@Selection Region region,
@Arg(desc = "# of copies to stack", def = "1")
int count,
@ -376,14 +378,14 @@ public class RegionCommands {
final BlockVector3 shiftVector = direction.toVector3().multiply(count * (Math.abs(direction.dot(size)) + 1)).toBlockPoint();
region.shift(shiftVector);
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
session.getRegionSelector(world).learnChanges();
session.getRegionSelector(world).explainRegionAdjust(actor, session);
} catch (RegionOperationException e) {
player.printError(e.getMessage());
actor.printError(e.getMessage());
}
}
player.print(affected + " block(s) changed. Undo with //undo");
actor.print(affected + " block(s) changed. Undo with //undo");
return affected;
}
@ -395,15 +397,16 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.regen")
@Logging(REGION)
public void regenerateChunk(Player player, LocalSession session, EditSession editSession, @Selection Region region) throws WorldEditException {
public void regenerateChunk(Actor actor, World world, LocalSession session,
EditSession editSession, @Selection Region region) throws WorldEditException {
Mask mask = session.getMask();
try {
session.setMask(null);
player.getWorld().regenerate(region, editSession);
world.regenerate(region, editSession);
} finally {
session.setMask(mask);
}
player.print("Region regenerated.");
actor.print("Region regenerated.");
}
@Command(
@ -415,7 +418,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.deform")
@Logging(ALL)
public int deform(Player player, LocalSession session, EditSession editSession,
public int deform(Actor actor, LocalSession session, EditSession editSession,
@Selection Region region,
@Arg(desc = "The expression to use", variable = true)
List<String> expression,
@ -430,7 +433,7 @@ public class RegionCommands {
zero = Vector3.ZERO;
unit = Vector3.ONE;
} else if (offset) {
zero = session.getPlacementPosition(player).toVector3();
zero = session.getPlacementPosition(actor).toVector3();
unit = Vector3.ONE;
} else {
final Vector3 min = region.getMinimumPoint().toVector3();
@ -446,11 +449,13 @@ public class RegionCommands {
try {
final int affected = editSession.deformRegion(region, zero, unit, String.join(" ", expression), session.getTimeout());
player.findFreePosition();
player.print(affected + " block(s) have been deformed.");
if (actor instanceof Player) {
((Player) actor).findFreePosition();
}
actor.print(affected + " block(s) have been deformed.");
return affected;
} catch (ExpressionException e) {
player.printError(e.getMessage());
actor.printError(e.getMessage());
return 0;
}
}
@ -462,7 +467,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.hollow")
@Logging(REGION)
public int hollow(Player player, EditSession editSession,
public int hollow(Actor actor, EditSession editSession,
@Selection Region region,
@Arg(desc = "Thickness of the shell to leave", def = "0")
int thickness,
@ -471,7 +476,7 @@ public class RegionCommands {
checkCommandArgument(thickness >= 0, "Thickness must be >= 0");
int affected = editSession.hollowOutRegion(region, thickness, pattern);
player.print(affected + " block(s) have been changed.");
actor.print(affected + " block(s) have been changed.");
return affected;
}
@ -481,14 +486,14 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.forest")
@Logging(REGION)
public int forest(Player player, EditSession editSession, @Selection Region region,
public int forest(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "The type of tree to place", def = "tree")
TreeType type,
@Arg(desc = "The density of the forest", def = "5")
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]");
int affected = editSession.makeForest(region, density / 100, type);
player.print(affected + " trees created.");
actor.print(affected + " trees created.");
return affected;
}
@ -498,7 +503,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.flora")
@Logging(REGION)
public int flora(Player player, EditSession editSession, @Selection Region region,
public int flora(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "The density of the forest", def = "5")
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]");
@ -510,7 +515,7 @@ public class RegionCommands {
Operations.completeLegacy(visitor);
int affected = ground.getAffected();
player.print(affected + " flora created.");
actor.print(affected + " flora created.");
return affected;
}