Search in sources :

Example 1 with RegionMask

use of com.sk89q.worldedit.function.mask.RegionMask in project FastAsyncWorldEdit by IntellectualSites.

the class ClipboardCommands method copy.

@Command(name = "/copy", aliases = "/cp", desc = "Copy the selection to the clipboard")
@CommandPermissions("worldedit.clipboard.copy")
@Preload(Preload.PreloadCheck.PRELOAD)
@Confirm(Confirm.Processor.REGION)
public void copy(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Switch(name = 'e', desc = "Also copy entities") boolean copyEntities, @Switch(name = 'b', desc = "Also copy biomes") boolean copyBiomes, // FAWE start
@Switch(name = 'c', desc = "Set the origin of the clipboard to the center of the region, at the region's lowest " + "y-level.") boolean centerClipboard, @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air", def = "") Mask mask) throws WorldEditException {
    BlockVector3 min = region.getMinimumPoint();
    BlockVector3 max = region.getMaximumPoint();
    long volume = ((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1);
    FaweLimit limit = actor.getLimit();
    if (volume >= limit.MAX_CHECKS) {
        throw FaweCache.MAX_CHECKS;
    }
    session.setClipboard(null);
    Clipboard clipboard = new BlockArrayClipboard(region, actor.getUniqueId());
    clipboard.setOrigin(centerClipboard ? region.getCenter().toBlockPoint().withY(region.getMinimumY()) : session.getPlacementPosition(actor));
    ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
    copy.setCopyingEntities(copyEntities);
    copy.setCopyingBiomes(copyBiomes);
    Mask sourceMask = editSession.getSourceMask();
    Region[] regions = editSession.getAllowedRegions();
    Region allowedRegion;
    if (regions == null || regions.length == 0) {
        allowedRegion = new NullRegion();
    } else {
        allowedRegion = new RegionIntersection(regions);
    }
    final Mask firstSourceMask = mask != null ? mask : sourceMask;
    final Mask finalMask = MaskIntersection.of(firstSourceMask, new RegionMask(allowedRegion)).optimize();
    if (finalMask != Masks.alwaysTrue()) {
        copy.setSourceMask(finalMask);
    }
    if (sourceMask != null) {
        editSession.setSourceMask(null);
        new MaskTraverser(sourceMask).reset(editSession);
        editSession.setSourceMask(null);
    }
    try {
        Operations.completeLegacy(copy);
    } catch (Throwable e) {
        throw e;
    } finally {
        clipboard.flush();
    }
    session.setClipboard(new ClipboardHolder(clipboard));
    copy.getStatusMessages().forEach(actor::print);
// FAWE end
}
Also used : BlockArrayClipboard(com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard) MultiClipboardHolder(com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder) URIClipboardHolder(com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder) ClipboardHolder(com.sk89q.worldedit.session.ClipboardHolder) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) ClipboardMask(com.sk89q.worldedit.internal.annotation.ClipboardMask) Mask(com.sk89q.worldedit.function.mask.Mask) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) MaskTraverser(com.fastasyncworldedit.core.util.MaskTraverser) BlockVector3(com.sk89q.worldedit.math.BlockVector3) ForwardExtentCopy(com.sk89q.worldedit.function.operation.ForwardExtentCopy) NullRegion(com.sk89q.worldedit.regions.NullRegion) RegionIntersection(com.sk89q.worldedit.regions.RegionIntersection) FaweLimit(com.fastasyncworldedit.core.limit.FaweLimit) NullRegion(com.sk89q.worldedit.regions.NullRegion) Region(com.sk89q.worldedit.regions.Region) DiskOptimizedClipboard(com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard) Clipboard(com.sk89q.worldedit.extent.clipboard.Clipboard) BlockArrayClipboard(com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard) ReadOnlyClipboard(com.fastasyncworldedit.core.extent.clipboard.ReadOnlyClipboard) Preload(com.sk89q.worldedit.command.util.annotation.Preload) Command(org.enginehub.piston.annotation.Command) Confirm(com.sk89q.worldedit.command.util.annotation.Confirm) CommandPermissions(com.sk89q.worldedit.command.util.CommandPermissions)

Example 2 with RegionMask

use of com.sk89q.worldedit.function.mask.RegionMask in project FastAsyncWorldEdit by IntellectualSites.

the class EditSession method fixLiquid.

/**
 * Fix liquids so that they turn into stationary blocks and extend outward.
 *
 * @param origin the original position
 * @param radius the radius to fix
 * @param fluid  the type of the fluid
 * @return number of blocks affected
 * @throws MaxChangedBlocksException thrown if too many blocks are changed
 */
public int fixLiquid(BlockVector3 origin, double radius, BlockType fluid) throws MaxChangedBlocksException {
    checkNotNull(origin);
    checkArgument(radius >= 0, "radius >= 0 required");
    // Our origins can only be liquids
    Mask liquidMask = new SingleBlockTypeMask(this, fluid);
    // But we will also visit air blocks
    MaskIntersection blockMask = new MaskUnion(liquidMask, Masks.negate(new ExistingBlockMask(this)));
    // There are boundaries that the routine needs to stay in
    Mask mask = new MaskIntersection(new BoundedHeightMask(minY, Math.min(origin.getBlockY(), maxY)), new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), blockMask);
    BlockReplace replace = new BlockReplace(this, fluid.getDefaultState());
    // FAWE start - provide extent for preloading, world min/maxY
    NonRisingVisitor visitor = new NonRisingVisitor(mask, replace, Integer.MAX_VALUE, minY, maxY, this);
    // Around the origin in a 3x3 block
    for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) {
        if (liquidMask.test(position)) {
            visitor.visit(position);
        }
    }
    Operations.completeLegacy(visitor);
    return visitor.getAffected();
}
Also used : MaskIntersection(com.sk89q.worldedit.function.mask.MaskIntersection) SingleBlockTypeMask(com.fastasyncworldedit.core.function.mask.SingleBlockTypeMask) NonRisingVisitor(com.sk89q.worldedit.function.visitor.NonRisingVisitor) BlockTypeMask(com.sk89q.worldedit.function.mask.BlockTypeMask) SingleBlockTypeMask(com.fastasyncworldedit.core.function.mask.SingleBlockTypeMask) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) BlockStateMask(com.sk89q.worldedit.function.mask.BlockStateMask) WallMakeMask(com.fastasyncworldedit.core.function.mask.WallMakeMask) ExistingBlockMask(com.sk89q.worldedit.function.mask.ExistingBlockMask) BoundedHeightMask(com.sk89q.worldedit.function.mask.BoundedHeightMask) ResettableMask(com.fastasyncworldedit.core.function.mask.ResettableMask) Mask(com.sk89q.worldedit.function.mask.Mask) MaskUnion(com.fastasyncworldedit.core.function.mask.MaskUnion) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) ExistingBlockMask(com.sk89q.worldedit.function.mask.ExistingBlockMask) MutableBlockVector3(com.fastasyncworldedit.core.math.MutableBlockVector3) BlockVector3(com.sk89q.worldedit.math.BlockVector3) BoundedHeightMask(com.sk89q.worldedit.function.mask.BoundedHeightMask) BlockReplace(com.sk89q.worldedit.function.block.BlockReplace) EllipsoidRegion(com.sk89q.worldedit.regions.EllipsoidRegion)

Example 3 with RegionMask

use of com.sk89q.worldedit.function.mask.RegionMask in project FastAsyncWorldEdit by IntellectualSites.

the class EditSession method fillXZ.

/**
 * Fills an area recursively in the X/Z directions.
 *
 * @param origin    the origin to start the fill from
 * @param pattern   the pattern to fill with
 * @param radius    the radius of the spherical area to fill, with 0 as the smallest radius
 * @param depth     the maximum depth, starting from the origin, with 1 as the smallest depth
 * @param recursive whether a breadth-first search should be performed
 * @return number of blocks affected
 * @throws MaxChangedBlocksException thrown if too many blocks are changed
 */
public int fillXZ(BlockVector3 origin, Pattern pattern, double radius, int depth, boolean recursive) throws MaxChangedBlocksException {
    checkNotNull(origin);
    checkNotNull(pattern);
    checkArgument(radius >= 0, "radius >= 0");
    checkArgument(depth >= 1, "depth >= 1");
    Mask mask = new MaskIntersection(new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), new BoundedHeightMask(Math.max(origin.getBlockY() - depth + 1, minY), Math.min(maxY, origin.getBlockY())), Masks.negate(new ExistingBlockMask(this)));
    // Want to replace blocks
    BlockReplace replace = new BlockReplace(this, pattern);
    // Pick how we're going to visit blocks
    RecursiveVisitor visitor;
    // FAWE start - provide extent for preloading, min/max y
    if (recursive) {
        visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), minY, maxY, this);
    } else {
        visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), minY, maxY, this);
    }
    // FAWE end
    // Start at the origin
    visitor.visit(origin);
    // Execute
    Operations.completeLegacy(visitor);
    // FAWE start
    return this.changes = visitor.getAffected();
// FAWE end
}
Also used : MaskIntersection(com.sk89q.worldedit.function.mask.MaskIntersection) BlockTypeMask(com.sk89q.worldedit.function.mask.BlockTypeMask) SingleBlockTypeMask(com.fastasyncworldedit.core.function.mask.SingleBlockTypeMask) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) BlockStateMask(com.sk89q.worldedit.function.mask.BlockStateMask) WallMakeMask(com.fastasyncworldedit.core.function.mask.WallMakeMask) ExistingBlockMask(com.sk89q.worldedit.function.mask.ExistingBlockMask) BoundedHeightMask(com.sk89q.worldedit.function.mask.BoundedHeightMask) ResettableMask(com.fastasyncworldedit.core.function.mask.ResettableMask) Mask(com.sk89q.worldedit.function.mask.Mask) RecursiveVisitor(com.sk89q.worldedit.function.visitor.RecursiveVisitor) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) ExistingBlockMask(com.sk89q.worldedit.function.mask.ExistingBlockMask) DownwardVisitor(com.sk89q.worldedit.function.visitor.DownwardVisitor) BoundedHeightMask(com.sk89q.worldedit.function.mask.BoundedHeightMask) BlockReplace(com.sk89q.worldedit.function.block.BlockReplace) EllipsoidRegion(com.sk89q.worldedit.regions.EllipsoidRegion)

Example 4 with RegionMask

use of com.sk89q.worldedit.function.mask.RegionMask in project FastAsyncWorldEdit by IntellectualSites.

the class ClipboardCommands method cut.

/*
    @Command(
        name = "/lazycut",
        desc = "Lazily cut the selection to the clipboard"
    )
    @CommandPermissions("worldedit.clipboard.lazycut")
    public void lazyCut(Actor actor, LocalSession session, EditSession editSession,
                        @Selection final Region region,
                        @Switch(name = 'e', desc = "Skip copy entities")
                            boolean skipEntities,
                        @ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
                            Mask maskOpt,
                        @Switch(name = 'b', desc = "Also copy biomes")
                            boolean copyBiomes) throws WorldEditException {
        BlockVector3 min = region.getMinimumPoint();
        BlockVector3 max = region.getMaximumPoint();
        long volume = ((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1);
        FaweLimit limit = actor.getLimit();
        if (volume >= limit.MAX_CHECKS) {
            throw FaweCache.MAX_CHECKS;
        }
        if (volume >= limit.MAX_CHANGES) {
            throw FaweCache.MAX_CHANGES;
        }
        session.setClipboard(null);

        ReadOnlyClipboard lazyClipboard = new WorldCutClipboard(editSession, region, !skipEntities, copyBiomes);
        clipboard.setOrigin(session.getPlacementPosition(actor));
        session.setClipboard(new ClipboardHolder(lazyClipboard));
        actor.print(Caption.of("fawe.worldedit.cut.command.cut.lazy", region.getArea()));
    }*/
// FAWE end
@Command(name = "/cut", desc = "Cut the selection to the clipboard", descFooter = "WARNING: Cutting and pasting entities cannot be undone!")
@CommandPermissions("worldedit.clipboard.cut")
@Logging(REGION)
@Preload(Preload.PreloadCheck.PRELOAD)
@Confirm(Confirm.Processor.REGION)
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, @Switch(name = 'e', desc = "Also cut entities") boolean copyEntities, @Switch(name = 'b', desc = "Also copy biomes, source biomes are unaffected") boolean copyBiomes, @ArgFlag(name = 'm', desc = "Set the exclude mask, non-matching blocks become air") Mask mask) throws WorldEditException {
    // FAWE start - Inject limits & respect source mask
    BlockVector3 min = region.getMinimumPoint();
    BlockVector3 max = region.getMaximumPoint();
    long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1));
    FaweLimit limit = actor.getLimit();
    if (volume >= limit.MAX_CHECKS) {
        throw FaweCache.MAX_CHECKS;
    }
    if (volume >= limit.MAX_CHANGES) {
        throw FaweCache.MAX_CHANGES;
    }
    session.setClipboard(null);
    BlockArrayClipboard clipboard = new BlockArrayClipboard(region, actor.getUniqueId());
    clipboard.setOrigin(session.getPlacementPosition(actor));
    ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
    copy.setSourceFunction(new BlockReplace(editSession, leavePattern));
    copy.setCopyingEntities(copyEntities);
    copy.setRemovingEntities(true);
    copy.setCopyingBiomes(copyBiomes);
    Mask sourceMask = editSession.getSourceMask();
    Region[] regions = editSession.getAllowedRegions();
    Region allowedRegion;
    if (regions == null || regions.length == 0) {
        allowedRegion = new NullRegion();
    } else {
        allowedRegion = new RegionIntersection(regions);
    }
    final Mask firstSourceMask = mask != null ? mask : sourceMask;
    final Mask finalMask = MaskIntersection.of(firstSourceMask, new RegionMask(allowedRegion)).optimize();
    if (finalMask != Masks.alwaysTrue()) {
        copy.setSourceMask(finalMask);
    }
    if (sourceMask != null) {
        editSession.setSourceMask(null);
        new MaskTraverser(sourceMask).reset(editSession);
        editSession.setSourceMask(null);
    }
    try {
        Operations.completeLegacy(copy);
    } catch (Throwable e) {
        throw e;
    } finally {
        clipboard.flush();
    }
    session.setClipboard(new ClipboardHolder(clipboard));
    if (!actor.hasPermission("fawe.tips")) {
        actor.print(Caption.of("fawe.tips.tip.lazycut"));
    }
    copy.getStatusMessages().forEach(actor::print);
// FAWE end
}
Also used : BlockArrayClipboard(com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard) MultiClipboardHolder(com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder) URIClipboardHolder(com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder) ClipboardHolder(com.sk89q.worldedit.session.ClipboardHolder) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) ClipboardMask(com.sk89q.worldedit.internal.annotation.ClipboardMask) Mask(com.sk89q.worldedit.function.mask.Mask) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) MaskTraverser(com.fastasyncworldedit.core.util.MaskTraverser) BlockVector3(com.sk89q.worldedit.math.BlockVector3) BlockReplace(com.sk89q.worldedit.function.block.BlockReplace) ForwardExtentCopy(com.sk89q.worldedit.function.operation.ForwardExtentCopy) NullRegion(com.sk89q.worldedit.regions.NullRegion) RegionIntersection(com.sk89q.worldedit.regions.RegionIntersection) FaweLimit(com.fastasyncworldedit.core.limit.FaweLimit) NullRegion(com.sk89q.worldedit.regions.NullRegion) Region(com.sk89q.worldedit.regions.Region) Logging(com.sk89q.worldedit.command.util.Logging) Preload(com.sk89q.worldedit.command.util.annotation.Preload) Command(org.enginehub.piston.annotation.Command) Confirm(com.sk89q.worldedit.command.util.annotation.Confirm) CommandPermissions(com.sk89q.worldedit.command.util.CommandPermissions)

Example 5 with RegionMask

use of com.sk89q.worldedit.function.mask.RegionMask in project FastAsyncWorldEdit by IntellectualSites.

the class EditSession method moveRegion.

/**
 * Move the blocks in a region a certain direction.
 *
 * @param region       the region to move
 * @param offset       the offset. Is directional.
 * @param multiplier   the number to multiply the offset by
 * @param moveEntities true to move entities
 * @param copyBiomes   true to copy biomes (source biome is unchanged)
 * @param mask         source mask for the operation (only matching blocks are moved)
 * @param replacement  the replacement pattern to fill in after moving, or null to use air
 * @return number of blocks moved
 * @throws MaxChangedBlocksException thrown if too many blocks are changed
 * @throws IllegalArgumentException  thrown if the region is not a flat region, but copyBiomes is true
 */
public int moveRegion(Region region, BlockVector3 offset, int multiplier, boolean moveEntities, boolean copyBiomes, Mask mask, Pattern replacement) throws MaxChangedBlocksException {
    checkNotNull(region);
    checkNotNull(offset);
    checkArgument(multiplier >= 1, "distance >= 1 required");
    checkArgument(!copyBiomes || region instanceof FlatRegion, "can't copy biomes from non-flat region");
    // FAWE start - add up distance
    BlockVector3 to = region.getMinimumPoint().add(offset.multiply(multiplier));
    final BlockVector3 displace = offset.multiply(multiplier);
    final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1);
    BlockVector3 disAbs = displace.abs();
    if (disAbs.getBlockX() < size.getBlockX() && disAbs.getBlockY() < size.getBlockY() && disAbs.getBlockZ() < size.getBlockZ()) {
        // Buffer if overlapping
        enableQueue();
    }
    ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to);
    if (replacement == null) {
        replacement = BlockTypes.AIR.getDefaultState();
    }
    BlockReplace remove = replacement instanceof ExistingPattern ? null : new BlockReplace(this, replacement);
    // Remove
    copy.setSourceFunction(remove);
    copy.setCopyingEntities(moveEntities);
    copy.setRemovingEntities(moveEntities);
    copy.setCopyingBiomes(copyBiomes);
    copy.setRepetitions(1);
    final Region allowedRegion;
    if (allowedRegions == null || allowedRegions.length == 0) {
        allowedRegion = new NullRegion();
    } else {
        allowedRegion = new RegionIntersection(allowedRegions);
    }
    Mask sourceMask = this.getSourceMask();
    mask = MaskIntersection.of(sourceMask, mask, new RegionMask(allowedRegion)).optimize();
    if (mask != Masks.alwaysTrue()) {
        copy.setSourceMask(mask);
        if (sourceMask != null && sourceMask.equals(mask)) {
            setSourceMask(null);
        }
    }
    Operations.completeBlindly(copy);
    return this.changes = copy.getAffected();
// FAWE end
}
Also used : ExistingPattern(com.fastasyncworldedit.core.function.pattern.ExistingPattern) RegionIntersection(com.sk89q.worldedit.regions.RegionIntersection) FlatRegion(com.sk89q.worldedit.regions.FlatRegion) Regions.asFlatRegion(com.sk89q.worldedit.regions.Regions.asFlatRegion) BlockTypeMask(com.sk89q.worldedit.function.mask.BlockTypeMask) SingleBlockTypeMask(com.fastasyncworldedit.core.function.mask.SingleBlockTypeMask) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) BlockStateMask(com.sk89q.worldedit.function.mask.BlockStateMask) WallMakeMask(com.fastasyncworldedit.core.function.mask.WallMakeMask) ExistingBlockMask(com.sk89q.worldedit.function.mask.ExistingBlockMask) BoundedHeightMask(com.sk89q.worldedit.function.mask.BoundedHeightMask) ResettableMask(com.fastasyncworldedit.core.function.mask.ResettableMask) Mask(com.sk89q.worldedit.function.mask.Mask) CuboidRegion(com.sk89q.worldedit.regions.CuboidRegion) CylinderRegion(com.sk89q.worldedit.regions.CylinderRegion) EllipsoidRegion(com.sk89q.worldedit.regions.EllipsoidRegion) FlatRegion(com.sk89q.worldedit.regions.FlatRegion) NullRegion(com.sk89q.worldedit.regions.NullRegion) Region(com.sk89q.worldedit.regions.Region) Regions.asFlatRegion(com.sk89q.worldedit.regions.Regions.asFlatRegion) RegionMask(com.sk89q.worldedit.function.mask.RegionMask) MutableBlockVector3(com.fastasyncworldedit.core.math.MutableBlockVector3) BlockVector3(com.sk89q.worldedit.math.BlockVector3) BlockReplace(com.sk89q.worldedit.function.block.BlockReplace) ForwardExtentCopy(com.sk89q.worldedit.function.operation.ForwardExtentCopy) NullRegion(com.sk89q.worldedit.regions.NullRegion)

Aggregations

RegionMask (com.sk89q.worldedit.function.mask.RegionMask)8 Mask (com.sk89q.worldedit.function.mask.Mask)7 BlockReplace (com.sk89q.worldedit.function.block.BlockReplace)6 BlockVector3 (com.sk89q.worldedit.math.BlockVector3)6 EllipsoidRegion (com.sk89q.worldedit.regions.EllipsoidRegion)6 ResettableMask (com.fastasyncworldedit.core.function.mask.ResettableMask)5 SingleBlockTypeMask (com.fastasyncworldedit.core.function.mask.SingleBlockTypeMask)5 WallMakeMask (com.fastasyncworldedit.core.function.mask.WallMakeMask)5 BlockStateMask (com.sk89q.worldedit.function.mask.BlockStateMask)5 BlockTypeMask (com.sk89q.worldedit.function.mask.BlockTypeMask)5 BoundedHeightMask (com.sk89q.worldedit.function.mask.BoundedHeightMask)5 ExistingBlockMask (com.sk89q.worldedit.function.mask.ExistingBlockMask)5 MutableBlockVector3 (com.fastasyncworldedit.core.math.MutableBlockVector3)4 MaskIntersection (com.sk89q.worldedit.function.mask.MaskIntersection)4 ForwardExtentCopy (com.sk89q.worldedit.function.operation.ForwardExtentCopy)4 NullRegion (com.sk89q.worldedit.regions.NullRegion)4 Region (com.sk89q.worldedit.regions.Region)4 RegionIntersection (com.sk89q.worldedit.regions.RegionIntersection)4 RecursiveVisitor (com.sk89q.worldedit.function.visitor.RecursiveVisitor)3 MultiClipboardHolder (com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder)2