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 c25bf8fee3..d9240bc6b6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -119,6 +119,7 @@ import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.mask.BlockMaskUtil; import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; @@ -1527,8 +1528,10 @@ public int stackRegionBlockUnits(Region region, BlockVector3 offset, int count, copy.setTransform(new AffineTransform().translate(offset)); copy.setCopyingEntities(copyEntities); copy.setCopyingBiomes(copyBiomes); - if (mask != null) { - copy.setSourceMask(mask); + Mask sourceMask = BlockMaskUtil.checkForAllowedBlocksMask(actor, mask, this); + + if (sourceMask != null) { + copy.setSourceMask(sourceMask); } Operations.completeLegacy(copy); return copy.getAffected(); @@ -1587,9 +1590,10 @@ public int moveRegion(Region region, BlockVector3 offset, int multiplier, copy.setCopyingEntities(moveEntities); copy.setRemovingEntities(moveEntities); copy.setCopyingBiomes(copyBiomes); + Mask sourceMask = BlockMaskUtil.checkForAllowedBlocksMask(actor, mask, this); - if (mask != null) { - copy.setSourceMask(mask); + if (sourceMask != null) { + copy.setSourceMask(sourceMask); } // Then we need to copy the buffer to the world diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index 62a0979ab0..e710e2dfe2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -52,6 +52,8 @@ public abstract class LocalConfiguration { public boolean profile = false; public boolean traceUnflushedSessions = true; public Set disallowedBlocks = new HashSet<>(); + public boolean disableDisallowedBlockCategories = true; + public boolean disableDisallowedBlockCopying = true; public int defaultChangeLimit = -1; public int maxChangeLimit = -1; public int defaultVerticalHeight = 256; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index b2c7fcec1a..bfc6393f1c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -50,6 +50,7 @@ import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.mask.BlockMaskUtil; import com.sk89q.worldedit.world.World; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; @@ -102,8 +103,10 @@ public void copy(Actor actor, LocalSession session, EditSession editSession, ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setCopyingEntities(copyEntities); copy.setCopyingBiomes(copyBiomes); - if (mask != null) { - copy.setSourceMask(mask); + Mask sourceMask = BlockMaskUtil.checkForAllowedBlocksMask(actor, mask, editSession); + + if (sourceMask != null) { + copy.setSourceMask(sourceMask); } Operations.completeLegacy(copy); session.setClipboard(new ClipboardHolder(clipboard)); @@ -135,8 +138,10 @@ public void cut(Actor actor, LocalSession session, EditSession editSession, copy.setCopyingEntities(copyEntities); copy.setRemovingEntities(true); copy.setCopyingBiomes(copyBiomes); - if (mask != null) { - copy.setSourceMask(mask); + Mask sourceMask = BlockMaskUtil.checkForAllowedBlocksMask(actor, mask, editSession); + + if (sourceMask != null) { + copy.setSourceMask(sourceMask); } Operations.completeLegacy(copy); session.setClipboard(new ClipboardHolder(clipboard)); @@ -299,9 +304,10 @@ void revolve(Actor actor, LocalSession session, EditSession editSession, @Select ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setCopyingEntities(copyEntities); copy.setCopyingBiomes(copyBiomes); + Mask sourceMask = BlockMaskUtil.checkForAllowedBlocksMask(actor, mask, editSession); - if (mask != null) { - copy.setSourceMask(mask); + if (sourceMask != null) { + copy.setSourceMask(sourceMask); } Operations.complete(copy); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java index cf6dd579bf..54a6daccff 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -19,11 +19,14 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; +import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.registry.InputParser; @@ -66,6 +69,17 @@ public Pattern parseFromInput(String input, ParserContext context) throws InputP RandomPattern randomPattern = new RandomPattern(); Set blocks = category.getAll(); + LocalConfiguration config = worldEdit.getConfiguration(); + if (context.isRestricted() && config.disableDisallowedBlockCategories) { + Actor actor = context.requireActor(); + Set disallowedBlocks = config.disallowedBlocks; + if (actor != null + && !actor.hasPermission("worldedit.anyblock") + && blocks.stream().map(BlockType::id).anyMatch(disallowedBlocks::contains)) { + throw new DisallowedUsageException(TranslatableComponent.of("worldedit.error.disallowed-blocks")); + } + } + if (blocks.isEmpty()) { throw new InputParseException(TranslatableComponent.of("worldedit.error.empty-tag", TextComponent.of(category.id()))); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AllowedBlocksMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AllowedBlocksMask.java new file mode 100644 index 0000000000..973f08d1cf --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/AllowedBlocksMask.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.function.mask; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockType; + +public final class AllowedBlocksMask extends AbstractExtentMask { + + private final WorldEdit worldEdit; + + /** + * Create a new allowed blocks mask. + * + * @param worldEdit the WorldEdit instance + * @param extent the extent + */ + public AllowedBlocksMask(WorldEdit worldEdit, Extent extent) { + super(extent); + this.worldEdit = worldEdit; + } + + @Override + public boolean test(BlockVector3 vector) { + Extent extent = getExtent(); + BlockType block = extent.getBlock(vector).getBlockType(); + return !worldEdit.getConfiguration().disallowedBlocks.contains(block.id()); + } + +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 23c1bdb1cf..efc260496e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -92,6 +92,8 @@ public void load() { profile = getBool("profile", profile); traceUnflushedSessions = getBool("trace-unflushed-sessions", traceUnflushedSessions); disallowedBlocks = getStringSet("disallowed-blocks", getDefaultDisallowedBlocks()); + disableDisallowedBlockCategories = getBool("disable-disallowed-block-categories", disableDisallowedBlockCategories); + disableDisallowedBlockCopying = getBool("disable-disallowed-block-copying", disableDisallowedBlockCopying); defaultChangeLimit = getInt("default-max-changed-blocks", defaultChangeLimit); maxChangeLimit = getInt("max-changed-blocks", maxChangeLimit); defaultVerticalHeight = getInt("default-vertical-height", defaultVerticalHeight); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index f2bea3c107..612dea597f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -84,6 +84,9 @@ public void load() { disallowedBlocks = new HashSet<>(config.getStringList("limits.disallowed-blocks", Lists.newArrayList(getDefaultDisallowedBlocks()))); allowedDataCycleBlocks = new HashSet<>(config.getStringList("limits.allowed-data-cycle-blocks", null)); + disableDisallowedBlockCategories = config.getBoolean("disallowed-blocks.disable-block-categories", disableDisallowedBlockCategories); + disableDisallowedBlockCopying = config.getBoolean("disallowed-blocks.disable-block-copying", disableDisallowedBlockCopying); + registerHelp = config.getBoolean("register-help", true); logCommands = config.getBoolean("logging.log-commands", logCommands); logFile = config.getString("logging.file", logFile); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/mask/BlockMaskUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/mask/BlockMaskUtil.java new file mode 100644 index 0000000000..3d11755d77 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/mask/BlockMaskUtil.java @@ -0,0 +1,54 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.util.mask; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.AllowedBlocksMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; + +public class BlockMaskUtil { + + /** + * Utility function to expand the masks of copying operations by the disallowed blocks list + * + * @param actor the actor issuing the copying operation + * @param mask a potential mask already set by the actor + * @param extent the extent + */ + public static Mask checkForAllowedBlocksMask(Actor actor, Mask mask, Extent extent) { + WorldEdit worldEdit = WorldEdit.getInstance(); + + if (worldEdit.getConfiguration().disableDisallowedBlockCopying + && actor != null + && !actor.hasPermission("worldedit.anyblock")) { + Mask allowedBlocksMask = new AllowedBlocksMask(worldEdit, extent); + + return (mask == null) + ? allowedBlocksMask + : new MaskIntersection(allowedBlocksMask, mask); + } + + return mask; + } + +} \ No newline at end of file diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index a635a5a617..48535e46af 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -379,6 +379,7 @@ "worldedit.error.empty-tag": "Tag name '{0}' has no contents.", "worldedit.error.no-match": "No match for '{0}'.", "worldedit.error.disallowed-block": "Block '{0}' not allowed (see WorldEdit configuration).", + "worldedit.error.disallowed-blocks": "Some of the specified blocks are not allowed.", "worldedit.error.max-changes": "Max blocks changed in an operation reached ({0}).", "worldedit.error.max-brush-radius": "Maximum brush radius (in configuration): {0}", "worldedit.error.max-radius": "Maximum radius (in configuration): {0}", diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java index 47b57a6821..b0983a7736 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java @@ -97,6 +97,9 @@ public void load() { logger.warn("Error loading WorldEdit configuration", e); } + disableDisallowedBlockCategories = node.node("disallowed-blocks", "disable-block-categories").getBoolean(disableDisallowedBlockCategories); + disableDisallowedBlockCopying = node.node("disallowed-blocks", "disable-block-copying").getBoolean(disableDisallowedBlockCopying); + registerHelp = node.node("register-help").getBoolean(true); logCommands = node.node("logging", "log-commands").getBoolean(logCommands); logFile = node.node("logging", "file").getString(logFile);