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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 2386 additions and 569 deletions

View File

@ -48,6 +48,11 @@
<allow pkg="io.papermc.lib"/>
</subpackage>
<subpackage name="cli">
<allow pkg="org.apache.logging.log4j"/>
<allow pkg="org.apache.commons.cli" />
</subpackage>
<subpackage name="forge">
<allow pkg="cpw"/>
<allow pkg="net.minecraft"/>

View File

@ -2,7 +2,7 @@ rootProject.name = "worldedit"
include("worldedit-libs")
listOf("bukkit", "core", "forge", "sponge", "fabric").forEach {
listOf("bukkit", "core", "forge", "sponge", "fabric", "cli").forEach {
include("worldedit-libs:$it")
include("worldedit-$it")
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import org.bukkit.Bukkit;
@ -44,9 +43,4 @@ public class BukkitBlockCategoryRegistry implements BlockCategoryRegistry {
Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, new NamespacedKey(namespace, key), Material.class);
return getFromBukkitTag(tag);
}
@Override
public Set<BlockType> getAll(Category<BlockType> category) {
return getCategorisedByName(category.getId());
}
}

View File

@ -0,0 +1,160 @@
/*
* 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.bukkit;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.extension.platform.AbstractNonPlayerActor;
import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import org.bukkit.Material;
import org.bukkit.command.BlockCommandSender;
import java.util.UUID;
import javax.annotation.Nullable;
public class BukkitBlockCommandSender extends AbstractNonPlayerActor implements Locatable {
private final BlockCommandSender sender;
private final WorldEditPlugin plugin;
private final Location location;
private final UUID uuid;
public BukkitBlockCommandSender(WorldEditPlugin plugin, BlockCommandSender sender) {
checkNotNull(plugin);
checkNotNull(sender);
this.plugin = plugin;
this.sender = sender;
this.location = BukkitAdapter.adapt(sender.getBlock().getLocation());
this.uuid = new UUID(location.toVector().toBlockPoint().hashCode(), location.getExtent().hashCode());
}
@Override
public String getName() {
return sender.getName();
}
@Override
public void printRaw(String msg) {
for (String part : msg.split("\n")) {
sender.sendMessage(part);
}
}
@Override
public void print(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.LIGHT_PURPLE));
}
}
@Override
public void printDebug(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.GRAY));
}
}
@Override
public void printError(String msg) {
for (String part : msg.split("\n")) {
print(TextComponent.of(part, TextColor.RED));
}
}
@Override
public void print(Component component) {
TextAdapter.sendComponent(sender, component);
}
@Override
public Location getLocation() {
return this.location;
}
@Override
public boolean setLocation(Location location) {
return false;
}
@Override
public Extent getExtent() {
return this.location.getExtent();
}
@Override
public UUID getUniqueId() {
return uuid;
}
@Override
public String[] getGroups() {
return new String[0];
}
@Override
public void checkPermission(String permission) throws AuthorizationException {
if (!hasPermission(permission)) {
throw new AuthorizationException();
}
}
@Override
public boolean hasPermission(String permission) {
return sender.hasPermission(permission);
}
@Override
public SessionKey getSessionKey() {
return new SessionKey() {
@Nullable
@Override
public String getName() {
return sender.getName();
}
@Override
public boolean isActive() {
return sender.getBlock().getType() == Material.COMMAND_BLOCK
|| sender.getBlock().getType() == Material.CHAIN_COMMAND_BLOCK
|| sender.getBlock().getType() == Material.REPEATING_COMMAND_BLOCK;
}
@Override
public boolean isPersistent() {
return false;
}
@Override
public UUID getUniqueId() {
return uuid;
}
};
}
}

View File

@ -22,8 +22,7 @@ package com.sk89q.worldedit.bukkit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.extension.platform.AbstractNonPlayerActor;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.text.Component;
@ -31,12 +30,11 @@ import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.io.File;
import java.util.UUID;
import javax.annotation.Nullable;
public class BukkitCommandSender implements Actor {
public class BukkitCommandSender extends AbstractNonPlayerActor {
/**
* One time generated ID.
@ -98,11 +96,6 @@ public class BukkitCommandSender implements Actor {
TextAdapter.sendComponent(sender, component);
}
@Override
public boolean canDestroyBedrock() {
return true;
}
@Override
public String[] getGroups() {
return new String[0];
@ -117,42 +110,23 @@ public class BukkitCommandSender implements Actor {
public void checkPermission(String permission) throws AuthorizationException {
}
@Override
public boolean isPlayer() {
return false;
}
@Override
public File openFileOpenDialog(String[] extensions) {
return null;
}
@Override
public File openFileSaveDialog(String[] extensions) {
return null;
}
@Override
public void dispatchCUIEvent(CUIEvent event) {
}
@Override
public SessionKey getSessionKey() {
return new SessionKey() {
@Nullable
@Override
public String getName() {
return null;
return sender.getName();
}
@Override
public boolean isActive() {
return false;
return true;
}
@Override
public boolean isPersistent() {
return false;
return true;
}
@Override

View File

@ -32,6 +32,7 @@ import java.io.File;
public class BukkitConfiguration extends YAMLConfiguration {
public boolean noOpPermissions = false;
public boolean commandBlockSupport = false;
@Unreported private final WorldEditPlugin plugin;
public BukkitConfiguration(YAMLProcessor config, WorldEditPlugin plugin) {
@ -43,6 +44,7 @@ public class BukkitConfiguration extends YAMLConfiguration {
public void load() {
super.load();
noOpPermissions = config.getBoolean("no-op-permissions", false);
commandBlockSupport = config.getBoolean("command-block-support", false);
migrateLegacyFolders();
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
import org.bukkit.Bukkit;
@ -44,9 +43,4 @@ public class BukkitItemCategoryRegistry implements ItemCategoryRegistry {
Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_ITEMS, new NamespacedKey(namespace, key), Material.class);
return getFromBukkitTag(tag);
}
@Override
public Set<ItemType> getAll(Category<ItemType> category) {
return getCategorisedByName(category.getId());
}
}

View File

@ -58,6 +58,7 @@ import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
@ -159,6 +160,11 @@ public class BukkitWorld extends AbstractWorld {
return getWorld().getName();
}
@Override
public String getId() {
return getWorld().getName().replace(" ", "_").toLowerCase(Locale.ROOT);
}
@Override
public Path getStoragePath() {
return getWorld().getWorldFolder().toPath();

View File

@ -56,6 +56,7 @@ import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Biome;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
@ -432,6 +433,8 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter {
public Actor wrapCommandSender(CommandSender sender) {
if (sender instanceof Player) {
return wrapPlayer((Player) sender);
} else if (config.commandBlockSupport && sender instanceof BlockCommandSender) {
return new BukkitBlockCommandSender(this, (BlockCommandSender) sender);
}
return new BukkitCommandSender(this, sender);

View File

@ -149,3 +149,4 @@ no-op-permissions: false
debug: false
show-help-on-first-use: true
server-side-cui: true
command-block-support: false

View File

@ -0,0 +1,33 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
dependencies {
"compile"(project(":worldedit-core"))
"compile"("org.apache.logging.log4j:log4j-core:2.8.1")
"compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1")
"compile"("commons-cli:commons-cli:1.4")
}
tasks.named<Jar>("jar") {
manifest {
attributes(
"Implementation-Version" to project.version,
"Main-Class" to "com.sk89q.worldedit.cli.CLIWorldEdit"
)
}
}
tasks.named<ShadowJar>("shadowJar") {
dependencies {
include { true }
}
minimize {
exclude { true }
}
}
tasks.named("assemble").configure {
dependsOn("shadowJar")
}

View File

@ -0,0 +1,37 @@
/*
* 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.cli;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
public class CLIBlockCategoryRegistry implements BlockCategoryRegistry {
@Override
public Set<BlockType> getCategorisedByName(String category) {
return CLIWorldEdit.inst.getFileRegistries().getDataFile().blocktags.getOrDefault(category, Collections.emptyList()).stream()
.map(BlockType.REGISTRY::get)
.collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.cli;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.sk89q.worldedit.cli.data.FileRegistries;
import com.sk89q.worldedit.registry.state.BooleanProperty;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BundledBlockRegistry;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
public class CLIBlockRegistry extends BundledBlockRegistry {
private Property<?> createProperty(String type, String key, List<String> values) {
switch (type) {
case "int": {
List<Integer> fixedValues = values.stream().map(Integer::parseInt).collect(Collectors.toList());
return new IntegerProperty(key, fixedValues);
}
case "bool": {
List<Boolean> fixedValues = values.stream().map(Boolean::parseBoolean).collect(Collectors.toList());
return new BooleanProperty(key, fixedValues);
}
case "enum": {
return new EnumProperty(key, values);
}
case "direction": {
List<Direction> fixedValues = values.stream().map(String::toUpperCase).map(Direction::valueOf).collect(Collectors.toList());
return new DirectionalProperty(key, fixedValues);
}
default:
throw new RuntimeException("Failed to create property");
}
}
@Nullable
@Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
Map<String, FileRegistries.BlockProperty> properties =
CLIWorldEdit.inst.getFileRegistries().getDataFile().blocks.get(blockType.getId()).properties;
return ImmutableMap.copyOf(Maps.transformEntries(properties,
(Maps.EntryTransformer<String, FileRegistries.BlockProperty, Property<?>>)
(key, value) -> createProperty(value.type, key, value.values)));
}
}

View File

@ -0,0 +1,164 @@
/*
* 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.cli;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.FileDialogUtil;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer;
import org.slf4j.Logger;
import java.io.File;
import java.util.UUID;
public class CLICommandSender implements Actor {
/**
* One time generated ID.
*/
private static final UUID DEFAULT_ID = UUID.fromString("a233eb4b-4cab-42cd-9fd9-7e7b9a3f74be");
private final CLIWorldEdit app;
private final Logger sender;
public CLICommandSender(CLIWorldEdit app, Logger sender) {
checkNotNull(app);
checkNotNull(sender);
this.app = app;
this.sender = sender;
}
@Override
public UUID getUniqueId() {
return DEFAULT_ID;
}
@Override
public String getName() {
return "Console";
}
@Override
public void printRaw(String msg) {
for (String part : msg.split("\n")) {
sender.info(part);
}
}
private static final String ANSI_PURPLE = "\u001B[35m";
private static final String ANSI_RED = "\u001B[31m";
private static final String ANSI_GREEN = "\u001B[32m";
private static final String ANSI_RESET = "\u001B[0m";
@Override
public void print(String msg) {
for (String part : msg.split("\n")) {
sender.info(ANSI_PURPLE + part + ANSI_RESET);
}
}
@Override
public void printDebug(String msg) {
for (String part : msg.split("\n")) {
sender.debug(ANSI_GREEN + part + ANSI_RESET);
}
}
@Override
public void printError(String msg) {
for (String part : msg.split("\n")) {
sender.error(ANSI_RED + part + ANSI_RESET);
}
}
@Override
public void print(Component component) {
print(PlainComponentSerializer.INSTANCE.serialize(component));
}
@Override
public boolean canDestroyBedrock() {
return true;
}
@Override
public String[] getGroups() {
return new String[0];
}
@Override
public boolean hasPermission(String perm) {
return true;
}
@Override
public void checkPermission(String permission) throws AuthorizationException {
}
@Override
public boolean isPlayer() {
return false;
}
@Override
public File openFileOpenDialog(String[] extensions) {
return FileDialogUtil.showOpenDialog(extensions);
}
@Override
public File openFileSaveDialog(String[] extensions) {
return FileDialogUtil.showSaveDialog(extensions);
}
@Override
public void dispatchCUIEvent(CUIEvent event) {
}
@Override
public SessionKey getSessionKey() {
return new SessionKey() {
@Override
public String getName() {
return "Console";
}
@Override
public boolean isActive() {
return true;
}
@Override
public boolean isPersistent() {
return true;
}
@Override
public UUID getUniqueId() {
return DEFAULT_ID;
}
};
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.cli;
import com.sk89q.worldedit.util.PropertiesConfiguration;
import java.io.File;
public class CLIConfiguration extends PropertiesConfiguration {
public CLIConfiguration(CLIWorldEdit app) {
super(app.getWorkingDir().resolve("worldedit.properties").toFile());
}
@Override
protected void loadExtra() {
}
@Override
public File getWorkingDirectory() {
return CLIWorldEdit.inst.getWorkingDir().toFile();
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.cli;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
import java.util.Set;
import java.util.stream.Collectors;
public class CLIItemCategoryRegistry implements ItemCategoryRegistry {
@Override
public Set<ItemType> getCategorisedByName(String category) {
return CLIWorldEdit.inst.getFileRegistries().getDataFile().itemtags.get(category).stream()
.map(ItemType.REGISTRY::get)
.collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,159 @@
/*
* 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.cli;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.AbstractPlatform;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.entity.EntityTypes;
import com.sk89q.worldedit.world.registry.Registries;
import org.enginehub.piston.CommandManager;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import javax.annotation.Nullable;
class CLIPlatform extends AbstractPlatform {
private final CLIWorldEdit app;
private int dataVersion = -1;
private final List<World> worlds = new ArrayList<>();
private final Timer timer = new Timer();
private int lastTimerId = 0;
CLIPlatform(CLIWorldEdit app) {
this.app = app;
}
@Override
public Registries getRegistries() {
return CLIRegistries.getInstance();
}
@Override
public int getDataVersion() {
return this.dataVersion;
}
public void setDataVersion(int dataVersion) {
this.dataVersion = dataVersion;
}
@Override
public DataFixer getDataFixer() {
return null;
}
@Override
public boolean isValidMobType(String type) {
return EntityTypes.get(type) != null;
}
@Override
public void reload() {
getConfiguration().load();
}
@Override
public int schedule(long delay, long period, Runnable task) {
this.timer.schedule(new TimerTask() {
@Override
public void run() {
task.run();
if (period >= 0) {
timer.schedule(this, period);
}
}
}, delay);
return this.lastTimerId++;
}
@Override
public List<? extends World> getWorlds() {
return this.worlds;
}
@Nullable
@Override
public Player matchPlayer(Player player) {
return null;
}
@Nullable
@Override
public World matchWorld(World world) {
return this.worlds.stream()
.filter(w -> w.getId().equals(world.getId()))
.findAny()
.orElse(null);
}
@Override
public void registerCommands(CommandManager manager) {
}
@Override
public void registerGameHooks() {
}
@Override
public CLIConfiguration getConfiguration() {
return app.getConfig();
}
@Override
public String getVersion() {
return app.getInternalVersion();
}
@Override
public String getPlatformName() {
return "CLI-Official";
}
@Override
public String getPlatformVersion() {
return app.getInternalVersion();
}
@Override
public Map<Capability, Preference> getCapabilities() {
Map<Capability, Preference> capabilities = new EnumMap<>(Capability.class);
capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS);
capabilities.put(Capability.GAME_HOOKS, Preference.NORMAL);
capabilities.put(Capability.PERMISSIONS, Preference.NORMAL);
capabilities.put(Capability.USER_COMMANDS, Preference.NORMAL);
capabilities.put(Capability.WORLD_EDITING, Preference.PREFERRED);
return capabilities;
}
public void addWorld(World world) {
worlds.add(world);
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.cli;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import com.sk89q.worldedit.world.registry.BundledRegistries;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
public class CLIRegistries extends BundledRegistries {
private static final CLIRegistries INSTANCE = new CLIRegistries();
private final BlockRegistry blockRegistry = new CLIBlockRegistry();
private final BlockCategoryRegistry blockCategoryRegistry = new CLIBlockCategoryRegistry();
private final ItemCategoryRegistry itemCategoryRegistry = new CLIItemCategoryRegistry();
/**
* Create a new instance.
*/
private CLIRegistries() {
}
@Override
public BlockRegistry getBlockRegistry() {
return blockRegistry;
}
@Override
public BlockCategoryRegistry getBlockCategoryRegistry() {
return blockCategoryRegistry;
}
@Override
public ItemCategoryRegistry getItemCategoryRegistry() {
return itemCategoryRegistry;
}
/**
* Get a static instance.
*
* @return an instance
*/
public static CLIRegistries getInstance() {
return INSTANCE;
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.cli;
public interface CLIWorld {
/**
* Saves this world back to file if dirty or forced.
*
* @param force Force a save
*/
void save(boolean force);
/**
* Gets whether the world is dirty.
*
* @return If it's dirty
*/
boolean isDirty();
/**
* Set the world's dirty status
*
* @param dirty if dirty
*/
void setDirty(boolean dirty);
}

View File

@ -0,0 +1,335 @@
/*
* 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.cli;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.cli.data.FileRegistries;
import com.sk89q.worldedit.cli.schematic.ClipboardWorld;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockCategory;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.FuzzyBlockState;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemCategory;
import com.sk89q.worldedit.world.item.ItemType;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Map;
import java.util.Scanner;
/**
* The CLI implementation of WorldEdit.
*/
public class CLIWorldEdit {
private static final Logger LOGGER = LoggerFactory.getLogger(CLIWorldEdit.class);
public static CLIWorldEdit inst;
private CLIPlatform platform;
private CLIConfiguration config;
private Path workingDir;
private String version;
private Actor commandSender;
private FileRegistries fileRegistries;
public CLIWorldEdit() {
inst = this;
}
private void setupPlatform() {
this.fileRegistries = new FileRegistries(this);
this.fileRegistries.loadDataFiles();
WorldEdit.getInstance().getPlatformManager().register(platform);
}
public void setupRegistries() {
// Blocks
for (Map.Entry<String, FileRegistries.BlockManifest> manifestEntry : fileRegistries.getDataFile().blocks.entrySet()) {
if (BlockType.REGISTRY.get(manifestEntry.getKey()) == null) {
BlockType.REGISTRY.register(manifestEntry.getKey(), new BlockType(manifestEntry.getKey(), input -> {
ParserContext context = new ParserContext();
context.setPreferringWildcard(true);
context.setTryLegacy(false);
context.setRestricted(false);
try {
FuzzyBlockState state = (FuzzyBlockState) WorldEdit.getInstance().getBlockFactory().parseFromInput(
manifestEntry.getValue().defaultstate,
context
).toImmutableState();
BlockState defaultState = input.getBlockType().getAllStates().get(0);
for (Map.Entry<Property<?>, Object> propertyObjectEntry : state.getStates().entrySet()) {
@SuppressWarnings("unchecked")
Property<Object> prop = (Property<Object>) propertyObjectEntry.getKey();
defaultState = defaultState.with(prop, propertyObjectEntry.getValue());
}
return defaultState;
} catch (InputParseException e) {
LOGGER.warn("Error loading block state for " + manifestEntry.getKey(), e);
return input;
}
}));
}
}
// Items
for (String name : fileRegistries.getDataFile().items) {
if (ItemType.REGISTRY.get(name) == null) {
ItemType.REGISTRY.register(name, new ItemType(name));
}
}
// Entities
for (String name : fileRegistries.getDataFile().entities) {
if (EntityType.REGISTRY.get(name) == null) {
EntityType.REGISTRY.register(name, new EntityType(name));
}
}
// Biomes
for (String name : fileRegistries.getDataFile().biomes) {
if (BiomeType.REGISTRY.get(name) == null) {
BiomeType.REGISTRY.register(name, new BiomeType(name));
}
}
// Tags
for (String name : fileRegistries.getDataFile().blocktags.keySet()) {
if (BlockCategory.REGISTRY.get(name) == null) {
BlockCategory.REGISTRY.register(name, new BlockCategory(name));
}
}
for (String name : fileRegistries.getDataFile().itemtags.keySet()) {
if (ItemCategory.REGISTRY.get(name) == null) {
ItemCategory.REGISTRY.register(name, new ItemCategory(name));
}
}
}
public void onInitialized() {
// Setup working directory
workingDir = Paths.get("worldedit");
if (!Files.exists(workingDir)) {
try {
Files.createDirectory(workingDir);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
this.commandSender = new CLICommandSender(this, LOGGER);
this.platform = new CLIPlatform(this);
LOGGER.info("WorldEdit CLI (version " + getInternalVersion() + ") is loaded");
}
public void onStarted() {
setupPlatform();
setupRegistries();
WorldEdit.getInstance().loadMappings();
config = new CLIConfiguration(this);
config.load();
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
}
public void onStopped() {
WorldEdit worldEdit = WorldEdit.getInstance();
worldEdit.getSessionManager().unload();
worldEdit.getPlatformManager().unregister(platform);
}
public FileRegistries getFileRegistries() {
return this.fileRegistries;
}
/**
* Get the configuration.
*
* @return the CLI configuration
*/
CLIConfiguration getConfig() {
return this.config;
}
/**
* Get the WorldEdit proxy for the platform.
*
* @return the WorldEdit platform
*/
public Platform getPlatform() {
return this.platform;
}
/**
* Get the working directory where WorldEdit's files are stored.
*
* @return the working directory
*/
public Path getWorkingDir() {
return this.workingDir;
}
/**
* Get the version of the WorldEdit-CLI implementation.
*
* @return a version string
*/
String getInternalVersion() {
if (version == null) {
version = getClass().getPackage().getImplementationVersion();
}
return version;
}
public void saveAllWorlds(boolean force) {
platform.getWorlds().stream()
.filter(world -> world instanceof CLIWorld)
.forEach(world -> ((CLIWorld) world).save(force));
}
public void run(InputStream inputStream) {
try (Scanner scanner = new Scanner(inputStream)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.equals("stop")) {
commandSender.print("Stopping!");
break;
}
CommandEvent event = new CommandEvent(commandSender, line);
WorldEdit.getInstance().getEventBus().post(event);
if (!event.isCancelled()) {
commandSender.printError("Unknown command!");
} else {
saveAllWorlds(false);
}
}
} finally {
saveAllWorlds(false);
}
}
public static void main(String[] args) {
Options options = new Options();
options.addOption("f", "file", true, "The file to load in. Either a schematic, or a level.dat in a world folder.");
options.addOption("s", "script", true, "A file containing a list of commands to run. Newline separated.");
int exitCode = 0;
CLIWorldEdit app = new CLIWorldEdit();
app.onInitialized();
InputStream inputStream = System.in;
try {
CommandLine cmd = new DefaultParser().parse(options, args);
String fileArg = cmd.getOptionValue('f');
File file;
if (fileArg == null) {
String[] formats = Arrays.copyOf(ClipboardFormats.getFileExtensionArray(), ClipboardFormats.getFileExtensionArray().length + 1);
formats[formats.length - 1] = "dat";
file = app.commandSender.openFileOpenDialog(formats);
} else {
file = new File(fileArg);
}
if (file == null) {
throw new IllegalArgumentException("A file must be provided!");
}
if (file.getName().endsWith("level.dat")) {
throw new IllegalArgumentException("level.dat file support is unfinished.");
} else {
ClipboardFormat format = ClipboardFormats.findByFile(file);
if (format != null) {
ClipboardReader dataVersionReader = format
.getReader(Files.newInputStream(file.toPath(), StandardOpenOption.READ));
int dataVersion = dataVersionReader.getDataVersion()
.orElseThrow(() -> new IllegalArgumentException("Failed to obtain data version from schematic."));
dataVersionReader.close();
app.platform.setDataVersion(dataVersion);
app.onStarted();
try (ClipboardReader clipboardReader = format.getReader(Files.newInputStream(file.toPath(), StandardOpenOption.READ))) {
ClipboardWorld world = new ClipboardWorld(
file,
clipboardReader.read(),
file.getName()
);
app.platform.addWorld(world);
WorldEdit.getInstance().getSessionManager().get(app.commandSender).setWorldOverride(world);
}
} else {
throw new IllegalArgumentException("Unknown file provided!");
}
}
String scriptFile = cmd.getOptionValue('s');
if (scriptFile != null) {
File scriptFileHandle = new File(scriptFile);
if (!scriptFileHandle.exists()) {
throw new IllegalArgumentException("Could not find given script file.");
}
InputStream scriptStream = Files.newInputStream(scriptFileHandle.toPath(), StandardOpenOption.READ);
InputStream newLineStream = new ByteArrayInputStream("\n".getBytes(StandardCharsets.UTF_8));
// Cleaner to do this than make an Enumeration :(
inputStream = new SequenceInputStream(new SequenceInputStream(scriptStream, newLineStream), inputStream);
}
app.run(inputStream);
} catch (Exception e) {
e.printStackTrace();
exitCode = 1;
} finally {
app.onStopped();
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.exit(exitCode);
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.cli.data;
import com.google.common.io.Resources;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sk89q.worldedit.cli.CLIWorldEdit;
import com.sk89q.worldedit.util.io.ResourceLoader;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
public class FileRegistries {
private CLIWorldEdit app;
private Gson gson = new GsonBuilder().create();
private DataFile dataFile;
public FileRegistries(CLIWorldEdit app) {
this.app = app;
}
public void loadDataFiles() {
try {
URL url = ResourceLoader.getResource(FileRegistries.class, app.getPlatform().getDataVersion() + ".json");
this.dataFile = gson.fromJson(Resources.toString(url, StandardCharsets.UTF_8), DataFile.class);
} catch (IOException e) {
throw new RuntimeException("The provided file is not compatible with this version of WorldEdit-CLI. Please update or report this.");
}
}
public DataFile getDataFile() {
return this.dataFile;
}
public static class BlockManifest {
public String defaultstate;
public Map<String, BlockProperty> properties;
}
public static class BlockProperty {
public List<String> values;
public String type;
}
public static class DataFile {
public Map<String, List<String>> itemtags;
public Map<String, List<String>> blocktags;
public Map<String, List<String>> entitytags;
public List<String> items;
public List<String> entities;
public List<String> biomes;
public Map<String, BlockManifest> blocks;
}
}

View File

@ -0,0 +1,217 @@
/*
* 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.cli.schematic;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.cli.CLIWorld;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable;
public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld {
private final File file;
private final Clipboard clipboard;
private final String name;
private boolean dirty = false;
public ClipboardWorld(File file, Clipboard clipboard, String name) {
this.file = file;
this.clipboard = clipboard;
this.name = name;
}
@Override
public String getName() {
return this.name;
}
@Override
public String getId() {
return getName().replace(" ", "_").toLowerCase(Locale.ROOT);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight)
throws WorldEditException {
dirty = true;
return clipboard.setBlock(position, block);
}
@Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
return false;
}
@Override
public int getBlockLightLevel(BlockVector3 position) {
return 0;
}
@Override
public boolean clearContainerBlockContents(BlockVector3 position) {
return false;
}
@Override
public void dropItem(Vector3 position, BaseItemStack item) {
}
@Override
public void simulateBlockMine(BlockVector3 position) {
}
@Override
public boolean regenerate(Region region, EditSession editSession) {
return false;
}
@Override
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position)
throws MaxChangedBlocksException {
return false;
}
@Override
public BlockVector3 getSpawnPosition() {
return clipboard.getOrigin();
}
@Override
public List<? extends Entity> getEntities(Region region) {
return clipboard.getEntities(region);
}
@Override
public List<? extends Entity> getEntities() {
return clipboard.getEntities();
}
@Nullable
@Override
public Entity createEntity(Location location, BaseEntity entity) {
dirty = true;
return clipboard.createEntity(location, entity);
}
@Override
public BlockState getBlock(BlockVector3 position) {
return clipboard.getBlock(position);
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
return clipboard.getFullBlock(position);
}
@Override
public BiomeType getBiome(BlockVector2 position) {
return clipboard.getBiome(position);
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
dirty = true;
return clipboard.setBiome(position, biome);
}
@Override
public Region getRegion() {
return clipboard.getRegion();
}
@Override
public BlockVector3 getDimensions() {
return clipboard.getDimensions();
}
@Override
public BlockVector3 getOrigin() {
return clipboard.getOrigin();
}
@Override
public void setOrigin(BlockVector3 origin) {
clipboard.setOrigin(origin);
dirty = true;
}
@Override
public boolean hasBiomes() {
return clipboard.hasBiomes();
}
@Override
public BlockVector3 getMaximumPoint() {
return clipboard.getMaximumPoint();
}
@Override
public BlockVector3 getMinimumPoint() {
return clipboard.getMinimumPoint();
}
@Override
public void save(boolean force) {
if (dirty || force) {
try (ClipboardWriter writer = ClipboardFormats.findByFile(file).getWriter(new FileOutputStream(file))) {
writer.write(this);
dirty = false;
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public boolean isDirty() {
return this.dirty;
}
@Override
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,33 @@
#Don't put comments; they get removed
default-max-polygon-points=-1
schematic-save-dir=schematics
super-pickaxe-many-drop-items=true
register-help=true
nav-wand-item=minecraft:compass
profile=false
trace-unflushed-sessions=false
super-pickaxe-drop-items=true
disallowed-blocks=minecraft:oak_sapling,minecraft:jungle_sapling,minecraft:dark_oak_sapling,minecraft:spruce_sapling,minecraft:birch_sapling,minecraft:acacia_sapling,minecraft:black_bed,minecraft:blue_bed,minecraft:brown_bed,minecraft:cyan_bed,minecraft:gray_bed,minecraft:green_bed,minecraft:light_blue_bed,minecraft:light_gray_bed,minecraft:lime_bed,minecraft:magenta_bed,minecraft:orange_bed,minecraft:pink_bed,minecraft:purple_bed,minecraft:red_bed,minecraft:white_bed,minecraft:yellow_bed,minecraft:powered_rail,minecraft:detector_rail,minecraft:grass,minecraft:dead_bush,minecraft:moving_piston,minecraft:piston_head,minecraft:sunflower,minecraft:rose_bush,minecraft:dandelion,minecraft:poppy,minecraft:brown_mushroom,minecraft:red_mushroom,minecraft:tnt,minecraft:torch,minecraft:fire,minecraft:redstone_wire,minecraft:wheat,minecraft:potatoes,minecraft:carrots,minecraft:melon_stem,minecraft:pumpkin_stem,minecraft:beetroots,minecraft:rail,minecraft:lever,minecraft:redstone_torch,minecraft:redstone_wall_torch,minecraft:repeater,minecraft:comparator,minecraft:stone_button,minecraft:birch_button,minecraft:acacia_button,minecraft:dark_oak_button,minecraft:jungle_button,minecraft:oak_button,minecraft:spruce_button,minecraft:cactus,minecraft:sugar_cane,minecraft:bedrock
max-super-pickaxe-size=5
max-brush-radius=10
craftscript-dir=craftscripts
no-double-slash=false
wand-item=minecraft:wooden_axe
shell-save-type=
scripting-timeout=3000
snapshots-dir=
use-inventory-creative-override=false
log-file=worldedit.log
log-format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n
max-changed-blocks=-1
nav-wand-distance=50
butcher-default-radius=-1
default-max-changed-blocks=-1
history-size=15
use-inventory=false
allow-symbolic-links=false
use-inventory-override=false
log-commands=false
butcher-max-radius=-1
max-polygon-points=20
max-radius=-1

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="com.sk89q,org.enginehub">
<Appenders>
<Console name="SysOut" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
</Console>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<OnStartupTriggeringPolicy />
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="SysOut"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>

View File

@ -21,8 +21,8 @@ package com.sk89q.worldedit;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.World;
@ -65,10 +65,10 @@ public class EditSessionFactory {
*
* @param world the world
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
* @param player the player that the {@link EditSession} is for
* @param actor the actor that the {@link EditSession} is for
* @return an instance
*/
public EditSession getEditSession(World world, int maxBlocks, Player player) {
public EditSession getEditSession(World world, int maxBlocks, Actor actor) {
// ============ READ ME ============
@ -114,10 +114,10 @@ public class EditSessionFactory {
* @param world the world
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
* @param blockBag an optional {@link BlockBag} to use, otherwise null
* @param player the player that the {@link EditSession} is for
* @param actor the actor that the {@link EditSession} is for
* @return an instance
*/
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Player player) {
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Actor actor) {
// ============ READ ME ============
@ -156,8 +156,8 @@ public class EditSessionFactory {
}
@Override
public EditSession getEditSession(World world, int maxBlocks, Player player) {
return getEditSession(world, maxBlocks, null, player);
public EditSession getEditSession(World world, int maxBlocks, Actor actor) {
return getEditSession(world, maxBlocks, null, actor);
}
@Override
@ -166,11 +166,11 @@ public class EditSessionFactory {
}
@Override
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Player player) {
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Actor actor) {
if (WorldEdit.getInstance().getConfiguration().traceUnflushedSessions) {
return new TracedEditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks, null));
return new TracedEditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, actor, maxBlocks, null));
}
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks, null));
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, actor, maxBlocks, null));
}
}

View File

@ -34,6 +34,7 @@ import com.sk89q.worldedit.command.tool.SinglePickaxe;
import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.cui.CUIEvent;
@ -100,6 +101,7 @@ public class LocalSession {
private transient BlockVector3 cuiTemporaryBlock;
private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE;
private transient List<Countable<BlockState>> lastDistribution;
private transient World worldOverride;
// Saved properties
private String lastScript;
@ -226,21 +228,21 @@ public class LocalSession {
* Performs an undo.
*
* @param newBlockBag a new block bag
* @param player the player
* @param actor the actor
* @return whether anything was undone
*/
public EditSession undo(@Nullable BlockBag newBlockBag, Player player) {
checkNotNull(player);
public EditSession undo(@Nullable BlockBag newBlockBag, Actor actor) {
checkNotNull(actor);
--historyPointer;
if (historyPointer >= 0) {
EditSession editSession = history.get(historyPointer);
try (EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory()
.getEditSession(editSession.getWorld(), -1, newBlockBag, player)) {
.getEditSession(editSession.getWorld(), -1, newBlockBag, actor)) {
newEditSession.enableStandardMode();
newEditSession.setReorderMode(reorderMode);
newEditSession.setFastMode(fastMode);
if (newEditSession.getSurvivalExtent() != null) {
newEditSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt"));
newEditSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt"));
}
editSession.undo(newEditSession);
}
@ -255,20 +257,20 @@ public class LocalSession {
* Performs a redo
*
* @param newBlockBag a new block bag
* @param player the player
* @param actor the actor
* @return whether anything was redone
*/
public EditSession redo(@Nullable BlockBag newBlockBag, Player player) {
checkNotNull(player);
public EditSession redo(@Nullable BlockBag newBlockBag, Actor actor) {
checkNotNull(actor);
if (historyPointer < history.size()) {
EditSession editSession = history.get(historyPointer);
try (EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory()
.getEditSession(editSession.getWorld(), -1, newBlockBag, player)) {
.getEditSession(editSession.getWorld(), -1, newBlockBag, actor)) {
newEditSession.enableStandardMode();
newEditSession.setReorderMode(reorderMode);
newEditSession.setFastMode(fastMode);
if (newEditSession.getSurvivalExtent() != null) {
newEditSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt"));
newEditSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt"));
}
editSession.redo(newEditSession);
}
@ -279,6 +281,19 @@ public class LocalSession {
return null;
}
public boolean hasWorldOverride() {
return this.worldOverride != null;
}
@Nullable
public World getWorldOverride() {
return this.worldOverride;
}
public void setWorldOverride(@Nullable World worldOverride) {
this.worldOverride = worldOverride;
}
/**
* Get the default region selector.
*
@ -311,6 +326,9 @@ public class LocalSession {
if (selector.getWorld() == null || !selector.getWorld().equals(world)) {
selector.setWorld(world);
selector.clear();
if (hasWorldOverride() && !world.equals(getWorldOverride())) {
setWorldOverride(null);
}
}
return selector;
}
@ -326,6 +344,9 @@ public class LocalSession {
checkNotNull(selector);
selector.setWorld(world);
this.selector = selector;
if (hasWorldOverride() && !world.equals(getWorldOverride())) {
setWorldOverride(null);
}
}
/**
@ -483,14 +504,18 @@ public class LocalSession {
* Get the position use for commands that take a center point
* (i.e. //forestgen, etc.).
*
* @param player the player
* @param actor the actor
* @return the position to use
* @throws IncompleteRegionException thrown if a region is not fully selected
*/
public BlockVector3 getPlacementPosition(Player player) throws IncompleteRegionException {
checkNotNull(player);
public BlockVector3 getPlacementPosition(Actor actor) throws IncompleteRegionException {
checkNotNull(actor);
if (!placeAtPos1) {
return player.getBlockIn().toVector().toBlockPoint();
if (actor instanceof Locatable) {
return ((Locatable) actor).getBlockLocation().toVector().toBlockPoint();
} else {
throw new IncompleteRegionException();
}
}
return selector.getPrimaryPosition();
@ -653,9 +678,9 @@ public class LocalSession {
/**
* Tell the player the WorldEdit version.
*
* @param player the player
* @param actor the actor
*/
public void tellVersion(Actor player) {
public void tellVersion(Actor actor) {
}
public boolean shouldUseServerCUI() {
@ -885,25 +910,38 @@ public class LocalSession {
/**
* Construct a new edit session.
*
* @param player the player
* @param actor the actor
* @return an edit session
*/
public EditSession createEditSession(Player player) {
checkNotNull(player);
public EditSession createEditSession(Actor actor) {
checkNotNull(actor);
BlockBag blockBag = getBlockBag(player);
World world = null;
if (hasWorldOverride()) {
world = getWorldOverride();
} else if (actor instanceof Locatable && ((Locatable) actor).getExtent() instanceof World) {
world = (World) ((Locatable) actor).getExtent();
}
// Create an edit session
EditSession editSession = WorldEdit.getInstance().getEditSessionFactory()
.getEditSession(player.isPlayer() ? player.getWorld() : null,
getBlockChangeLimit(), blockBag, player);
EditSession editSession;
if (actor.isPlayer() && actor instanceof Player) {
BlockBag blockBag = getBlockBag((Player) actor);
editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(
world,
getBlockChangeLimit(), blockBag, actor
);
} else {
editSession = WorldEdit.getInstance().getEditSessionFactory()
.getEditSession(world, getBlockChangeLimit());
}
Request.request().setEditSession(editSession);
editSession.setFastMode(fastMode);
editSession.setReorderMode(reorderMode);
editSession.setMask(mask);
if (editSession.getSurvivalExtent() != null) {
editSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt"));
editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt"));
}
return editSession;

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 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;
/**
* Raised when a world is missing but is required.
*/
public class MissingWorldException extends WorldEditException {
}

View File

@ -229,7 +229,7 @@ public final class WorldEdit {
* traversal exploits by checking the root directory and the file directory.
* On success, a {@code java.io.File} object will be returned.
*
* @param player the player
* @param actor the actor
* @param dir sub-directory to look in
* @param filename filename (user-submitted)
* @param defaultExt append an extension if missing one, null to not use
@ -237,8 +237,8 @@ public final class WorldEdit {
* @return a file
* @throws FilenameException thrown if the filename is invalid
*/
public File getSafeSaveFile(Player player, File dir, String filename, String defaultExt, String... extensions) throws FilenameException {
return getSafeFile(player, dir, filename, defaultExt, extensions, true);
public File getSafeSaveFile(Actor actor, File dir, String filename, String defaultExt, String... extensions) throws FilenameException {
return getSafeFile(actor, dir, filename, defaultExt, extensions, true);
}
/**
@ -247,7 +247,7 @@ public final class WorldEdit {
* traversal exploits by checking the root directory and the file directory.
* On success, a {@code java.io.File} object will be returned.
*
* @param player the player
* @param actor the actor
* @param dir sub-directory to look in
* @param filename filename (user-submitted)
* @param defaultExt append an extension if missing one, null to not use
@ -255,14 +255,14 @@ public final class WorldEdit {
* @return a file
* @throws FilenameException thrown if the filename is invalid
*/
public File getSafeOpenFile(Player player, File dir, String filename, String defaultExt, String... extensions) throws FilenameException {
return getSafeFile(player, dir, filename, defaultExt, extensions, false);
public File getSafeOpenFile(Actor actor, File dir, String filename, String defaultExt, String... extensions) throws FilenameException {
return getSafeFile(actor, dir, filename, defaultExt, extensions, false);
}
/**
* Get a safe path to a file.
*
* @param player the player
* @param actor the actor
* @param dir sub-directory to look in
* @param filename filename (user-submitted)
* @param defaultExt append an extension if missing one, null to not use
@ -271,16 +271,16 @@ public final class WorldEdit {
* @return a file
* @throws FilenameException thrown if the filename is invalid
*/
private File getSafeFile(@Nullable Player player, File dir, String filename, String defaultExt, String[] extensions, boolean isSave) throws FilenameException {
private File getSafeFile(@Nullable Actor actor, File dir, String filename, String defaultExt, String[] extensions, boolean isSave) throws FilenameException {
if (extensions != null && (extensions.length == 1 && extensions[0] == null)) extensions = null;
File f;
if (filename.equals("#") && player != null) {
if (filename.equals("#") && actor != null) {
if (isSave) {
f = player.openFileSaveDialog(extensions);
f = actor.openFileSaveDialog(extensions);
} else {
f = player.openFileOpenDialog(extensions);
f = actor.openFileOpenDialog(extensions);
}
if (f == null) {

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"))));
}

View File

@ -26,7 +26,7 @@ import com.sk89q.worldedit.WorldEditException;
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.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.block.BlockReplace;
@ -45,6 +45,7 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
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;
@ -67,7 +68,7 @@ public class ClipboardCommands {
desc = "Copy the selection to the clipboard"
)
@CommandPermissions("worldedit.clipboard.copy")
public void copy(Player player, LocalSession session, EditSession editSession,
public void copy(Actor actor, LocalSession session, EditSession editSession,
@Selection Region region,
@Switch(name = 'e', desc = "Also copy entities")
boolean copyEntities,
@ -76,7 +77,7 @@ public class ClipboardCommands {
@ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air", def = "")
Mask mask) throws WorldEditException {
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(session.getPlacementPosition(player));
clipboard.setOrigin(session.getPlacementPosition(actor));
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
copy.setCopyingEntities(copyEntities);
copy.setCopyingBiomes(copyBiomes);
@ -88,7 +89,7 @@ public class ClipboardCommands {
List<String> messages = Lists.newArrayList();
copy.addStatusMessages(messages);
messages.forEach(player::print);
messages.forEach(actor::print);
}
@Command(
@ -97,7 +98,7 @@ public class ClipboardCommands {
)
@CommandPermissions("worldedit.clipboard.cut")
@Logging(REGION)
public void cut(Player player, LocalSession session, EditSession editSession,
public void cut(Actor actor, LocalSession session, EditSession editSession,
@Selection Region region,
@Arg(desc = "Pattern to leave in place of the selection", def = "air")
Pattern leavePattern,
@ -109,7 +110,7 @@ public class ClipboardCommands {
Mask mask) throws WorldEditException {
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(session.getPlacementPosition(player));
clipboard.setOrigin(session.getPlacementPosition(actor));
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
copy.setSourceFunction(new BlockReplace(editSession, leavePattern));
copy.setCopyingEntities(copyEntities);
@ -123,7 +124,7 @@ public class ClipboardCommands {
List<String> messages = Lists.newArrayList();
copy.addStatusMessages(messages);
messages.forEach(player::print);
messages.forEach(actor::print);
}
@Command(
@ -132,7 +133,7 @@ public class ClipboardCommands {
)
@CommandPermissions("worldedit.clipboard.paste")
@Logging(PLACEMENT)
public void paste(Player player, LocalSession session, EditSession editSession,
public void paste(Actor actor, World world, LocalSession session, EditSession editSession,
@Switch(name = 'a', desc = "Skip air blocks")
boolean ignoreAirBlocks,
@Switch(name = 'o', desc = "Paste at the original position")
@ -151,7 +152,7 @@ public class ClipboardCommands {
Clipboard clipboard = holder.getClipboard();
Region region = clipboard.getRegion();
BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player);
BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(actor);
Operation operation = holder
.createPaste(editSession)
.to(to)
@ -166,16 +167,16 @@ public class ClipboardCommands {
BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3()));
Vector3 max = realTo.add(holder.getTransform().apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3()));
RegionSelector selector = new CuboidRegionSelector(player.getWorld(), realTo.toBlockPoint(), max.toBlockPoint());
session.setRegionSelector(player.getWorld(), selector);
RegionSelector selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint());
session.setRegionSelector(world, selector);
selector.learnChanges();
selector.explainRegionAdjust(player, session);
selector.explainRegionAdjust(actor, session);
}
player.print("The clipboard has been pasted at " + to);
actor.print("The clipboard has been pasted at " + to);
List<String> messages = Lists.newArrayList();
operation.addStatusMessages(messages);
messages.forEach(player::print);
messages.forEach(actor::print);
}
@Command(
@ -186,7 +187,7 @@ public class ClipboardCommands {
"Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n"
)
@CommandPermissions("worldedit.clipboard.rotate")
public void rotate(Player player, LocalSession session,
public void rotate(Actor actor, LocalSession session,
@Arg(desc = "Amount to rotate on the y-axis")
double yRotate,
@Arg(desc = "Amount to rotate on the x-axis", def = "0")
@ -196,7 +197,7 @@ public class ClipboardCommands {
if (Math.abs(yRotate % 90) > 0.001 ||
Math.abs(xRotate % 90) > 0.001 ||
Math.abs(zRotate % 90) > 0.001) {
player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.");
actor.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.");
}
ClipboardHolder holder = session.getClipboard();
@ -205,7 +206,7 @@ public class ClipboardCommands {
transform = transform.rotateX(-xRotate);
transform = transform.rotateZ(-zRotate);
holder.setTransform(holder.getTransform().combine(transform));
player.print("The clipboard copy has been rotated.");
actor.print("The clipboard copy has been rotated.");
}
@Command(
@ -213,14 +214,14 @@ public class ClipboardCommands {
desc = "Flip the contents of the clipboard across the origin"
)
@CommandPermissions("worldedit.clipboard.flip")
public void flip(Player player, LocalSession session,
public void flip(Actor actor, LocalSession session,
@Arg(desc = "The direction to flip, defaults to look direction.", def = Direction.AIM)
@Direction BlockVector3 direction) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
AffineTransform transform = new AffineTransform();
transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3());
holder.setTransform(holder.getTransform().combine(transform));
player.print("The clipboard copy has been flipped.");
actor.print("The clipboard copy has been flipped.");
}
@Command(
@ -228,8 +229,8 @@ public class ClipboardCommands {
desc = "Clear your clipboard"
)
@CommandPermissions("worldedit.clipboard.clear")
public void clearClipboard(Player player, LocalSession session) throws WorldEditException {
public void clearClipboard(Actor actor, LocalSession session) throws WorldEditException {
session.setClipboard(null);
player.print("Clipboard cleared.");
actor.print("Clipboard cleared.");
}
}

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.MultiDirection;
import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
@ -34,6 +35,7 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.CommandManagerService;
@ -120,7 +122,7 @@ public class ExpandCommands {
desc = "Expand the selection area"
)
@Logging(REGION)
public void expand(Player player, LocalSession session,
public void expand(Actor actor, World world, LocalSession session,
@Arg(desc = "Amount to expand the selection by, can be `vert` to expand to the whole vertical column")
int amount,
@Arg(desc = "Amount to expand the selection by in the other direction", def = "0")
@ -128,7 +130,7 @@ public class ExpandCommands {
@Arg(desc = "Direction to expand", def = Direction.AIM)
@MultiDirection
List<BlockVector3> direction) throws WorldEditException {
Region region = session.getSelection(player.getWorld());
Region region = session.getSelection(world);
int oldSize = region.getArea();
if (reverseAmount == 0) {
@ -141,12 +143,12 @@ public class ExpandCommands {
}
}
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(world).learnChanges();
int newSize = region.getArea();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
session.getRegionSelector(world).explainRegionAdjust(actor, session);
player.print("Region expanded " + (newSize - oldSize) + " block(s).");
actor.print("Region expanded " + (newSize - oldSize) + " block(s).");
}
}

View File

@ -33,6 +33,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.item.ItemType;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
@ -72,23 +73,23 @@ public class GeneralCommands {
desc = "Modify block change limit"
)
@CommandPermissions("worldedit.limit")
public void limit(Player player, LocalSession session,
public void limit(Actor actor, LocalSession session,
@Arg(desc = "The limit to set", def = "")
Integer limit) {
LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted");
boolean mayDisable = actor.hasPermission("worldedit.limit.unrestricted");
limit = limit == null ? config.defaultChangeLimit : Math.max(-1, limit);
if (!mayDisable && config.maxChangeLimit > -1) {
if (limit > config.maxChangeLimit) {
player.printError("Your maximum allowable limit is " + config.maxChangeLimit + ".");
actor.printError("Your maximum allowable limit is " + config.maxChangeLimit + ".");
return;
}
}
session.setBlockChangeLimit(limit);
player.print("Block change limit set to " + limit + "."
actor.print("Block change limit set to " + limit + "."
+ (limit == config.defaultChangeLimit ? "" : " (Use //limit to go back to the default.)"));
}
@ -97,22 +98,22 @@ public class GeneralCommands {
desc = "Modify evaluation timeout time."
)
@CommandPermissions("worldedit.timeout")
public void timeout(Player player, LocalSession session,
public void timeout(Actor actor, LocalSession session,
@Arg(desc = "The timeout time to set", def = "")
Integer limit) {
LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.timeout.unrestricted");
boolean mayDisable = actor.hasPermission("worldedit.timeout.unrestricted");
limit = limit == null ? config.calculationTimeout : Math.max(-1, limit);
if (!mayDisable && config.maxCalculationTimeout > -1) {
if (limit > config.maxCalculationTimeout) {
player.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms.");
actor.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms.");
return;
}
}
session.setTimeout(limit);
player.print("Timeout time set to " + limit + " ms."
actor.print("Timeout time set to " + limit + " ms."
+ (limit == config.calculationTimeout ? "" : " (Use //timeout to go back to the default.)"));
}
@ -121,21 +122,21 @@ public class GeneralCommands {
desc = "Toggle fast mode"
)
@CommandPermissions("worldedit.fast")
public void fast(Player player, LocalSession session,
public void fast(Actor actor, LocalSession session,
@Arg(desc = "The new fast mode state", def = "")
Boolean fastMode) {
boolean hasFastMode = session.hasFastMode();
if (fastMode != null && fastMode == hasFastMode) {
player.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + ".");
actor.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + ".");
return;
}
if (hasFastMode) {
session.setFastMode(false);
player.print("Fast mode disabled.");
actor.print("Fast mode disabled.");
} else {
session.setFastMode(true);
player.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.");
actor.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.");
}
}
@ -144,14 +145,14 @@ public class GeneralCommands {
desc = "Sets the reorder mode of WorldEdit"
)
@CommandPermissions("worldedit.reorder")
public void reorderMode(Player player, LocalSession session,
public void reorderMode(Actor actor, LocalSession session,
@Arg(desc = "The reorder mode", def = "")
EditSession.ReorderMode reorderMode) {
if (reorderMode == null) {
player.print("The reorder mode is " + session.getReorderMode().getDisplayName());
actor.print("The reorder mode is " + session.getReorderMode().getDisplayName());
} else {
session.setReorderMode(reorderMode);
player.print("The reorder mode is now " + session.getReorderMode().getDisplayName());
actor.print("The reorder mode is now " + session.getReorderMode().getDisplayName());
}
}
@ -182,21 +183,36 @@ public class GeneralCommands {
}
}
@Command(
name = "/world",
desc = "Sets the world override"
)
@CommandPermissions("worldedit.world")
public void world(Actor actor, LocalSession session,
@Arg(desc = "The world override", def = "") World world) {
session.setWorldOverride(world);
if (world == null) {
actor.print("Removed world override.");
} else {
actor.print("Set the world override to " + world.getId() + ". (Use //world to go back to default)");
}
}
@Command(
name = "gmask",
aliases = {"/gmask"},
desc = "Set the global mask"
)
@CommandPermissions("worldedit.global-mask")
public void gmask(Player player, LocalSession session,
public void gmask(Actor actor, LocalSession session,
@Arg(desc = "The mask to set", def = "")
Mask mask) {
if (mask == null) {
session.setMask(null);
player.print("Global mask disabled.");
actor.print("Global mask disabled.");
} else {
session.setMask(mask);
player.print("Global mask set.");
actor.print("Global mask set.");
}
}

View File

@ -27,6 +27,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.pattern.Pattern;
import com.sk89q.worldedit.internal.annotation.Radii;
import com.sk89q.worldedit.internal.annotation.Selection;
@ -73,7 +74,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT)
public int hcyl(Player player, LocalSession session, EditSession editSession,
public int hcyl(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
@Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W")
@ -81,7 +82,7 @@ public class GenerationCommands {
List<Double> radii,
@Arg(desc = "The height of the cylinder", def = "1")
int height) throws WorldEditException {
return cyl(player, session, editSession, pattern, radii, height, true);
return cyl(actor, session, editSession, pattern, radii, height, true);
}
@Command(
@ -90,7 +91,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT)
public int cyl(Player player, LocalSession session, EditSession editSession,
public int cyl(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
@Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W")
@ -112,7 +113,7 @@ public class GenerationCommands {
break;
default:
player.printError("You must either specify 1 or 2 radius values.");
actor.printError("You must either specify 1 or 2 radius values.");
return 0;
}
@ -120,9 +121,9 @@ public class GenerationCommands {
worldEdit.checkMaxRadius(radiusZ);
worldEdit.checkMaxRadius(height);
BlockVector3 pos = session.getPlacementPosition(player);
BlockVector3 pos = session.getPlacementPosition(actor);
int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow);
player.print(affected + " block(s) have been created.");
actor.print(affected + " block(s) have been created.");
return affected;
}
@ -132,7 +133,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.sphere")
@Logging(PLACEMENT)
public int hsphere(Player player, LocalSession session, EditSession editSession,
public int hsphere(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
@Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W")
@ -140,7 +141,7 @@ public class GenerationCommands {
List<Double> radii,
@Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position")
boolean raised) throws WorldEditException {
return sphere(player, session, editSession, pattern, radii, raised, true);
return sphere(actor, session, editSession, pattern, radii, raised, true);
}
@Command(
@ -149,7 +150,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.sphere")
@Logging(PLACEMENT)
public int sphere(Player player, LocalSession session, EditSession editSession,
public int sphere(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
@Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W")
@ -172,7 +173,7 @@ public class GenerationCommands {
break;
default:
player.printError("You must either specify 1 or 3 radius values.");
actor.printError("You must either specify 1 or 3 radius values.");
return 0;
}
@ -180,14 +181,16 @@ public class GenerationCommands {
worldEdit.checkMaxRadius(radiusY);
worldEdit.checkMaxRadius(radiusZ);
BlockVector3 pos = session.getPlacementPosition(player);
BlockVector3 pos = session.getPlacementPosition(actor);
if (raised) {
pos = pos.add(0, (int) radiusY, 0);
}
int affected = editSession.makeSphere(pos, pattern, radiusX, radiusY, radiusZ, !hollow);
player.findFreePosition();
player.print(affected + " block(s) have been created.");
if (actor instanceof Player) {
((Player) actor).findFreePosition();
}
actor.print(affected + " block(s) have been created.");
return affected;
}
@ -197,7 +200,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.forest")
@Logging(POSITION)
public int forestGen(Player player, LocalSession session, EditSession editSession,
public int forestGen(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The size of the forest, in blocks", def = "10")
int size,
@Arg(desc = "The type of forest", def = "tree")
@ -207,8 +210,8 @@ public class GenerationCommands {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
worldEdit.checkMaxRadius(size);
density /= 100;
int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
player.print(affected + " trees created.");
int affected = editSession.makeForest(session.getPlacementPosition(actor), size, density, type);
actor.print(affected + " trees created.");
return affected;
}
@ -218,12 +221,12 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.pumpkins")
@Logging(POSITION)
public int pumpkins(Player player, LocalSession session, EditSession editSession,
public int pumpkins(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The size of the patch", def = "10")
int size) throws WorldEditException {
worldEdit.checkMaxRadius(size);
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), size);
player.print(affected + " pumpkin patches created.");
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size);
actor.print(affected + " pumpkin patches created.");
return affected;
}
@ -233,12 +236,12 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.pyramid")
@Logging(PLACEMENT)
public int hollowPyramid(Player player, LocalSession session, EditSession editSession,
public int hollowPyramid(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern,
@Arg(desc = "The size of the pyramid")
int size) throws WorldEditException {
return pyramid(player, session, editSession, pattern, size, true);
return pyramid(actor, session, editSession, pattern, size, true);
}
@Command(
@ -247,7 +250,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.pyramid")
@Logging(PLACEMENT)
public int pyramid(Player player, LocalSession session, EditSession editSession,
public int pyramid(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern,
@Arg(desc = "The size of the pyramid")
@ -255,10 +258,12 @@ public class GenerationCommands {
@Switch(name = 'h', desc = "Make a hollow pyramid")
boolean hollow) throws WorldEditException {
worldEdit.checkMaxRadius(size);
BlockVector3 pos = session.getPlacementPosition(player);
BlockVector3 pos = session.getPlacementPosition(actor);
int affected = editSession.makePyramid(pos, pattern, size, !hollow);
player.findFreePosition();
player.print(affected + " block(s) have been created.");
if (actor instanceof Player) {
((Player) actor).findFreePosition();
}
actor.print(affected + " block(s) have been created.");
return affected;
}
@ -270,7 +275,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.shape")
@Logging(ALL)
public int generate(Player player, LocalSession session, EditSession editSession,
public int generate(Actor actor, LocalSession session, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern,
@ -292,7 +297,7 @@ public class GenerationCommands {
zero = Vector3.ZERO;
unit = Vector3.ONE;
} else if (offset) {
zero = session.getPlacementPosition(player).toVector3();
zero = session.getPlacementPosition(actor).toVector3();
unit = Vector3.ONE;
} else if (offsetCenter) {
final Vector3 min = region.getMinimumPoint().toVector3();
@ -314,11 +319,13 @@ public class GenerationCommands {
try {
final int affected = editSession.makeShape(region, zero, unit, pattern, String.join(" ", expression), hollow, session.getTimeout());
player.findFreePosition();
player.print(affected + " block(s) have been created.");
if (actor instanceof Player) {
((Player) actor).findFreePosition();
}
actor.print(affected + " block(s) have been created.");
return affected;
} catch (ExpressionException e) {
player.printError(e.getMessage());
actor.printError(e.getMessage());
return 0;
}
}
@ -331,7 +338,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.shape.biome")
@Logging(ALL)
public int generateBiome(Player player, LocalSession session, EditSession editSession,
public int generateBiome(Actor actor, LocalSession session, EditSession editSession,
@Selection Region region,
@Arg(desc = "The biome type to set")
BiomeType target,
@ -352,7 +359,7 @@ public class GenerationCommands {
zero = Vector3.ZERO;
unit = Vector3.ONE;
} else if (offset) {
zero = session.getPlacementPosition(player).toVector3();
zero = session.getPlacementPosition(actor).toVector3();
unit = Vector3.ONE;
} else if (offsetCenter) {
final Vector3 min = region.getMinimumPoint().toVector3();
@ -374,11 +381,10 @@ public class GenerationCommands {
try {
final int affected = editSession.makeBiomeShape(region, zero, unit, target, String.join(" ", expression), hollow, session.getTimeout());
player.findFreePosition();
player.print("" + affected + " columns affected.");
actor.print("" + affected + " columns affected.");
return affected;
} catch (ExpressionException e) {
player.printError(e.getMessage());
actor.printError(e.getMessage());
return 0;
}
}

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
@ -132,9 +133,9 @@ public class HistoryCommands {
desc = "Clear your history"
)
@CommandPermissions("worldedit.history.clear")
public void clearHistory(Player player, LocalSession session) {
public void clearHistory(Actor actor, LocalSession session) {
session.clearHistory();
player.print("History cleared.");
actor.print("History cleared.");
}
}

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;
}

View File

@ -99,7 +99,7 @@ public class SchematicCommands {
desc = "Load a schematic into your clipboard"
)
@CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"})
public void load(Player player, LocalSession session,
public void load(Actor actor, LocalSession session,
@Arg(desc = "File name.")
String filename,
@Arg(desc = "Format name.", def = "sponge")
@ -107,12 +107,12 @@ public class SchematicCommands {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
File f = worldEdit.getSafeOpenFile(player, dir, filename,
File f = worldEdit.getSafeOpenFile(actor, dir, filename,
BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension(),
ClipboardFormats.getFileExtensionArray());
if (!f.exists()) {
player.printError("Schematic " + filename + " does not exist!");
actor.printError("Schematic " + filename + " does not exist!");
return;
}
@ -121,12 +121,12 @@ public class SchematicCommands {
format = ClipboardFormats.findByAlias(formatName);
}
if (format == null) {
player.printError("Unknown schematic format: " + formatName);
actor.printError("Unknown schematic format: " + formatName);
return;
}
SchematicLoadTask task = new SchematicLoadTask(player, f, format);
AsyncCommandBuilder.wrap(task, player)
SchematicLoadTask task = new SchematicLoadTask(actor, f, format);
AsyncCommandBuilder.wrap(task, actor)
.registerWithSupervisor(worldEdit.getSupervisor(), "Loading schematic " + filename)
.sendMessageAfterDelay("(Please wait... loading schematic.)")
.onSuccess(TextComponent.of(filename, TextColor.GOLD)
@ -142,7 +142,7 @@ public class SchematicCommands {
desc = "Save a schematic into your clipboard"
)
@CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save"})
public void save(Player player, LocalSession session,
public void save(Actor actor, LocalSession session,
@Arg(desc = "File name.")
String filename,
@Arg(desc = "Format name.", def = "sponge")
@ -156,19 +156,19 @@ public class SchematicCommands {
ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
if (format == null) {
player.printError("Unknown schematic format: " + formatName);
actor.printError("Unknown schematic format: " + formatName);
return;
}
File f = worldEdit.getSafeSaveFile(player, dir, filename, format.getPrimaryFileExtension());
File f = worldEdit.getSafeSaveFile(actor, dir, filename, format.getPrimaryFileExtension());
boolean overwrite = f.exists();
if (overwrite) {
if (!player.hasPermission("worldedit.schematic.delete")) {
if (!actor.hasPermission("worldedit.schematic.delete")) {
throw new StopExecutionException(TextComponent.of("That schematic already exists!"));
}
if (!allowOverwrite) {
player.printError("That schematic already exists. Use the -f flag to overwrite it.");
actor.printError("That schematic already exists. Use the -f flag to overwrite it.");
return;
}
}
@ -184,8 +184,8 @@ public class SchematicCommands {
ClipboardHolder holder = session.getClipboard();
SchematicSaveTask task = new SchematicSaveTask(player, f, format, holder, overwrite);
AsyncCommandBuilder.wrap(task, player)
SchematicSaveTask task = new SchematicSaveTask(actor, f, format, holder, overwrite);
AsyncCommandBuilder.wrap(task, actor)
.registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename)
.sendMessageAfterDelay("(Please wait... saving schematic.)")
.onSuccess(filename + " saved" + (overwrite ? " (overwriting previous file)." : "."), null)
@ -278,12 +278,12 @@ public class SchematicCommands {
}
private static class SchematicLoadTask implements Callable<ClipboardHolder> {
private final Player player;
private final Actor actor;
private final File file;
private final ClipboardFormat format;
SchematicLoadTask(Player player, File file, ClipboardFormat format) {
this.player = player;
SchematicLoadTask(Actor actor, File file, ClipboardFormat format) {
this.actor = actor;
this.file = file;
this.format = format;
}
@ -296,21 +296,21 @@ public class SchematicCommands {
ClipboardReader reader = closer.register(format.getReader(bis));
Clipboard clipboard = reader.read();
log.info(player.getName() + " loaded " + file.getCanonicalPath());
log.info(actor.getName() + " loaded " + file.getCanonicalPath());
return new ClipboardHolder(clipboard);
}
}
}
private static class SchematicSaveTask implements Callable<Void> {
private final Player player;
private final Actor actor;
private final File file;
private final ClipboardFormat format;
private final ClipboardHolder holder;
private final boolean overwrite;
SchematicSaveTask(Player player, File file, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) {
this.player = player;
SchematicSaveTask(Actor actor, File file, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) {
this.actor = actor;
this.file = file;
this.format = format;
this.holder = holder;
@ -339,7 +339,7 @@ public class SchematicCommands {
ClipboardWriter writer = closer.register(format.getWriter(bos));
writer.write(target);
log.info(player.getName() + " saved " + file.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : ""));
log.info(actor.getName() + " saved " + file.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : ""));
}
return null;
}

View File

@ -33,6 +33,8 @@ 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.extension.platform.Locatable;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.block.BlockDistributionCounter;
@ -104,23 +106,26 @@ public class SelectionCommands {
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.pos")
public void pos1(Player player, LocalSession session,
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(player.getWorld(), coordinates.toVector3());
pos = new Location(world, coordinates.toVector3());
} else if (actor instanceof Locatable) {
pos = ((Locatable) actor).getBlockLocation();
} else {
pos = player.getBlockIn();
}
if (!session.getRegionSelector(player.getWorld()).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(player))) {
player.printError("Position already set.");
actor.printError("You must provide coordinates as console.");
return;
}
session.getRegionSelector(player.getWorld())
.explainPrimarySelection(player, session, pos.toVector().toBlockPoint());
if (!session.getRegionSelector(world).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) {
actor.printError("Position already set.");
return;
}
session.getRegionSelector(world)
.explainPrimarySelection(actor, session, pos.toVector().toBlockPoint());
}
@Command(
@ -129,23 +134,26 @@ public class SelectionCommands {
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.pos")
public void pos2(Player player, LocalSession session,
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(player.getWorld(), coordinates.toVector3());
pos = new Location(world, coordinates.toVector3());
} else if (actor instanceof Locatable) {
pos = ((Locatable) actor).getBlockLocation();
} else {
pos = player.getBlockIn();
}
if (!session.getRegionSelector(player.getWorld()).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(player))) {
player.printError("Position already set.");
actor.printError("You must provide coordinates as console.");
return;
}
session.getRegionSelector(player.getWorld())
.explainSecondarySelection(player, session, pos.toVector().toBlockPoint());
if (!session.getRegionSelector(world).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) {
actor.printError("Position already set.");
return;
}
session.getRegionSelector(world)
.explainSecondarySelection(actor, session, pos.toVector().toBlockPoint());
}
@Command(
@ -229,7 +237,7 @@ public class SelectionCommands {
: ChunkStore.toChunk(coordinates.toBlockVector3());
} else {
// use player loc
min2D = ChunkStore.toChunk(player.getBlockIn().toVector().toBlockPoint());
min2D = ChunkStore.toChunk(player.getBlockLocation().toVector().toBlockPoint());
}
min = BlockVector3.at(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16);
@ -302,7 +310,7 @@ public class SelectionCommands {
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.contract")
public void contract(Player player, LocalSession session,
public void contract(Actor actor, World world, LocalSession session,
@Arg(desc = "Amount to contract the selection by")
int amount,
@Arg(desc = "Amount to contract the selection by in the other direction", def = "0")
@ -311,7 +319,7 @@ public class SelectionCommands {
@MultiDirection
List<BlockVector3> direction) throws WorldEditException {
try {
Region region = session.getSelection(player.getWorld());
Region region = session.getSelection(world);
int oldSize = region.getArea();
if (reverseAmount == 0) {
for (BlockVector3 dir : direction) {
@ -322,15 +330,14 @@ public class SelectionCommands {
region.contract(dir.multiply(amount), dir.multiply(-reverseAmount));
}
}
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(world).learnChanges();
int newSize = region.getArea();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
session.getRegionSelector(world).explainRegionAdjust(actor, session);
player.print("Region contracted " + (oldSize - newSize) + " blocks.");
actor.print("Region contracted " + (oldSize - newSize) + " blocks.");
} catch (RegionOperationException e) {
player.printError(e.getMessage());
actor.printError(e.getMessage());
}
}
@ -340,26 +347,26 @@ public class SelectionCommands {
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.shift")
public void shift(Player player, LocalSession session,
public void shift(Actor actor, World world, LocalSession session,
@Arg(desc = "Amount to shift the selection by")
int amount,
@Arg(desc = "Direction to contract", def = Direction.AIM)
@MultiDirection
List<BlockVector3> direction) throws WorldEditException {
try {
Region region = session.getSelection(player.getWorld());
Region region = session.getSelection(world);
for (BlockVector3 dir : direction) {
region.shift(dir.multiply(amount));
}
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(world).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
session.getRegionSelector(world).explainRegionAdjust(actor, session);
player.print("Region shifted.");
actor.print("Region shifted.");
} catch (RegionOperationException e) {
player.printError(e.getMessage());
actor.printError(e.getMessage());
}
}
@ -369,18 +376,18 @@ public class SelectionCommands {
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.outset")
public void outset(Player player, LocalSession session,
public void outset(Actor actor, World world, LocalSession session,
@Arg(desc = "Amount to expand the selection by in all directions")
int amount,
@Switch(name = 'h', desc = "Only expand horizontally")
boolean onlyHorizontal,
@Switch(name = 'v', desc = "Only expand vertically")
boolean onlyVertical) throws WorldEditException {
Region region = session.getSelection(player.getWorld());
Region region = session.getSelection(world);
region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region outset.");
session.getRegionSelector(world).learnChanges();
session.getRegionSelector(world).explainRegionAdjust(actor, session);
actor.print("Region outset.");
}
@Command(
@ -389,18 +396,18 @@ public class SelectionCommands {
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.inset")
public void inset(Player player, LocalSession session,
public void inset(Actor actor, World world, LocalSession session,
@Arg(desc = "Amount to contract the selection by in all directions")
int amount,
@Switch(name = 'h', desc = "Only contract horizontally")
boolean onlyHorizontal,
@Switch(name = 'v', desc = "Only contract vertically")
boolean onlyVertical) throws WorldEditException {
Region region = session.getSelection(player.getWorld());
Region region = session.getSelection(world);
region.contract(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region inset.");
session.getRegionSelector(world).learnChanges();
session.getRegionSelector(world).explainRegionAdjust(actor, session);
actor.print("Region inset.");
}
private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, boolean onlyVertical) {
@ -519,16 +526,15 @@ public class SelectionCommands {
aliases = { ";", "/desel", "/deselect" },
desc = "Choose a region selector"
)
public void select(Player player, LocalSession session,
public void select(Actor actor, World world, LocalSession session,
@Arg(desc = "Selector to switch to", def = "")
SelectorChoice selector,
@Switch(name = 'd', desc = "Set default selector")
boolean setDefaultSelector) throws WorldEditException {
final World world = player.getWorld();
if (selector == null) {
session.getRegionSelector(world).clear();
session.dispatchCUISelection(player);
player.print("Selection cleared.");
session.dispatchCUISelection(actor);
actor.print("Selection cleared.");
return;
}
@ -538,38 +544,38 @@ public class SelectionCommands {
switch (selector) {
case CUBOID:
newSelector = new CuboidRegionSelector(oldSelector);
player.print("Cuboid: left click for point 1, right click for point 2");
actor.print("Cuboid: left click for point 1, right click for point 2");
break;
case EXTEND:
newSelector = new ExtendingCuboidRegionSelector(oldSelector);
player.print("Cuboid: left click for a starting point, right click to extend");
actor.print("Cuboid: left click for a starting point, right click to extend");
break;
case POLY: {
newSelector = new Polygonal2DRegionSelector(oldSelector);
player.print("2D polygon selector: Left/right click to add a point.");
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit();
limit.ifPresent(integer -> player.print(integer + " points maximum."));
actor.print("2D polygon selector: Left/right click to add a point.");
Optional<Integer> limit = ActorSelectorLimits.forActor(actor).getPolygonVertexLimit();
limit.ifPresent(integer -> actor.print(integer + " points maximum."));
break;
}
case ELLIPSOID:
newSelector = new EllipsoidRegionSelector(oldSelector);
player.print("Ellipsoid selector: left click=center, right click to extend");
actor.print("Ellipsoid selector: left click=center, right click to extend");
break;
case SPHERE:
newSelector = new SphereRegionSelector(oldSelector);
player.print("Sphere selector: left click=center, right click to set radius");
actor.print("Sphere selector: left click=center, right click to set radius");
break;
case CYL:
newSelector = new CylinderRegionSelector(oldSelector);
player.print("Cylindrical selector: Left click=center, right click to extend.");
actor.print("Cylindrical selector: Left click=center, right click to extend.");
break;
case CONVEX:
case HULL:
case POLYHEDRON: {
newSelector = new ConvexPolyhedralRegionSelector(oldSelector);
player.print("Convex polyhedral selector: Left click=First vertex, right click to add more.");
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
limit.ifPresent(integer -> player.print(integer + " points maximum."));
actor.print("Convex polyhedral selector: Left click=First vertex, right click to add more.");
Optional<Integer> limit = ActorSelectorLimits.forActor(actor).getPolyhedronVertexLimit();
limit.ifPresent(integer -> actor.print(integer + " points maximum."));
break;
}
case LIST:
@ -587,7 +593,7 @@ public class SelectionCommands {
box.appendCommand("cyl", "Select a cylinder", "//sel cyl");
box.appendCommand("convex", "Select a convex polyhedral", "//sel convex");
player.print(box.create(1));
actor.print(box.create(1));
return;
}
@ -602,14 +608,14 @@ public class SelectionCommands {
if (found != null) {
session.setDefaultRegionSelector(found);
player.print("Your default region selector is now " + found.name() + ".");
actor.print("Your default region selector is now " + found.name() + ".");
} else {
throw new RuntimeException("Something unexpected happened. Please report this.");
}
}
session.setRegionSelector(world, newSelector);
session.dispatchCUISelection(player);
session.dispatchCUISelection(actor);
}
private static class BlockDistributionResult extends PaginationBox {

View File

@ -28,12 +28,14 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
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.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import com.sk89q.worldedit.world.storage.MissingWorldException;
@ -67,24 +69,24 @@ public class SnapshotCommands {
desc = "List snapshots"
)
@CommandPermissions("worldedit.snapshots.list")
public void list(Player player,
public void list(Actor actor, World world,
@ArgFlag(name = 'p', desc = "Page of results to return", def = "1")
int page) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) {
player.printError("Snapshot/backup restore is not configured.");
actor.printError("Snapshot/backup restore is not configured.");
return;
}
try {
List<Snapshot> snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName());
List<Snapshot> snapshots = config.snapshotRepo.getSnapshots(true, world.getName());
if (!snapshots.isEmpty()) {
player.print(new SnapshotListBox(player.getWorld().getName(), snapshots).create(page));
actor.print(new SnapshotListBox(world.getName(), snapshots).create(page));
} else {
player.printError("No snapshots are available. See console for details.");
actor.printError("No snapshots are available. See console for details.");
// Okay, let's toss some debugging information!
File dir = config.snapshotRepo.getDirectory();
@ -99,7 +101,7 @@ public class SnapshotCommands {
}
}
} catch (MissingWorldException ex) {
player.printError("No snapshots were found for this world.");
actor.printError("No snapshots were found for this world.");
}
}
@ -108,37 +110,37 @@ public class SnapshotCommands {
desc = "Choose a snapshot to use"
)
@CommandPermissions("worldedit.snapshots.restore")
public void use(Player player, LocalSession session,
public void use(Actor actor, World world, LocalSession session,
@Arg(desc = "Snapeshot to use")
String name) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) {
player.printError("Snapshot/backup restore is not configured.");
actor.printError("Snapshot/backup restore is not configured.");
return;
}
// Want the latest snapshot?
if (name.equalsIgnoreCase("latest")) {
try {
Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName());
Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName());
if (snapshot != null) {
session.setSnapshot(null);
player.print("Now using newest snapshot.");
actor.print("Now using newest snapshot.");
} else {
player.printError("No snapshots were found.");
actor.printError("No snapshots were found.");
}
} catch (MissingWorldException ex) {
player.printError("No snapshots were found for this world.");
actor.printError("No snapshots were found for this world.");
}
} else {
try {
session.setSnapshot(config.snapshotRepo.getSnapshot(name));
player.print("Snapshot set to: " + name);
actor.print("Snapshot set to: " + name);
} catch (InvalidSnapshotException e) {
player.printError("That snapshot does not exist or is not available.");
actor.printError("That snapshot does not exist or is not available.");
}
}
}
@ -148,36 +150,36 @@ public class SnapshotCommands {
desc = "Choose the snapshot based on the list id"
)
@CommandPermissions("worldedit.snapshots.restore")
public void sel(Player player, LocalSession session,
public void sel(Actor actor, World world, LocalSession session,
@Arg(desc = "The list ID to select")
int index) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) {
player.printError("Snapshot/backup restore is not configured.");
actor.printError("Snapshot/backup restore is not configured.");
return;
}
if (index < 1) {
player.printError("Invalid index, must be equal or higher then 1.");
actor.printError("Invalid index, must be equal or higher then 1.");
return;
}
try {
List<Snapshot> snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName());
List<Snapshot> snapshots = config.snapshotRepo.getSnapshots(true, world.getName());
if (snapshots.size() < index) {
player.printError("Invalid index, must be between 1 and " + snapshots.size() + ".");
actor.printError("Invalid index, must be between 1 and " + snapshots.size() + ".");
return;
}
Snapshot snapshot = snapshots.get(index - 1);
if (snapshot == null) {
player.printError("That snapshot does not exist or is not available.");
actor.printError("That snapshot does not exist or is not available.");
return;
}
session.setSnapshot(snapshot);
player.print("Snapshot set to: " + snapshot.getName());
actor.print("Snapshot set to: " + snapshot.getName());
} catch (MissingWorldException e) {
player.printError("No snapshots were found for this world.");
actor.printError("No snapshots were found for this world.");
}
}
@ -186,29 +188,29 @@ public class SnapshotCommands {
desc = "Choose the nearest snapshot before a date"
)
@CommandPermissions("worldedit.snapshots.restore")
public void before(Player player, LocalSession session,
public void before(Actor actor, World world, LocalSession session,
@Arg(desc = "The soonest date that may be used")
ZonedDateTime date) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) {
player.printError("Snapshot/backup restore is not configured.");
actor.printError("Snapshot/backup restore is not configured.");
return;
}
try {
Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName());
Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, world.getName());
if (snapshot == null) {
player.printError("Couldn't find a snapshot before "
actor.printError("Couldn't find a snapshot before "
+ dateFormat.withZone(session.getTimeZone()).format(date) + ".");
} else {
session.setSnapshot(snapshot);
player.print("Snapshot set to: " + snapshot.getName());
actor.print("Snapshot set to: " + snapshot.getName());
}
} catch (MissingWorldException ex) {
player.printError("No snapshots were found for this world.");
actor.printError("No snapshots were found for this world.");
}
}
@ -217,28 +219,28 @@ public class SnapshotCommands {
desc = "Choose the nearest snapshot after a date"
)
@CommandPermissions("worldedit.snapshots.restore")
public void after(Player player, LocalSession session,
public void after(Actor actor, World world, LocalSession session,
@Arg(desc = "The soonest date that may be used")
ZonedDateTime date) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) {
player.printError("Snapshot/backup restore is not configured.");
actor.printError("Snapshot/backup restore is not configured.");
return;
}
try {
Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName());
Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, world.getName());
if (snapshot == null) {
player.printError("Couldn't find a snapshot after "
actor.printError("Couldn't find a snapshot after "
+ dateFormat.withZone(session.getTimeZone()).format(date) + ".");
} else {
session.setSnapshot(snapshot);
player.print("Snapshot set to: " + snapshot.getName());
actor.print("Snapshot set to: " + snapshot.getName());
}
} catch (MissingWorldException ex) {
player.printError("No snapshots were found for this world.");
actor.printError("No snapshots were found for this world.");
}
}

View File

@ -27,9 +27,10 @@ import com.sk89q.worldedit.WorldEditException;
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.regions.Region;
import com.sk89q.worldedit.world.DataException;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import com.sk89q.worldedit.world.snapshot.SnapshotRestore;
@ -60,25 +61,25 @@ public class SnapshotUtilCommands {
)
@Logging(REGION)
@CommandPermissions("worldedit.snapshots.restore")
public void restore(Player player, LocalSession session, EditSession editSession,
public void restore(Actor actor, World world, LocalSession session, EditSession editSession,
@Arg(name = "snapshot", desc = "The snapshot to restore", def = "")
String snapshotName) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) {
player.printError("Snapshot/backup restore is not configured.");
actor.printError("Snapshot/backup restore is not configured.");
return;
}
Region region = session.getSelection(player.getWorld());
Region region = session.getSelection(world);
Snapshot snapshot;
if (snapshotName != null) {
try {
snapshot = config.snapshotRepo.getSnapshot(snapshotName);
} catch (InvalidSnapshotException e) {
player.printError("That snapshot does not exist or is not available.");
actor.printError("That snapshot does not exist or is not available.");
return;
}
} else {
@ -88,10 +89,10 @@ public class SnapshotUtilCommands {
// No snapshot set?
if (snapshot == null) {
try {
snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName());
snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName());
if (snapshot == null) {
player.printError("No snapshots were found. See console for details.");
actor.printError("No snapshots were found. See console for details.");
// Okay, let's toss some debugging information!
File dir = config.snapshotRepo.getDirectory();
@ -108,7 +109,7 @@ public class SnapshotUtilCommands {
return;
}
} catch (MissingWorldException ex) {
player.printError("No snapshots were found for this world.");
actor.printError("No snapshots were found for this world.");
return;
}
}
@ -118,9 +119,9 @@ public class SnapshotUtilCommands {
// Load chunk store
try {
chunkStore = snapshot.getChunkStore();
player.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring...");
actor.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring...");
} catch (DataException | IOException e) {
player.printError("Failed to load snapshot: " + e.getMessage());
actor.printError("Failed to load snapshot: " + e.getMessage());
return;
}
@ -134,15 +135,15 @@ public class SnapshotUtilCommands {
if (restore.hadTotalFailure()) {
String error = restore.getLastErrorMessage();
if (!restore.getMissingChunks().isEmpty()) {
player.printError("Chunks were not present in snapshot.");
actor.printError("Chunks were not present in snapshot.");
} else if (error != null) {
player.printError("Errors prevented any blocks from being restored.");
player.printError("Last error: " + error);
actor.printError("Errors prevented any blocks from being restored.");
actor.printError("Last error: " + error);
} else {
player.printError("No chunks could be loaded. (Bad archive?)");
actor.printError("No chunks could be loaded. (Bad archive?)");
}
} else {
player.print(String.format("Restored; %d "
actor.print(String.format("Restored; %d "
+ "missing chunks and %d other errors.",
restore.getMissingChunks().size(),
restore.getErrorChunks().size()));

View File

@ -36,10 +36,7 @@ import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.PrintCommandHelp;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
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;
import com.sk89q.worldedit.function.EntityFunction;
import com.sk89q.worldedit.function.mask.BlockTypeMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
@ -49,7 +46,6 @@ 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;
@ -90,7 +86,7 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.fill")
@Logging(PLACEMENT)
public int fill(Player player, LocalSession session, EditSession editSession,
public int fill(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with")
Pattern pattern,
@Arg(desc = "The radius to fill in")
@ -101,9 +97,9 @@ public class UtilityCommands {
we.checkMaxRadius(radius);
depth = Math.max(1, depth);
BlockVector3 pos = session.getPlacementPosition(player);
BlockVector3 pos = session.getPlacementPosition(actor);
int affected = editSession.fillXZ(pos, pattern, radius, depth, false);
player.print(affected + " block(s) have been created.");
actor.print(affected + " block(s) have been created.");
return affected;
}
@ -113,7 +109,7 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.fill.recursive")
@Logging(PLACEMENT)
public int fillr(Player player, LocalSession session, EditSession editSession,
public int fillr(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with")
Pattern pattern,
@Arg(desc = "The radius to fill in")
@ -125,9 +121,9 @@ public class UtilityCommands {
depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth);
we.checkMaxRadius(radius);
BlockVector3 pos = session.getPlacementPosition(player);
BlockVector3 pos = session.getPlacementPosition(actor);
int affected = editSession.fillXZ(pos, pattern, radius, depth, true);
player.print(affected + " block(s) have been created.");
actor.print(affected + " block(s) have been created.");
return affected;
}
@ -137,7 +133,7 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.drain")
@Logging(PLACEMENT)
public int drain(Player player, LocalSession session, EditSession editSession,
public int drain(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The radius to drain")
double radius,
@Switch(name = 'w', desc = "Also un-waterlog blocks")
@ -145,8 +141,8 @@ public class UtilityCommands {
radius = Math.max(0, radius);
we.checkMaxRadius(radius);
int affected = editSession.drainArea(
session.getPlacementPosition(player), radius, waterlogged);
player.print(affected + " block(s) have been changed.");
session.getPlacementPosition(actor), radius, waterlogged);
actor.print(affected + " block(s) have been changed.");
return affected;
}
@ -157,13 +153,13 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.fixlava")
@Logging(PLACEMENT)
public int fixLava(Player player, LocalSession session, EditSession editSession,
public int fixLava(Actor actor, 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.");
int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA);
actor.print(affected + " block(s) have been changed.");
return affected;
}
@ -174,13 +170,13 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.fixwater")
@Logging(PLACEMENT)
public int fixWater(Player player, LocalSession session, EditSession editSession,
public int fixWater(Actor actor, 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.");
int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER);
actor.print(affected + " block(s) have been changed.");
return affected;
}
@ -191,18 +187,17 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.removeabove")
@Logging(PLACEMENT)
public int removeAbove(Player player, LocalSession session, EditSession editSession,
public int removeAbove(Actor actor, World world, 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();
height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1);
int affected = editSession.removeAbove(session.getPlacementPosition(player), size, height);
player.print(affected + " block(s) have been removed.");
int affected = editSession.removeAbove(session.getPlacementPosition(actor), size, height);
actor.print(affected + " block(s) have been removed.");
return affected;
}
@ -213,18 +208,17 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.removebelow")
@Logging(PLACEMENT)
public int removeBelow(Player player, LocalSession session, EditSession editSession,
public int removeBelow(Actor actor, World world, 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();
height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1);
int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height);
player.print(affected + " block(s) have been removed.");
int affected = editSession.removeBelow(session.getPlacementPosition(actor), size, height);
actor.print(affected + " block(s) have been removed.");
return affected;
}
@ -235,7 +229,7 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.removenear")
@Logging(PLACEMENT)
public int removeNear(Player player, LocalSession session, EditSession editSession,
public int removeNear(Actor actor, 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")
@ -243,8 +237,8 @@ public class UtilityCommands {
radius = Math.max(1, radius);
we.checkMaxRadius(radius);
int affected = editSession.removeNear(session.getPlacementPosition(player), mask, radius);
player.print(affected + " block(s) have been removed.");
int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, radius);
actor.print(affected + " block(s) have been removed.");
return affected;
}
@ -255,7 +249,7 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.replacenear")
@Logging(PLACEMENT)
public int replaceNear(Player player, LocalSession session, EditSession editSession,
public int replaceNear(Actor actor, World world, 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 = "")
@ -265,17 +259,17 @@ public class UtilityCommands {
radius = Math.max(1, radius);
we.checkMaxRadius(radius);
BlockVector3 base = session.getPlacementPosition(player);
BlockVector3 base = session.getPlacementPosition(actor);
BlockVector3 min = base.subtract(radius, radius, radius);
BlockVector3 max = base.add(radius, radius, radius);
Region region = new CuboidRegion(player.getWorld(), min, max);
Region region = new CuboidRegion(world, min, max);
if (from == null) {
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;
}
@ -286,14 +280,14 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.snow")
@Logging(PLACEMENT)
public int snow(Player player, LocalSession session, EditSession editSession,
public int snow(Actor actor, 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);
player.print(affected + " surface(s) covered. Let it snow~");
int affected = editSession.simulateSnow(session.getPlacementPosition(actor), size);
actor.print(affected + " surface(s) covered. Let it snow~");
return affected;
}
@ -304,14 +298,14 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.thaw")
@Logging(PLACEMENT)
public int thaw(Player player, LocalSession session, EditSession editSession,
public int thaw(Actor actor, 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);
player.print(affected + " surface(s) thawed.");
int affected = editSession.thaw(session.getPlacementPosition(actor), size);
actor.print(affected + " surface(s) thawed.");
return affected;
}
@ -322,7 +316,7 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.green")
@Logging(PLACEMENT)
public int green(Player player, LocalSession session, EditSession editSession,
public int green(Actor actor, 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")
@ -331,8 +325,8 @@ public class UtilityCommands {
we.checkMaxRadius(size);
final boolean onlyNormalDirt = !convertCoarse;
final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt);
player.print(affected + " surface(s) greened.");
final int affected = editSession.green(session.getPlacementPosition(actor), size, onlyNormalDirt);
actor.print(affected + " surface(s) greened.");
return affected;
}
@ -343,7 +337,7 @@ public class UtilityCommands {
)
@CommandPermissions("worldedit.extinguish")
@Logging(PLACEMENT)
public void extinguish(Player player, LocalSession session, EditSession editSession,
public void extinguish(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The radius of the square to remove in", def = "")
Integer radius) throws WorldEditException {
@ -354,8 +348,8 @@ public class UtilityCommands {
we.checkMaxRadius(size);
Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE);
int affected = editSession.removeNear(session.getPlacementPosition(player), mask, size);
player.print(affected + " block(s) have been removed.");
int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, size);
actor.print(affected + " block(s) have been removed.");
}
@Command(
@ -384,7 +378,6 @@ public class UtilityCommands {
@Switch(name = 'r', desc = "Also destroy armor stands")
boolean killArmorStands) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
Player player = actor instanceof Player ? (Player) actor : null;
if (radius == null) {
radius = config.butcherDefaultRadius;
@ -410,7 +403,7 @@ public class UtilityCommands {
flags.or(CreatureButcher.Flags.TAGGED, killWithName, "worldedit.butcher.tagged");
flags.or(CreatureButcher.Flags.ARMOR_STAND, killArmorStands, "worldedit.butcher.armorstands");
int killed = killMatchingEntities(radius, player, flags::createFunction);
int killed = killMatchingEntities(radius, actor, flags::createFunction);
actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + ".");
@ -429,43 +422,32 @@ public class UtilityCommands {
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");
return 0;
}
int removed = killMatchingEntities(radius, player, remover::createFunction);
int removed = killMatchingEntities(radius, actor, remover::createFunction);
actor.print("Marked " + removed + (removed != 1 ? " entities" : " entity") + " for removal.");
return removed;
}
private int killMatchingEntities(Integer radius, Player player, Supplier<EntityFunction> func) throws IncompleteRegionException, MaxChangedBlocksException {
private int killMatchingEntities(Integer radius, Actor actor, Supplier<EntityFunction> func) throws IncompleteRegionException,
MaxChangedBlocksException {
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();
}
visitors.add(new EntityVisitor(entities.iterator(), func.get()));
LocalSession session = we.getSessionManager().get(actor);
BlockVector3 center = session.getPlacementPosition(actor);
EditSession editSession = session.createEditSession(actor);
List<? extends Entity> entities;
if (radius >= 0) {
CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius);
entities = editSession.getEntities(region);
} else {
Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING);
for (World world : platform.getWorlds()) {
List<? extends Entity> entities = world.getEntities();
visitors.add(new EntityVisitor(entities.iterator(), func.get()));
}
entities = editSession.getEntities();
}
visitors.add(new EntityVisitor(entities.iterator(), func.get()));
int killed = 0;
for (EntityVisitor visitor : visitors) {
@ -473,10 +455,8 @@ public class UtilityCommands {
killed += visitor.getAffected();
}
if (editSession != null) {
session.remember(editSession);
editSession.flushSession();
}
session.remember(editSession);
editSession.flushSession();
return killed;
}

View File

@ -30,6 +30,7 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.NoCapablePlatformException;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.util.paste.ActorCallbackPaste;
@ -81,8 +82,12 @@ public class WorldEditCommands {
actor.printDebug("----------- Capabilities -----------");
for (Capability capability : Capability.values()) {
Platform platform = pm.queryCapability(capability);
actor.printDebug(String.format("%s: %s", capability.name(), platform != null ? platform.getPlatformName() : "NONE"));
try {
Platform platform = pm.queryCapability(capability);
actor.printDebug(String.format("%s: %s", capability.name(), platform != null ? platform.getPlatformName() : "NONE"));
} catch (NoCapablePlatformException e) {
actor.printDebug(String.format("%s: %s", capability.name(), "NONE"));
}
}
}
@ -137,18 +142,18 @@ public class WorldEditCommands {
name = "tz",
desc = "Set your timezone for snapshots"
)
public void tz(Player player, LocalSession session,
public void tz(Actor actor, LocalSession session,
@Arg(desc = "The timezone to set")
String timezone) {
try {
ZoneId tz = ZoneId.of(timezone);
session.setTimezone(tz);
player.print("Timezone set for this session to: " + tz.getDisplayName(
actor.print("Timezone set for this session to: " + tz.getDisplayName(
TextStyle.FULL, Locale.ENGLISH
));
player.print("The current time in that timezone is: " + dateFormat.format(ZonedDateTime.now(tz)));
actor.print("The current time in that timezone is: " + dateFormat.format(ZonedDateTime.now(tz)));
} catch (ZoneRulesException e) {
player.printError("Invalid timezone");
actor.printError("Invalid timezone");
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.command.argument;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class WorldConverter implements ArgumentConverter<World> {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(World.class),
new WorldConverter()
);
}
private final TextComponent choices;
private WorldConverter() {
this.choices = TextComponent.of("any world");
}
@Override
public Component describeAcceptableArguments() {
return this.choices;
}
private Stream<? extends World> getWorlds() {
return WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getWorlds().stream();
}
@Override
public List<String> getSuggestions(String input) {
return getWorlds()
.map(World::getId)
.filter(world -> world.startsWith(input))
.collect(Collectors.toList());
}
@Override
public ConversionResult<World> convert(String s, InjectedValueAccess injectedValueAccess) {
World result = getWorlds()
.filter(world -> world.getId().equals(s))
.findAny().orElse(null);
return result == null
? FailedConversion.from(new IllegalArgumentException(
"Not a valid world: " + s))
: SuccessfulConversion.fromSingle(result);
}
}

View File

@ -34,8 +34,8 @@ public class SelectionWand implements DoubleActionBlockTool {
@Override
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
RegionSelector selector = session.getRegionSelector(player.getWorld());
BlockVector3 blockPoint = clicked.toVector().toBlockPoint();
if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) {
selector.explainPrimarySelection(player, session, blockPoint);
}
@ -46,6 +46,7 @@ public class SelectionWand implements DoubleActionBlockTool {
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
RegionSelector selector = session.getRegionSelector(player.getWorld());
BlockVector3 blockPoint = clicked.toVector().toBlockPoint();
if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) {
selector.explainSecondarySelection(player, session, blockPoint);
}

View File

@ -19,9 +19,9 @@
package com.sk89q.worldedit.entity;
import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.util.Faceted;
import com.sk89q.worldedit.util.Location;
import javax.annotation.Nullable;
@ -33,7 +33,7 @@ import javax.annotation.Nullable;
* instance of an entity, but a {@link BaseEntity} can be created from
* this entity by calling {@link #getState()}.</p>
*/
public interface Entity extends Faceted {
public interface Entity extends Faceted, Locatable {
/**
* Get a copy of the entity's state.
@ -47,28 +47,6 @@ public interface Entity extends Faceted {
@Nullable
BaseEntity getState();
/**
* Get the location of this entity.
*
* @return the location of the entity
*/
Location getLocation();
/**
* Sets the location of this entity.
*
* @param location the new location of the entity
* @return if the teleport worked
*/
boolean setLocation(Location location);
/**
* Get the extent that this entity is on.
*
* @return the extent
*/
Extent getExtent();
/**
* Remove this entity from it container.
*

View File

@ -191,8 +191,12 @@ public interface Player extends Entity, Actor {
* Get the point of the block that is being stood in.
*
* @return point
* @deprecated Use Locatable#getBlockLocation
*/
Location getBlockIn();
@Deprecated
default Location getBlockIn() {
return getBlockLocation();
}
/**
* Get the point of the block that is being stood upon.
@ -281,13 +285,6 @@ public interface Player extends Entity, Actor {
*/
void setPosition(Vector3 pos, float pitch, float yaw);
/**
* Move the player.
*
* @param pos where to move them
*/
void setPosition(Vector3 pos);
/**
* Sends a fake block to the client.
*

View File

@ -0,0 +1,51 @@
/*
* 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.sk89q.worldedit.internal.cui.CUIEvent;
import java.io.File;
public abstract class AbstractNonPlayerActor implements Actor {
@Override
public boolean canDestroyBedrock() {
return true;
}
@Override
public boolean isPlayer() {
return false;
}
@Override
public File openFileOpenDialog(String[] extensions) {
return null;
}
@Override
public File openFileSaveDialog(String[] extensions) {
return null;
}
@Override
public void dispatchCUIEvent(CUIEvent event) {
}
}

View File

@ -151,12 +151,12 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public void findFreePosition() {
findFreePosition(getBlockIn());
findFreePosition(getBlockLocation());
}
@Override
public boolean ascendLevel() {
final Location pos = getBlockIn();
final Location pos = getBlockLocation();
final int x = pos.getBlockX();
int y = Math.max(0, pos.getBlockY());
final int z = pos.getBlockZ();
@ -197,7 +197,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public boolean descendLevel() {
final Location pos = getBlockIn();
final Location pos = getBlockLocation();
final int x = pos.getBlockX();
int y = Math.max(0, pos.getBlockY() - 1);
final int z = pos.getBlockZ();
@ -247,7 +247,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public boolean ascendToCeiling(int clearance, boolean alwaysGlass) {
Location pos = getBlockIn();
Location pos = getBlockLocation();
int x = pos.getBlockX();
int initialY = Math.max(0, pos.getBlockY());
int y = Math.max(0, pos.getBlockY() + 2);
@ -287,7 +287,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public boolean ascendUpwards(int distance, boolean alwaysGlass) {
final Location pos = getBlockIn();
final Location pos = getBlockLocation();
final int x = pos.getBlockX();
final int initialY = Math.max(0, pos.getBlockY());
int y = Math.max(0, pos.getBlockY() + 1);
@ -345,13 +345,6 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
protected void setFlying(boolean flying) {
}
@Override
public Location getBlockIn() {
final Location location = getLocation();
return location.setPosition(location.toVector().floor());
}
@Override
public Location getBlockOn() {
final Location location = getLocation();

View File

@ -0,0 +1,69 @@
/*
* 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.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Location;
public interface Locatable {
/**
* Get the location of this actor.
*
* @return the location of the actor
*/
Location getLocation();
/**
* Get the location of this actor in block coordinates.
*
* @return the block location of the actor
*/
default Location getBlockLocation() {
Location location = getLocation();
return location.setPosition(location.toVector().floor());
}
/**
* Sets the location of this actor.
*
* @param location the new location of the actor
* @return if the teleport succeeded
*/
boolean setLocation(Location location);
/**
* Sets the position of this actor.
*
* @param pos where to move them
*/
default void setPosition(Vector3 pos) {
setLocation(new Location(getExtent(), pos));
}
/**
* Get the extent that this actor is in.
*
* @return the extent
*/
Extent getExtent();
}

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.extension.platform;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;
@ -26,6 +28,7 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MissingWorldException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.ApplyBrushCommands;
import com.sk89q.worldedit.command.BiomeCommands;
@ -79,6 +82,7 @@ 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.WorldConverter;
import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.command.util.SubCommandPermissionCondition;
@ -137,8 +141,6 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Handles the registration and invocation of commands.
*
@ -218,34 +220,55 @@ public final class PlatformCommandManager {
BooleanConverter.register(commandManager);
EntityRemoverConverter.register(commandManager);
RegionFactoryConverter.register(commandManager);
WorldConverter.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.");
}
});
});
context -> {
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("No LocalSession"));
return context.injectedValue(Key.of(World.class))
.map(world -> {
try {
return localSession.getSelection(world);
} catch (IncompleteRegionException e) {
exceptionConverter.convert(e);
throw new AssertionError("Should have thrown a new exception.", e);
}
});
});
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;
});
});
context -> {
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("No LocalSession"));
return context.injectedValue(Key.of(Actor.class))
.map(actor -> {
EditSession editSession = localSession.createEditSession(actor);
editSession.enableStandardMode();
return editSession;
});
});
globalInjectedValues.injectValue(Key.of(World.class),
context -> {
LocalSession localSession = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("No LocalSession"));
return context.injectedValue(Key.of(Actor.class))
.map(actor -> {
try {
if (localSession.hasWorldOverride()) {
return localSession.getWorldOverride();
} else if (actor instanceof Locatable && ((Locatable) actor).getExtent() instanceof World) {
return (World) ((Locatable) actor).getExtent();
} else {
throw new MissingWorldException();
}
} catch (MissingWorldException e) {
exceptionConverter.convert(e);
throw new AssertionError("Should have thrown a new exception.", e);
}
});
});
}
private <CI> void registerSubCommands(String name, List<String> aliases, String desc,

View File

@ -61,7 +61,7 @@ public interface Clipboard extends Extent {
/**
* Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector2)}
* strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes.OCEAN} instead of {@code null}
* strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes#OCEAN} instead of {@code null}
* if biomes aren't present. However, it might not be desired to set areas to ocean if the clipboard is defaulting
* to ocean, instead of having biomes explicitly set.
*

View File

@ -23,6 +23,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
import java.io.Closeable;
import java.io.IOException;
import java.util.OptionalInt;
/**
* Reads {@code Clipboard}s.
@ -39,4 +40,12 @@ public interface ClipboardReader extends Closeable {
*/
Clipboard read() throws IOException;
/**
* Get the DataVersion from a file (if possible).
*
* @return The data version, or empty
*/
default OptionalInt getDataVersion() {
return OptionalInt.empty();
}
}

View File

@ -60,6 +60,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.OptionalInt;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
@ -72,6 +73,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.class);
private final NBTInputStream inputStream;
private DataFixer fixer = null;
private int schematicVersion = -1;
private int dataVersion = -1;
/**
@ -86,25 +88,18 @@ public class SpongeSchematicReader extends NBTSchematicReader {
@Override
public Clipboard read() throws IOException {
NamedTag rootTag = inputStream.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
throw new IOException("Tag 'Schematic' does not exist or is not first");
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
// Check
CompoundTag schematicTag = getBaseTag();
Map<String, Tag> schematic = schematicTag.getValue();
int version = requireTag(schematic, "Version", IntTag.class).getValue();
final Platform platform = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.WORLD_EDITING);
int liveDataVersion = platform.getDataVersion();
if (version == 1) {
if (schematicVersion == 1) {
dataVersion = 1631; // this is a relatively safe assumption unless someone imports a schematic from 1.12, e.g. sponge 7.1-
fixer = platform.getDataFixer();
return readVersion1(schematicTag);
} else if (version == 2) {
} else if (schematicVersion == 2) {
dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue();
if (dataVersion > liveDataVersion) {
log.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.",
@ -126,6 +121,36 @@ public class SpongeSchematicReader extends NBTSchematicReader {
throw new IOException("This schematic version is currently not supported");
}
@Override
public OptionalInt getDataVersion() {
try {
CompoundTag schematicTag = getBaseTag();
Map<String, Tag> schematic = schematicTag.getValue();
if (schematicVersion == 1) {
return OptionalInt.of(1631);
} else if (schematicVersion == 2) {
return OptionalInt.of(requireTag(schematic, "DataVersion", IntTag.class).getValue());
}
return OptionalInt.empty();
} catch (IOException e) {
return OptionalInt.empty();
}
}
private CompoundTag getBaseTag() throws IOException {
NamedTag rootTag = inputStream.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
throw new IOException("Tag 'Schematic' does not exist or is not first");
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
// Check
Map<String, Tag> schematic = schematicTag.getValue();
schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue();
return schematicTag;
}
private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException {
BlockVector3 origin;
Region region;

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.CommandParameters;
import org.enginehub.piston.gen.CommandCallListener;
import org.enginehub.piston.inject.Key;
@ -72,18 +73,18 @@ public class CommandLoggingHandler implements CommandCallListener, AutoCloseable
logMode = loggingAnnotation.value();
}
Optional<Player> playerOpt = parameters.injectedValue(Key.of(Actor.class))
.filter(Player.class::isInstance)
.map(Player.class::cast);
Optional<Actor> playerOpt = parameters.injectedValue(Key.of(Actor.class));
Optional<World> worldOpt = parameters.injectedValue(Key.of(World.class));
if (!playerOpt.isPresent()) {
if (!playerOpt.isPresent() || !worldOpt.isPresent()) {
return;
}
Player player = playerOpt.get();
Actor actor = playerOpt.get();
World world = worldOpt.get();
builder.append("WorldEdit: ").append(player.getName());
builder.append(" (in \"").append(player.getWorld().getName()).append("\")");
builder.append("WorldEdit: ").append(actor.getName());
builder.append(" (in \"").append(world.getName()).append("\")");
builder.append(": ").append(parameters.getMetadata().getCalledName());
@ -93,14 +94,15 @@ public class CommandLoggingHandler implements CommandCallListener, AutoCloseable
parameters.getMetadata().getArguments().stream()
).collect(Collectors.joining(" ")));
if (logMode != null) {
if (logMode != null && actor instanceof Player) {
Player player = (Player) actor;
Vector3 position = player.getLocation().toVector();
LocalSession session = worldEdit.getSessionManager().get(player);
LocalSession session = worldEdit.getSessionManager().get(actor);
switch (logMode) {
case PLACEMENT:
try {
position = session.getPlacementPosition(player).toVector3();
position = session.getPlacementPosition(actor).toVector3();
} catch (IncompleteRegionException e) {
break;
}
@ -121,7 +123,7 @@ public class CommandLoggingHandler implements CommandCallListener, AutoCloseable
case REGION:
try {
builder.append(" - Region: ")
.append(session.getSelection(player.getWorld()));
.append(session.getSelection(world));
} catch (IncompleteRegionException e) {
break;
}

View File

@ -27,6 +27,7 @@ import com.sk89q.worldedit.InvalidItemException;
import com.sk89q.worldedit.MaxBrushRadiusException;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.MaxRadiusException;
import com.sk89q.worldedit.MissingWorldException;
import com.sk89q.worldedit.UnknownDirectionException;
import com.sk89q.worldedit.UnknownItemException;
import com.sk89q.worldedit.WorldEdit;
@ -81,6 +82,11 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper {
throw newCommandException("Make a region selection first.", e);
}
@ExceptionMatch
public void convert(MissingWorldException e) throws CommandException {
throw newCommandException("You need to provide a world (Try //world)", e);
}
@ExceptionMatch
public void convert(UnknownItemException e) throws CommandException {
throw newCommandException("Block name '" + e.getID() + "' was not recognized.", e);

View File

@ -33,6 +33,8 @@ import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes;
import java.nio.file.Path;
import java.util.PriorityQueue;
@ -133,6 +135,24 @@ public abstract class AbstractWorld implements World {
return null;
}
@Override
public WeatherType getWeather() {
return WeatherTypes.CLEAR;
}
@Override
public long getRemainingWeatherDuration() {
return 0;
}
@Override
public void setWeather(WeatherType weatherType) {
}
@Override
public void setWeather(WeatherType weatherType, long duration) {
}
private class QueuedEffect implements Comparable<QueuedEffect> {
private final Vector3 position;
private final BlockType blockType;

View File

@ -61,6 +61,11 @@ public class NullWorld extends AbstractWorld {
return "null";
}
@Override
public String getId() {
return "null";
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException {
return false;

View File

@ -31,6 +31,7 @@ import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.block.BlockState;
@ -44,7 +45,7 @@ import java.nio.file.Path;
/**
* Represents a world (dimension).
*/
public interface World extends Extent {
public interface World extends Extent, Keyed {
/**
* Get the name of the world.

View File

@ -37,5 +37,7 @@ public interface CategoryRegistry<T extends Keyed> {
*/
Set<T> getCategorisedByName(String category);
Set<T> getAll(final Category<T> category);
default Set<T> getAll(final Category<T> category) {
return getCategorisedByName(category.getId());
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.block.BlockType;
import java.util.Collections;
@ -31,9 +30,4 @@ public class NullBlockCategoryRegistry implements BlockCategoryRegistry {
public Set<BlockType> getCategorisedByName(String category) {
return Collections.emptySet();
}
@Override
public Set<BlockType> getAll(final Category<BlockType> category) {
return Collections.emptySet();
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.item.ItemType;
import java.util.Collections;
@ -31,9 +30,4 @@ public class NullItemCategoryRegistry implements ItemCategoryRegistry {
public Set<ItemType> getCategorisedByName(String category) {
return Collections.emptySet();
}
@Override
public Set<ItemType> getAll(final Category<ItemType> category) {
return Collections.emptySet();
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.fabric;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import net.minecraft.tag.BlockTags;
@ -38,9 +37,4 @@ public class FabricBlockCategoryRegistry implements BlockCategoryRegistry {
.map(Tag::values).orElse(Collections.emptySet())
.stream().map(FabricAdapter::adapt).collect(Collectors.toSet());
}
@Override
public Set<BlockType> getAll(Category<BlockType> category) {
return getCategorisedByName(category.getId());
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.fabric;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
import net.minecraft.tag.ItemTags;
@ -38,9 +37,4 @@ public class FabricItemCategoryRegistry implements ItemCategoryRegistry {
.map(Tag::values).orElse(Collections.emptySet())
.stream().map(FabricAdapter::adapt).collect(Collectors.toSet());
}
@Override
public Set<ItemType> getAll(Category<ItemType> category) {
return getCategorisedByName(category.getId());
}
}

View File

@ -100,6 +100,7 @@ import java.lang.ref.WeakReference;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Random;
@ -168,6 +169,13 @@ public class FabricWorld extends AbstractWorld {
return getWorld().getLevelProperties().getLevelName();
}
@Override
public String getId() {
return getWorld().getLevelProperties().getLevelName()
.replace(" ", "_").toLowerCase(Locale.ROOT)
+ getWorld().dimension.getType().getSuffix();
}
@Override
public Path getStoragePath() {
final World world = getWorld();

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.forge;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import net.minecraft.tags.BlockTags;
@ -38,9 +37,4 @@ public class ForgeBlockCategoryRegistry implements BlockCategoryRegistry {
.map(Tag::getAllElements).orElse(Collections.emptySet())
.stream().map(ForgeAdapter::adapt).collect(Collectors.toSet());
}
@Override
public Set<BlockType> getAll(Category<BlockType> category) {
return getCategorisedByName(category.getId());
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.forge;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
import net.minecraft.tags.ItemTags;
@ -38,9 +37,4 @@ public class ForgeItemCategoryRegistry implements ItemCategoryRegistry {
.map(Tag::getAllElements).orElse(Collections.emptySet())
.stream().map(ForgeAdapter::adapt).collect(Collectors.toSet());
}
@Override
public Set<ItemType> getAll(Category<ItemType> category) {
return getCategorisedByName(category.getId());
}
}

View File

@ -93,6 +93,7 @@ import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.SaveHandler;
import net.minecraft.world.storage.WorldInfo;
import net.minecraftforge.common.DimensionManager;
import javax.annotation.Nullable;
import java.io.File;
@ -169,6 +170,11 @@ public class ForgeWorld extends AbstractWorld {
return getWorld().getWorldInfo().getWorldName();
}
@Override
public String getId() {
return DimensionManager.getRegistry().getKey(getWorld().dimension.getType()).toString();
}
@Override
public Path getStoragePath() {
final World world = getWorld();

View File

@ -0,0 +1 @@
applyLibrariesConfiguration()

View File

@ -60,6 +60,7 @@ import java.lang.ref.WeakReference;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
@ -117,6 +118,12 @@ public abstract class SpongeWorld extends AbstractWorld {
return getWorld().getName();
}
@Override
public String getId() {
return getName().replace(" ", "_").toLowerCase(Locale.ROOT) +
getWorld().getDimension().getType().getName().toLowerCase(Locale.ROOT);
}
@Override
public Path getStoragePath() {
return getWorld().getDirectory();