diff --git a/build.gradle.kts b/build.gradle.kts index 21be27e98..290ac2f78 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ logger.lifecycle(""" 1) Read COMPILING.md if you haven't yet 2) Try running 'build' in a separate Gradle run 3) Use gradlew and not gradle - 4) If you still need help, ask on Discord! https://discord.gg/cSMxtGn + 4) If you still need help, ask on Discord! https://discord.gg/enginehub Output files will be in [subproject]/build/libs ******************************************* diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index bf07b7bb6..031038c9b 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -12,6 +12,7 @@ repositories { maven { url = uri("https://repo.codemc.org/repository/maven-public") } maven { url = uri("https://papermc.io/repo/repository/maven-public/") } maven { url = uri("http://empcraft.com/maven2") } + maven { url = uri("https://maven.enginehub.org/repo/") } maven { url = uri("http://ci.frostcast.net/plugin/repository/everything") } maven { url = uri("http://dl.bintray.com/tastybento/maven-repo") } maven { url = uri("http://ci.emc.gs/nexus/content/groups/aikar/") } @@ -38,10 +39,15 @@ dependencies { "implementation"("io.papermc:paperlib:1.0.2") "compileOnly"("com.sk89q:dummypermscompat:1.10") "implementation"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1") - "implementation"("org.bstats:bstats-bukkit:1.5") - "testCompile"("org.mockito:mockito-core:1.9.0-rc1") - "implementation"("com.sk89q.worldguard:worldguard-core:7.0.0-20190215.210421-39") { isTransitive = false } - "implementation"("com.sk89q.worldguard:worldguard-legacy:7.0.0-20190215.210421-39") { isTransitive = false } + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") { + exclude("junit", "junit") + } + "compileOnly"("com.sk89q.worldguard:worldguard-bukkit:7.0.0") { + exclude("com.sk89q.worldedit", "worldedit-bukkit") + exclude("com.sk89q.worldedit", "worldedit-core") + exclude("com.sk89q.worldedit.worldedit-libs", "bukkit") + exclude("com.sk89q.worldedit.worldedit-libs", "core") + } "implementation"("com.massivecraft:factions:2.8.0") { isTransitive = false } "implementation"("com.drtshock:factions:1.6.9.5") { isTransitive = false } "implementation"("com.factionsone:FactionsOne:1.2.2") { isTransitive = false } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/chat/TextualComponent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/chat/TextualComponent.java deleted file mode 100644 index 53365f433..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/chat/TextualComponent.java +++ /dev/null @@ -1,273 +0,0 @@ -package com.boydti.fawe.bukkit.chat; - -import com.google.common.base.Preconditions; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import org.bukkit.configuration.serialization.ConfigurationSerializable; -import org.bukkit.configuration.serialization.ConfigurationSerialization; - -/** - * Represents a textual component of a message part. - * This can be used to not only represent string literals in a JSON message, - * but also to represent localized strings and other text values. - *

Different instances of this class can be created with static constructor methods.

- */ -public abstract class TextualComponent implements Cloneable { - - static { - ConfigurationSerialization.registerClass(ArbitraryTextTypeComponent.class); - ConfigurationSerialization.registerClass(ComplexTextTypeComponent.class); - } - - static TextualComponent deserialize(Map map) { - if (map.containsKey("key") && map.size() == 2 && map.containsKey("value")) { - // Arbitrary text component - return ArbitraryTextTypeComponent.deserialize(map); - } else if (map.size() >= 2 && map.containsKey("key") && !map.containsKey("value") /* It contains keys that START WITH value */) { - // Complex JSON object - return ComplexTextTypeComponent.deserialize(map); - } - - return null; - } - - static boolean isTextKey(String key) { - return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector"); - } - - static boolean isTranslatableText(TextualComponent component) { - return component instanceof ComplexTextTypeComponent && component.getKey().equals("translate"); - } - - /** - * Create a textual component representing a string literal. - * - *

This is the default type of textual component when a single string - * literal is given to a method. - * - * @param textValue The text which will be represented. - * @return The text component representing the specified literal text. - */ - public static TextualComponent rawText(String textValue) { - return new ArbitraryTextTypeComponent("text", textValue); - } - - /** - * Create a textual component representing a localized string. - * The client will see this text component as their localized version of the specified string key, which can be overridden by a - * resource pack. - *

- * If the specified translation key is not present on the client resource pack, the translation key will be displayed as a string literal to - * the client. - *

- * - * @param translateKey The string key which maps to localized text. - * @return The text component representing the specified localized text. - */ - public static TextualComponent localizedText(String translateKey) { - return new ArbitraryTextTypeComponent("translate", translateKey); - } - - private static void throwUnsupportedSnapshot() { - throw new UnsupportedOperationException("This feature is only supported in snapshot releases."); - } - - /** - * Create a textual component representing a player name, retrievable by using a standard minecraft selector. - * The client will see the players or entities captured by the specified selector as the text represented by this component. - *

- * This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients. - *

- * - * @param selector The minecraft player or entity selector which will capture the entities whose string representations will be displayed in - * the place of this text component. - * @return The text component representing the name of the entities captured by the selector. - */ - public static TextualComponent selector(String selector) { - throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE - // OVERLOADS documentation accordingly - - return new ArbitraryTextTypeComponent("selector", selector); - } - - @Override - public String toString() { - return getReadableString(); - } - - /** - * @return The JSON key used to represent text components of this type. - */ - public abstract String getKey(); - - /** - * @return A readable String - */ - public abstract String getReadableString(); - - /** - * Clones a textual component instance. - * The returned object should not reference this textual component instance, but should maintain the same key and value. - */ - @Override - public abstract TextualComponent clone() throws CloneNotSupportedException; - - /** - * Writes the text data represented by this textual component to the specified JSON writer object. - * A new object within the writer is not started. - * - * @param writer The object to which to write the JSON data. - * @throws IOException If an error occurs while writing to the stream. - */ - public abstract void writeJson(JsonWriter writer) throws IOException; - - /** - * Internal class used to represent all types of text components. - * Exception validating done is on keys and values. - */ - private static final class ArbitraryTextTypeComponent extends TextualComponent implements ConfigurationSerializable { - - private String key; - private String value; - - public ArbitraryTextTypeComponent(String key, String value) { - setKey(key); - setValue(value); - } - - public static ArbitraryTextTypeComponent deserialize(Map map) { - return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString()); - } - - @Override - public String getKey() { - return key; - } - - public void setKey(String key) { - Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified."); - this.key = key; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - Preconditions.checkArgument(value != null, "The value must be specified."); - this.value = value; - } - - @Override - public TextualComponent clone() throws CloneNotSupportedException { - // Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone - return new ArbitraryTextTypeComponent(getKey(), getValue()); - } - - @Override - public void writeJson(JsonWriter writer) throws IOException { - writer.name(getKey()).value(getValue()); - } - - @Override - @SuppressWarnings("serial") - public Map serialize() { - return new HashMap() { - { - put("key", getKey()); - put("value", getValue()); - } - }; - } - - @Override - public String getReadableString() { - return getValue(); - } - } - - /** - * Internal class used to represent a text component with a nested JSON - * value. - * - *

Exception validating done is on keys and values. - */ - private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable { - - private String key; - private Map value; - - public ComplexTextTypeComponent(String key, Map values) { - setKey(key); - setValue(values); - } - - public static ComplexTextTypeComponent deserialize(Map map) { - String key = null; - Map value = new HashMap<>(); - for (Map.Entry valEntry : map.entrySet()) { - if (valEntry.getKey().equals("key")) { - key = (String) valEntry.getValue(); - } else if (valEntry.getKey().startsWith("value.")) { - value.put(valEntry.getKey().substring(6) /* Strips out the value prefix */, valEntry.getValue().toString()); - } - } - return new ComplexTextTypeComponent(key, value); - } - - @Override - public String getKey() { - return key; - } - - public void setKey(String key) { - Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified."); - this.key = key; - } - - public Map getValue() { - return value; - } - - public void setValue(Map value) { - Preconditions.checkArgument(value != null, "The value must be specified."); - this.value = value; - } - - @Override - public TextualComponent clone() { - // Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone - return new ComplexTextTypeComponent(getKey(), getValue()); - } - - @Override - public void writeJson(JsonWriter writer) throws IOException { - writer.name(getKey()); - writer.beginObject(); - for (Map.Entry jsonPair : value.entrySet()) { - writer.name(jsonPair.getKey()).value(jsonPair.getValue()); - } - writer.endObject(); - } - - @Override - @SuppressWarnings("serial") - public Map serialize() { - return new HashMap() { - { - put("key", getKey()); - for (Entry valEntry : getValue().entrySet()) { - put("value." + valEntry.getKey(), valEntry.getValue()); - } - } - }; - } - - @Override - public String getReadableString() { - return getKey(); - } - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java index a70360373..24a8cc696 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java @@ -19,6 +19,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.material.MaterialData; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; public class AsyncBlockState implements BlockState { @@ -99,6 +100,7 @@ public class AsyncBlockState implements BlockState { return block.getLocation(loc); } + @NotNull @Override public Chunk getChunk() { return block.getChunk(); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java index 96c755083..ee975b837 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java @@ -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(); } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitRegistries.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitRegistries.java index 31923c69f..0ac01328d 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitRegistries.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitRegistries.java @@ -34,7 +34,6 @@ class BukkitRegistries extends BundledRegistries { private static final BukkitRegistries INSTANCE = new BukkitRegistries(); private final BlockRegistry blockRegistry = new BukkitBlockRegistry(); - private final ItemRegistry itemRegistry = new BukkitItemRegistry(); private final BiomeRegistry biomeRegistry = new BukkitBiomeRegistry(); private final EntityRegistry entityRegistry = new BukkitEntityRegistry(); private final BlockCategoryRegistry blockCategoryRegistry = new BukkitBlockCategoryRegistry(); @@ -56,11 +55,6 @@ class BukkitRegistries extends BundledRegistries { return biomeRegistry; } - @Override - public ItemRegistry getItemRegistry() { - return itemRegistry; - } - @Override public BlockCategoryRegistry getBlockCategoryRegistry() { return blockCategoryRegistry; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index e48b847b9..06dbc31b5 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -23,9 +23,11 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.bukkit.FaweBukkit; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -33,6 +35,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.registry.BlockMaterial; +import java.util.OptionalInt; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; @@ -154,7 +157,30 @@ public interface BukkitImplAdapter extends IBukkitAdapter { */ void sendFakeOP(Player player); + /** + * Simulates a player using an item. + * + * @param world the world + * @param position the location + * @param item the item to be used + * @param face the direction in which to "face" when using the item + * @return whether the usage was successful + */ + default boolean simulateItemUse(World world, BlockVector3 position, BaseItem item, Direction face) { + return false; + } + default @org.jetbrains.annotations.Nullable World createWorld(WorldCreator creator) { return ((FaweBukkit) Fawe.imp()).createWorldUnloaded(creator::createWorld); } + + /** + * Retrieve the internal ID for a given state, if possible. + * + * @param state The block state + * @return the internal ID of the state + */ + default OptionalInt getInternalBlockStateId(BlockState state) { + return OptionalInt.empty(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java index 8f98d6093..dd4bf4b29 100644 --- a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java @@ -135,7 +135,7 @@ public final class StringUtil { } StringBuilder buffer = new StringBuilder(Integer.toString(str[initialIndex])); for (int i = initialIndex + 1; i < str.length; ++i) { - buffer.append(delimiter).append(str[i]); + buffer.append(delimiter).append(Integer.toString(str[i])); } return buffer.toString(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 1c002059a..3fd4c1d08 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1010,7 +1010,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { @Override @Nullable - public Entity createEntity(Location location, final BaseEntity entity) { + public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) { return getExtent().createEntity(location, entity); } @@ -1233,7 +1233,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public > int fillXZ(BlockVector3 origin, B block, double radius, int depth, boolean recursive) throws MaxChangedBlocksException { - return fillXZ(origin, block, radius, depth, recursive); + return fillXZ(origin, (Pattern) block, radius, depth, recursive); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java index 9b288271f..5b972e577 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java @@ -23,6 +23,7 @@ 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 +66,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 +115,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 +157,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 +167,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)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index dbdaf32cd..a03d169fa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -152,6 +152,7 @@ public class LocalSession implements TextureHolder { private transient VirtualWorld virtual; private transient BlockVector3 cuiTemporaryBlock; private transient List> lastDistribution; + private transient World worldOverride; // Saved properties private String lastScript; @@ -569,6 +570,19 @@ public class LocalSession implements TextureHolder { 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; + } + + public void unregisterTools(Player player) { for (Tool tool : tools) { if (tool instanceof BrushTool) { @@ -614,6 +628,9 @@ public class LocalSession implements TextureHolder { if (selector.getWorld() == null || !selector.getWorld().equals(world)) { selector.setWorld(world); selector.clear(); + if (hasWorldOverride() && !world.equals(getWorldOverride())) { + setWorldOverride(null); + } } } catch (Throwable ignore) { selector.clear(); @@ -632,6 +649,9 @@ public class LocalSession implements TextureHolder { checkNotNull(selector); selector.setWorld(world); this.selector = selector; + if (hasWorldOverride() && !world.equals(getWorldOverride())) { + setWorldOverride(null); + } } /** @@ -1328,17 +1348,23 @@ public class LocalSession implements TextureHolder { /** * Construct a new edit session. * - * @param player the actor + * @param actor the actor * @return an edit session */ - public EditSession createEditSession(Player player) { - checkNotNull(player); - - BlockBag blockBag = getBlockBag(player); - - World world = player.getWorld(); + public EditSession createEditSession(Actor actor) { + checkNotNull(actor); + BlockBag blockBag = null; + if (actor.isPlayer() && actor instanceof Player) { + blockBag = getBlockBag((Player) actor); + } + World world = null; + if (hasWorldOverride()) { + world = getWorldOverride(); + } else if (actor instanceof Locatable && ((Locatable) actor).getExtent() instanceof World) { + world = (World) ((Locatable) actor).getExtent(); + } EditSessionBuilder builder = new EditSessionBuilder(world); - if (player.isPlayer()) builder.player(FawePlayer.wrap(player)); + if (actor.isPlayer() && actor instanceof Player) builder.player(FawePlayer.wrap(actor)); builder.blockBag(blockBag); builder.fastmode(fastMode); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java index 823852c37..4ebef6078 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -72,6 +72,27 @@ public class ApplyBrushCommands { .ofTypes(ImmutableList.of(Key.of(double.class))) .build(); + public static void register(CommandManagerService service, CommandManager commandManager, CommandRegistrationHandler registration) { + commandManager.register("apply", builder -> { + builder.description(TextComponent.of("Apply brush, apply a function to every block")); + builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); + + CommandManager manager = service.newCommandManager(); + registration.register( + manager, + ApplyBrushCommandsRegistration.builder(), + new ApplyBrushCommands() + ); + + builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.apply"))); + + builder.addParts(REGION_FACTORY, RADIUS); + builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use")) + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); + } private void setApplyBrush(CommandParameters parameters, Player player, LocalSession localSession, Contextual generatorFactory) throws WorldEditException { double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 7b9abb491..fb7c5818c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -30,6 +30,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.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.anvil.ChunkDeleter; @@ -39,6 +40,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; 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.format.TextColor; @@ -51,8 +53,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.ArgFlag; @@ -94,10 +96,11 @@ public class ChunkCommands { @CommandPermissions("worldedit.listchunks") public void listChunks(Actor actor, World world, LocalSession session, @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { - Set chunks = session.getSelection(world).getChunks(); + final Region region = session.getSelection(world); - PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%", chunks); - actor.print(paginationBox.create(page)); + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, + () -> new ChunkListPaginationBox(region).create(page), + "Listing chunks for " + actor.getName()); } @Command( @@ -168,4 +171,27 @@ public class ChunkCommands { .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); } + private static class ChunkListPaginationBox extends PaginationBox { + //private final Region region; + private final List chunks; + + ChunkListPaginationBox(Region region) { + super("Selected Chunks", "/listchunks -p %page%"); + // TODO make efficient/streamable/calculable implementations of this + // for most region types, so we can just store the region and random-access get one page of chunks + // (this is non-trivial for some types of selections...) + //this.region = region.clone(); + this.chunks = new ArrayList<>(region.getChunks()); + } + + @Override + public Component getComponent(int number) { + return TextComponent.of(chunks.get(number).toString()); + } + + @Override + public int getComponentsSize() { + return chunks.size(); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java index 53d184d78..393a95606 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java @@ -29,6 +29,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; @@ -37,6 +38,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 java.util.List; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; @@ -119,7 +121,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") @@ -127,7 +129,7 @@ public class ExpandCommands { @Arg(desc = "Direction to expand", def = Direction.AIM) @MultiDirection List direction) throws WorldEditException { - Region region = session.getSelection(player.getWorld()); + Region region = session.getSelection(world); int oldSize = region.getArea(); if (reverseAmount == 0) { @@ -140,12 +142,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)."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 137ee9883..827c43b5b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -85,23 +85,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.)")); } @@ -110,22 +110,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.)")); } @@ -134,18 +134,20 @@ public class GeneralCommands { desc = "Toggle fast mode" ) @CommandPermissions("worldedit.fast") - public void fast(Player player, LocalSession session, @Arg(desc = "The new fast mode state", def = "") Boolean fastMode) { + 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); - BBC.FAST_DISABLED.send(player); + BBC.FAST_DISABLED.send(actor); } else { session.setFastMode(true); - BBC.FAST_ENABLED.send(player); + BBC.FAST_ENABLED.send(actor); } } @@ -154,14 +156,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()); } } @@ -193,18 +195,33 @@ public class GeneralCommands { } @Command( - name = "/gmask", - aliases = {"gmask", "globalmask", "/globalmask"}, + 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"}, descFooter = "The global destination mask applies to all edits you do and masks based on the destination blocks (i.e. the blocks in the world).", desc = "Set the global mask" ) @CommandPermissions({"worldedit.global-mask", "worldedit.mask.global"}) - public void gmask(Player player, LocalSession session, @Arg(desc = "The mask to set", def = "") Mask maskOpt) { - session.setMask(maskOpt); - if (maskOpt == null) { - BBC.MASK_DISABLED.send(player); + public void gmask(Actor actor, LocalSession session, @Arg(desc = "The mask to set", def = "") Mask mask) { + session.setMask(mask); + if (mask == null) { + BBC.MASK_DISABLED.send(actor); } else { - BBC.MASK.send(player); + BBC.MASK.send(actor); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java index caaf29da6..c42dd5ea4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -54,7 +54,7 @@ public final class RegistryConverter implements ArgumentConvert @SuppressWarnings("unchecked") public static void register(CommandManager commandManager) { ImmutableList.of( - BlockTypes.class, + BlockType.class, BlockCategory.class, ItemType.class, ItemCategory.class, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java index 19d43291b..b67806ca9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; @@ -91,8 +92,13 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo } private Location getTargetFace(Player player) { - Location target = player.getBlockTraceFace(getRange(), true); - target = player.getBlockTrace(getRange(), true); + Location target; + Mask mask = getTraceMask(); + if (this.range > -1) { + target = player.getBlockTrace(getRange(), true, mask); + } else { + target = player.getBlockTrace(MAX_RANGE, false, mask); + } if (target == null) { BBC.NO_BLOCK.send(player); return null; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java index d96a44819..be47971b7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java @@ -37,7 +37,7 @@ public class HollowCylinderBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { if (pattern == null) { - pattern = (BlockTypes.COBBLESTONE.getDefaultState()); + pattern = BlockTypes.COBBLESTONE.getDefaultState(); } editSession.makeCylinder(position, pattern, size, size, height, false); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java index bbba333b3..42a300048 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java @@ -31,7 +31,7 @@ public class HollowSphereBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { if (pattern == null) { - pattern = (BlockTypes.COBBLESTONE.getDefaultState()); + pattern = BlockTypes.COBBLESTONE.getDefaultState(); } editSession.makeSphere(position, pattern, size, size, size, false); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index 964880def..68e213a2b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -383,7 +383,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public Location getBlockOn() { - return getLocation().setPosition(getLocation().setY(getLocation().getY() - 1).toVector().floor()); + final Location location = getLocation(); + return location.setPosition(location.setY(location.getY() - 1).toVector().floor()); } @Override @@ -524,7 +525,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public void setPosition(Vector3 pos) { - setPosition(pos, getLocation().getPitch(), getLocation().getYaw()); + final Location location = getLocation(); + setPosition(pos, location.getPitch(), location.getYaw()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index a24a6cab7..7c99e5a41 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -393,7 +393,7 @@ public final class PlatformCommandManager { registerSubCommands( "brush", ImmutableList.of("br", "/brush", "/br", "/tool", "tool"), - "Tool commands", + "Brushing commands", BrushOptionsCommandsRegistration.builder(), new BrushOptionsCommands(worldEdit) ); @@ -729,6 +729,7 @@ public final class PlatformCommandManager { // exceptions without writing a hook into every dispatcher, we need to unwrap these // exceptions and rethrow their converted form, if their is one. try { + //Why the hell do we need to return an object if we aren't doing anything with it? Object result = task.get(); } catch (Throwable t) { // Use the exception converter to convert the exception if any of its causes diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java index a706da033..d93c26ba8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java @@ -125,7 +125,7 @@ public class CuboidRegionSelector implements RegionSelector, CUIRegion { public boolean selectPrimary(BlockVector3 position, SelectorLimits limits) { checkNotNull(position); - if (position.equals(position1)) { + if (position1 != null && position.equals(position1)) { return false; } @@ -138,7 +138,7 @@ public class CuboidRegionSelector implements RegionSelector, CUIRegion { public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { checkNotNull(position); - if (position.equals(position2)) { + if (position2 != null && position.equals(position2)) { return false; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 7ad85825f..c48d2d869 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -34,6 +34,8 @@ 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 javax.annotation.Nullable; import java.nio.file.Path; import java.util.PriorityQueue; @@ -132,6 +134,23 @@ 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 { private final Vector3 position; private final BlockType blockType; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index b547a1c2e..e30ed8fa9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -63,6 +63,10 @@ public class NullWorld extends AbstractWorld { return "null"; } + @Override + public String getId() { + return "null"; + } @Override public > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java index 61a8000f8..030c667aa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -106,10 +106,6 @@ public class ItemType implements RegistryItem, Keyed { return this.blockType; } - public void setBlockType(BlockType blockType) { - this.blockType = blockType; - } - public BaseItem getDefaultState() { if (defaultState == null) { this.defaultState = new BaseItemStack(this); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java index 0de14a17c..7f794b021 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java @@ -37,5 +37,7 @@ public interface CategoryRegistry { */ Set getCategorisedByName(String category); - Set getAll(final Category category); + default Set getAll(final Category category) { + return getCategorisedByName(category.getId()); + } } diff --git a/worldedit-libs/README.md b/worldedit-libs/README.md new file mode 100644 index 000000000..6387fde12 --- /dev/null +++ b/worldedit-libs/README.md @@ -0,0 +1,9 @@ +This project shades _API_ libraries, i.e. those libraries +whose classes are publicly referenced from `-core` classes. + +This project _does not_ shade implementation libraries, i.e. +those libraries whose classes are internally depended on. + +This is because the main reason for shading those libraries is for +their internal usage in each platform, not because we need them available to +dependents of `-core` to compile and work with WorldEdit's API. diff --git a/worldedit-libs/core/build.gradle.kts b/worldedit-libs/core/build.gradle.kts index 01f0d74e1..4a115d889 100644 --- a/worldedit-libs/core/build.gradle.kts +++ b/worldedit-libs/core/build.gradle.kts @@ -11,8 +11,7 @@ dependencies { "shade"("com.github.luben:zstd-jni:1.4.3-1") "shade"("com.thoughtworks.paranamer:paranamer:2.6") "shade"("com.sk89q.lib:jlibnoise:1.0.0") - - "shade"("FAWE-Piston:core/build/libs/core-${Versions.PISTON}:lastSuccessfulBuild@jar") + "shade"("FAWE-Piston:core/build/libs/core-${Versions.PISTON}:lastSuccessfulBuild@jar") "shade"("FAWE-Piston:core-ap/runtime/build/libs/runtime-${Versions.PISTON}:lastSuccessfulBuild@jar") "shade"("FAWE-Piston:default-impl/build/libs/default-impl-${Versions.PISTON}:lastSuccessfulBuild@jar")