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.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo;
import com.sk89q.worldedit.math.BlockVector2;
@ -39,6 +40,7 @@ import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.storage.LegacyChunkStore;
import com.sk89q.worldedit.world.storage.McRegionChunkStore;
import org.enginehub.piston.annotation.Command;
@ -78,7 +80,7 @@ public class ChunkCommands {
)
@CommandPermissions("worldedit.chunkinfo")
public void chunkInfo(Player player) {
Location pos = player.getBlockIn();
Location pos = player.getBlockLocation();
int chunkX = (int) Math.floor(pos.getBlockX() / 16.0);
int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0);
@ -93,13 +95,13 @@ public class ChunkCommands {
desc = "List chunks that your selection includes"
)
@CommandPermissions("worldedit.listchunks")
public void listChunks(Player player, LocalSession session,
public void listChunks(Actor actor, World world, LocalSession session,
@ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException {
final Region region = session.getSelection(player.getWorld());
final Region region = session.getSelection(world);
WorldEditAsyncCommandBuilder.createAndSendMessage(player,
WorldEditAsyncCommandBuilder.createAndSendMessage(actor,
() -> new ChunkListPaginationBox(region).create(page),
"Listing chunks for " + player.getName());
"Listing chunks for " + actor.getName());
}
@Command(
@ -108,10 +110,10 @@ public class ChunkCommands {
)
@CommandPermissions("worldedit.delchunks")
@Logging(REGION)
public void deleteChunks(Player player, LocalSession session,
public void deleteChunks(Actor actor, World world, LocalSession session,
@ArgFlag(name = 'o', desc = "Only delete chunks older than the specified time.", def = "")
ZonedDateTime beforeTime) throws WorldEditException {
Path worldDir = player.getWorld().getStoragePath();
Path worldDir = world.getStoragePath();
if (worldDir == null) {
throw new StopExecutionException(TextComponent.of("Couldn't find world folder for this world."));
}
@ -134,7 +136,7 @@ public class ChunkCommands {
ChunkDeletionInfo.ChunkBatch newBatch = new ChunkDeletionInfo.ChunkBatch();
newBatch.worldPath = worldDir.toAbsolutePath().normalize().toString();
newBatch.backup = true;
final Region selection = session.getSelection(player.getWorld());
final Region selection = session.getSelection(world);
if (selection instanceof CuboidRegion) {
newBatch.minChunk = selection.getMinimumPoint().shr(4).toBlockVector2();
newBatch.maxChunk = selection.getMaximumPoint().shr(4).toBlockVector2();
@ -159,13 +161,13 @@ public class ChunkCommands {
throw new StopExecutionException(TextComponent.of("Failed to write chunk list: " + e.getMessage()));
}
player.print(String.format("%d chunk(s) have been marked for deletion the next time the server starts.",
actor.print(String.format("%d chunk(s) have been marked for deletion the next time the server starts.",
newBatch.getChunkCount()));
if (currentInfo.batches.size() > 1) {
player.printDebug(String.format("%d chunks total marked for deletion. (May have overlaps).",
actor.printDebug(String.format("%d chunks total marked for deletion. (May have overlaps).",
currentInfo.batches.stream().mapToInt(ChunkDeletionInfo.ChunkBatch::getChunkCount).sum()));
}
player.print(TextComponent.of("You can mark more chunks for deletion, or to stop now, run: ", TextColor.LIGHT_PURPLE)
actor.print(TextComponent.of("You can mark more chunks for deletion, or to stop now, run: ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/stop", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop"))));
}