diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java index c978a14f..7567cb16 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java @@ -39,6 +39,7 @@ public abstract class BukkitQueue_0 extends NMSMa public static BukkitImplAdapter adapter; public static Method methodToNative; public static Method methodFromNative; + private static boolean setupAdapter = false; public BukkitQueue_0(final com.sk89q.worldedit.world.World world) { super(world); @@ -137,6 +138,9 @@ public abstract class BukkitQueue_0 extends NMSMa public static void setupAdapter(BukkitImplAdapter adapter) { try { + if (setupAdapter == (setupAdapter = true)) { + return; + } WorldEditPlugin instance = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"); Field fieldAdapter = WorldEditPlugin.class.getDeclaredField("bukkitAdapter"); fieldAdapter.setAccessible(true); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/RandomClipboardHolder.java b/core/src/main/java/com/boydti/fawe/object/clipboard/RandomClipboardHolder.java new file mode 100644 index 00000000..120b7314 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/RandomClipboardHolder.java @@ -0,0 +1,12 @@ +package com.boydti.fawe.object.clipboard; + +import com.google.common.io.ByteSource; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.world.registry.WorldData; +import java.util.UUID; + +public class RandomClipboardHolder extends LazyClipboardHolder { + public RandomClipboardHolder(ByteSource source, ClipboardFormat format, WorldData worldData, UUID uuid) { + super(source, format, worldData, uuid); + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java b/core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java index 130af219..fd311690 100644 --- a/core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java +++ b/core/src/main/java/com/boydti/fawe/object/pattern/FullClipboardPattern.java @@ -2,6 +2,7 @@ package com.boydti.fawe.object.pattern; import com.sk89q.worldedit.MutableBlockVector; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -20,8 +21,6 @@ import static com.google.common.base.Preconditions.checkNotNull; public class FullClipboardPattern extends AbstractPattern { private final Extent extent; private final Clipboard clipboard; - private final BaseBlock block; - private final MutableBlockVector mutable = new MutableBlockVector(); /** @@ -33,16 +32,19 @@ public class FullClipboardPattern extends AbstractPattern { checkNotNull(clipboard); this.clipboard = clipboard; this.extent = extent; - Vector origin = clipboard.getOrigin(); - block = clipboard.getBlock(origin); } @Override - public BaseBlock apply(Vector to) { + public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException { Region region = clipboard.getRegion(); - ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, to); + ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, setPosition); copy.setSourceMask(new ExistingBlockMask(clipboard)); Operations.completeBlindly(copy); - return block; + return true; + } + + @Override + public BaseBlock apply(Vector position) { + throw new IllegalStateException("Incorrect use. This pattern can only be applied to an extent!"); } } \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java b/core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java new file mode 100644 index 00000000..09ce1ea8 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java @@ -0,0 +1,54 @@ +package com.boydti.fawe.object.pattern; + +import com.boydti.fawe.object.PseudoRandom; +import com.boydti.fawe.object.schematic.Schematic; +import com.sk89q.worldedit.MutableBlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.pattern.AbstractPattern; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.world.registry.WorldData; + + +import static com.google.common.base.Preconditions.checkNotNull; + +public class RandomFullClipboardPattern extends AbstractPattern { + private final Extent extent; + private final ClipboardHolder[] clipboards; + private final MutableBlockVector mutable = new MutableBlockVector(); + private boolean randomRotate; + private WorldData worldData; + + public RandomFullClipboardPattern(Extent extent, WorldData worldData, ClipboardHolder[] clipboards, boolean randomRotate) { + checkNotNull(clipboards); + this.clipboards = clipboards; + this.extent = extent; + this.randomRotate = randomRotate; + this.worldData = worldData; + } + + @Override + public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException { + ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)]; + if (randomRotate) { + holder.setTransform(new AffineTransform().rotateY(PseudoRandom.random.random(4) * 90)); + } + Clipboard clipboard = holder.getClipboard(); + Schematic schematic = new Schematic(clipboard); + if (holder.getTransform().isIdentity()) { + schematic.paste(extent, setPosition, false); + } else { + schematic.paste(extent, worldData, setPosition, false, holder.getTransform()); + } + return true; + } + + @Override + public BaseBlock apply(Vector position) { + throw new IllegalStateException("Incorrect use. This pattern can only be applied to an extent!"); + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java b/core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java index 1d055379..2f20424f 100644 --- a/core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java +++ b/core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java @@ -1,24 +1,34 @@ package com.boydti.fawe.object.schematic; +import com.boydti.fawe.object.HasFaweQueue; +import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.clipboard.ReadOnlyClipboard; import com.boydti.fawe.util.EditSessionBuilder; import com.boydti.fawe.util.MaskTraverser; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.extent.transform.BlockTransformExtent; +import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.registry.WorldData; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -133,4 +143,77 @@ public class Schematic { editSession.flushQueue(); return editSession; } + + public void paste(Extent extent, WorldData worldData, Vector to, boolean pasteAir, Transform transform) { + Region region = clipboard.getRegion(); + BlockTransformExtent source = new BlockTransformExtent(clipboard, transform, worldData.getBlockRegistry()); + ForwardExtentCopy copy = new ForwardExtentCopy(source, clipboard.getRegion(), clipboard.getOrigin(), extent, to); + copy.setTransform(transform); + if (!pasteAir) { + copy.setSourceMask(new ExistingBlockMask(clipboard)); + } + Operations.completeBlindly(copy); + } + + public void paste(Extent extent, Vector to, boolean pasteAir) { + Region region = clipboard.getRegion().clone(); + final int maxY = extent.getMaximumPoint().getBlockY(); + final Vector bot = clipboard.getMinimumPoint(); + final Vector origin = clipboard.getOrigin(); + // Optimize for BlockArrayClipboard + if (clipboard instanceof BlockArrayClipboard && region instanceof CuboidRegion) { + // To is relative to the world origin (player loc + small clipboard offset) (As the positions supplied are relative to the clipboard min) + final int relx = to.getBlockX() + bot.getBlockX() - origin.getBlockX(); + final int rely = to.getBlockY() + bot.getBlockY() - origin.getBlockY(); + final int relz = to.getBlockZ() + bot.getBlockZ() - origin.getBlockZ(); + BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; + bac.IMP.forEach(new RunnableVal2() { + @Override + public void run(Vector mutable, BaseBlock block) { + mutable.mutX(mutable.getX() + relx); + mutable.mutY(mutable.getY() + rely); + mutable.mutZ(mutable.getZ() + relz); + if (mutable.getY() >= 0 && mutable.getY() <= maxY) { + try { + extent.setBlock(mutable, block); + } catch (WorldEditException e) { + throw new RuntimeException(e); + } + } + } + }, pasteAir); + } else { + // To must be relative to the clipboard origin ( player location - clipboard origin ) (as the locations supplied are relative to the world origin) + final int relx = to.getBlockX() - origin.getBlockX(); + final int rely = to.getBlockY() - origin.getBlockY(); + final int relz = to.getBlockZ() - origin.getBlockZ(); + RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() { + @Override + public boolean apply(Vector mutable) throws WorldEditException { + BaseBlock block = clipboard.getBlock(mutable); + if (block == EditSession.nullBlock && !pasteAir) { + return false; + } + mutable.mutX(mutable.getX() + relx); + mutable.mutY(mutable.getY() + rely); + mutable.mutZ(mutable.getZ() + relz); + if (mutable.getY() >= 0 && mutable.getY() <= maxY) { + return extent.setBlock(mutable, block); + } + return false; + } + }, (HasFaweQueue) (extent instanceof HasFaweQueue ? extent : null)); + Operations.completeBlindly(visitor); + } + // Entity offset is the paste location subtract the clipboard origin (entity's location is already relative to the world origin) + final int entityOffsetX = to.getBlockX() - origin.getBlockX(); + final int entityOffsetY = to.getBlockY() - origin.getBlockY(); + final int entityOffsetZ = to.getBlockZ() - origin.getBlockZ(); + // entities + for (Entity entity : clipboard.getEntities()) { + Location pos = entity.getLocation(); + Location newPos = new Location(pos.getExtent(), pos.getX() + entityOffsetX, pos.getY() + entityOffsetY, pos.getZ() + entityOffsetZ, pos.getYaw(), pos.getPitch()); + extent.createEntity(newPos, entity.getState()); + } + } } diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 228c9fdb..b94576bc 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -50,12 +50,8 @@ import com.boydti.fawe.object.brush.scroll.ScrollRange; import com.boydti.fawe.object.brush.scroll.ScrollSize; import com.boydti.fawe.object.brush.scroll.ScrollTarget; import com.boydti.fawe.object.brush.visualization.VisualMode; -import com.boydti.fawe.object.clipboard.LazyClipboardHolder; -import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.mask.IdMask; import com.boydti.fawe.util.MathMan; -import com.google.common.io.ByteSource; -import com.google.common.io.Files; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; @@ -93,9 +89,7 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; -import com.sk89q.worldedit.world.registry.WorldData; import java.io.File; -import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -103,10 +97,6 @@ import java.io.InputStream; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; -import java.util.ArrayList; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; import static com.google.common.base.Preconditions.checkNotNull; @@ -237,71 +227,11 @@ public class BrushCommands { } String filename = args.getString(1); try { - WorldData worldData = player.getWorld().getWorldData(); - if (filename.startsWith("http")) { - URL url = new URL(filename); - URL webInterface = new URL(Settings.IMP.WEB.ASSETS); - if (!url.getHost().equalsIgnoreCase(webInterface.getHost())) { - BBC.WEB_UNAUTHORIZED.send(player, url); - return; - } - List clipboards = new ArrayList<>(); - try (ReadableByteChannel rbc = Channels.newChannel(url.openStream())) { - try (InputStream in = Channels.newInputStream(rbc)) { - try (ZipInputStream zip = new ZipInputStream(in)) { - ZipEntry entry; - byte[] buffer = new byte[8192]; - while ((entry = zip.getNextEntry()) != null) { - if (entry.getName().endsWith(".schematic")) { - FastByteArrayOutputStream out = new FastByteArrayOutputStream(); - int len = 0; - while ((len = zip.read(buffer)) > 0) { - out.write(buffer, 0, len); - } - byte[] array = out.toByteArray(); - ByteSource source = ByteSource.wrap(array); - LazyClipboardHolder clipboard = new LazyClipboardHolder(source, ClipboardFormat.SCHEMATIC, worldData, null); - clipboards.add(clipboard); - } - } - } - } - } - tool.setScrollAction(new ScrollClipboard(tool, session, clipboards.toArray(new LazyClipboardHolder[clipboards.size()]))); - } else { - if (filename.contains("../") && !player.hasPermission("worldedit.schematic.load.other")) { - BBC.NO_PERM.send(player, "worldedit.schematic.load.other"); - return; - } - File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir); - File dir = new File(working, (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? (player.getUniqueId().toString() + File.separator) : "") + filename); - if (!dir.exists()) { - if ((!filename.contains("/") && !filename.contains("\\")) || player.hasPermission("worldedit.schematic.load.other")) { - dir = new File(this.worldEdit.getWorkingDirectoryFile(config.saveDir), filename); - } - } - if (!dir.exists() || !dir.isDirectory()) { - BBC.SCHEMATIC_NOT_FOUND.send(player, filename); - return; - } - File[] files = dir.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.getName().endsWith(".schematic"); - } - }); - if (files.length < 1) { - BBC.SCHEMATIC_NOT_FOUND.send(player, filename); - return; - } - LazyClipboardHolder[] clipboards = new LazyClipboardHolder[files.length]; - for (int i = 0; i < files.length; i++) { - File file = files[i]; - ByteSource source = Files.asByteSource(file); - clipboards[i] = new LazyClipboardHolder(source, ClipboardFormat.SCHEMATIC, worldData, null); - } - tool.setScrollAction(new ScrollClipboard(tool, session, clipboards)); + ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), filename, true); + if (clipboards == null) { + return; } + tool.setScrollAction(new ScrollClipboard(tool, session, clipboards)); break; } catch (IOException e) { throw new RuntimeException(e); diff --git a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index a9594775..f67bbd36 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -24,11 +24,11 @@ import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FawePlayer; -import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.clipboard.ReadOnlyClipboard; import com.boydti.fawe.object.clipboard.WorldCutClipboard; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.io.FastByteArrayOutputStream; +import com.boydti.fawe.object.schematic.Schematic; import com.boydti.fawe.util.ImgurUtility; import com.boydti.fawe.util.MaskTraverser; import com.sk89q.minecraft.util.commands.Command; @@ -40,14 +40,11 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; -import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; @@ -55,17 +52,14 @@ import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; -import com.sk89q.worldedit.regions.CuboidRegion; 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.util.Location; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; import java.io.IOException; @@ -373,7 +367,6 @@ public class ClipboardCommands { place(player, session, editSession, ignoreAirBlocks, atOrigin, selectPasted); return; } - Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); Vector to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); @@ -420,63 +413,13 @@ public class ClipboardCommands { @Switch('s') boolean selectPasted) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); final Clipboard clipboard = holder.getClipboard(); - Region region = clipboard.getRegion().clone(); - - final int maxY = editSession.getMaxY(); - final Vector bot = clipboard.getMinimumPoint(); final Vector origin = clipboard.getOrigin(); final Vector to = atOrigin ? origin : session.getPlacementPosition(player); - // Optimize for BlockArrayClipboard - if (clipboard instanceof BlockArrayClipboard && region instanceof CuboidRegion) { - // To is relative to the world origin (player loc + small clipboard offset) (As the positions supplied are relative to the clipboard min) - final int relx = to.getBlockX() + bot.getBlockX() - origin.getBlockX(); - final int rely = to.getBlockY() + bot.getBlockY() - origin.getBlockY(); - final int relz = to.getBlockZ() + bot.getBlockZ() - origin.getBlockZ(); - BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; - bac.IMP.forEach(new RunnableVal2() { - @Override - public void run(Vector mutable, BaseBlock block) { - mutable.mutX(mutable.getX() + relx); - mutable.mutY(mutable.getY() + rely); - mutable.mutZ(mutable.getZ() + relz); - if (mutable.getY() >= 0 && mutable.getY() <= maxY) { - editSession.setBlockFast(mutable, block); - } - } - }, !ignoreAirBlocks); - } else { - // To must be relative to the clipboard origin ( player location - clipboard origin ) (as the locations supplied are relative to the world origin) - final int relx = to.getBlockX() - origin.getBlockX(); - final int rely = to.getBlockY() - origin.getBlockY(); - final int relz = to.getBlockZ() - origin.getBlockZ(); - RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() { - @Override - public boolean apply(Vector mutable) throws WorldEditException { - BaseBlock block = clipboard.getBlock(mutable); - if (block == EditSession.nullBlock && ignoreAirBlocks) { - return false; - } - mutable.mutX(mutable.getX() + relx); - mutable.mutY(mutable.getY() + rely); - mutable.mutZ(mutable.getZ() + relz); - if (mutable.getY() >= 0 && mutable.getY() <= maxY) { - return editSession.setBlockFast(mutable, block); - } - return false; - } - }, editSession); - Operations.completeBlindly(visitor); - } - // Entity offset is the paste location subtract the clipboard origin (entity's location is already relative to the world origin) - final int entityOffsetX = to.getBlockX() - origin.getBlockX(); - final int entityOffsetY = to.getBlockY() - origin.getBlockY(); - final int entityOffsetZ = to.getBlockZ() - origin.getBlockZ(); - // entities - for (Entity entity : clipboard.getEntities()) { - Location pos = entity.getLocation(); - Location newPos = new Location(pos.getExtent(), pos.getX() + entityOffsetX, pos.getY() + entityOffsetY, pos.getZ() + entityOffsetZ, pos.getYaw(), pos.getPitch()); - editSession.createEntity(newPos, entity.getState()); - } + + Schematic schem = new Schematic(clipboard); + schem.paste(editSession, to, !ignoreAirBlocks); + + Region region = clipboard.getRegion().clone(); if (selectPasted) { Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint())); RegionSelector selector = new CuboidRegionSelector(player.getWorld(), to, max); diff --git a/core/src/main/java/com/sk89q/worldedit/extension/factory/HashTagPatternParser.java b/core/src/main/java/com/sk89q/worldedit/extension/factory/HashTagPatternParser.java index d0c36180..42e16420 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/factory/HashTagPatternParser.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/factory/HashTagPatternParser.java @@ -2,7 +2,25 @@ package com.sk89q.worldedit.extension.factory; import com.boydti.fawe.command.FaweParser; import com.boydti.fawe.command.SuggestInputParseException; -import com.boydti.fawe.object.pattern.*; +import com.boydti.fawe.object.pattern.BiomePattern; +import com.boydti.fawe.object.pattern.DataPattern; +import com.boydti.fawe.object.pattern.ExistingPattern; +import com.boydti.fawe.object.pattern.ExpressionPattern; +import com.boydti.fawe.object.pattern.FullClipboardPattern; +import com.boydti.fawe.object.pattern.IdPattern; +import com.boydti.fawe.object.pattern.Linear3DBlockPattern; +import com.boydti.fawe.object.pattern.LinearBlockPattern; +import com.boydti.fawe.object.pattern.MaskedPattern; +import com.boydti.fawe.object.pattern.NoXPattern; +import com.boydti.fawe.object.pattern.NoYPattern; +import com.boydti.fawe.object.pattern.NoZPattern; +import com.boydti.fawe.object.pattern.OffsetPattern; +import com.boydti.fawe.object.pattern.PatternExtent; +import com.boydti.fawe.object.pattern.RandomFullClipboardPattern; +import com.boydti.fawe.object.pattern.RandomOffsetPattern; +import com.boydti.fawe.object.pattern.RelativePattern; +import com.boydti.fawe.object.pattern.SolidRandomOffsetPattern; +import com.boydti.fawe.object.pattern.SurfaceRandomOffsetPattern; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.StringMan; import com.sk89q.worldedit.EditSession; @@ -14,6 +32,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.ClipboardPattern; @@ -29,6 +48,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.biome.Biomes; import com.sk89q.worldedit.world.registry.BiomeRegistry; import com.sk89q.worldedit.world.registry.BundledBlockData; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -97,25 +117,13 @@ public class HashTagPatternParser extends FaweParser { } switch (input.toLowerCase().charAt(0)) { case '#': { - switch (input) { + String[] split2 = input.split(":"); + String rest = split2.length > 1 ? input.substring(split2[0].length() + 1) : ""; + switch (split2[0].toLowerCase()) { case "#*": case "#existing": { return new ExistingPattern(Request.request().getEditSession()); } - case "#fullcopy": { - LocalSession session = context.requireSession(); - if (session != null) { - try { - ClipboardHolder holder = session.getClipboard(); - Clipboard clipboard = holder.getClipboard(); - return new FullClipboardPattern(Request.request().getEditSession(), clipboard); - } catch (EmptyClipboardException e) { - throw new InputParseException("To use #fullcopy, please first copy something to your clipboard"); - } - } else { - throw new InputParseException("No session is available, so no clipboard is available"); - } - } case "#clipboard": case "#copy": { LocalSession session = context.requireSession(); @@ -131,141 +139,163 @@ public class HashTagPatternParser extends FaweParser { throw new InputParseException("No session is available, so no clipboard is available"); } } - } - String[] split2 = input.split(":"); - if (split2.length > 1 || input.endsWith(":")) { - String rest = input.substring(split2[0].length() + 1); - switch (split2[0].toLowerCase()) { - case "#id": { - return new IdPattern(Request.request().getEditSession(), catchSuggestion(input, rest, context)); - } - case "#data": { - return new DataPattern(Request.request().getEditSession(), catchSuggestion(input, rest, context)); - } - case "#biome": { - World world = context.getWorld(); - BiomeRegistry biomeRegistry = world.getWorldData().getBiomeRegistry(); - List knownBiomes = biomeRegistry.getBiomes(); - BaseBiome biome = Biomes.findBiomeByName(knownBiomes, rest, biomeRegistry); - return new BiomePattern(Request.request().getEditSession(), biome); - } - case "#~": - case "#r": - case "#relative": - case "#rel": { - return new RelativePattern(catchSuggestion(input, rest, context)); - } - case "#!x": - case "#nx": - case "#nox": { - return new NoXPattern(catchSuggestion(input, rest, context)); - } - case "#!y": - case "#ny": - case "#noy": { - return new NoYPattern(catchSuggestion(input, rest, context)); - } - case "#!z": - case "#nz": - case "#noz": { - return new NoZPattern(catchSuggestion(input, rest, context)); - } - case "#mask": { - List split3 = suggestRemaining(rest, "#mask", "", "", ""); - Pattern primary = catchSuggestion(input, split3.get(1), context); - Pattern secondary = catchSuggestion(input, split3.get(2), context); - PatternExtent extent = new PatternExtent(primary); - Request request = Request.request(); - request.setExtent(extent); - request.setSession(context.getSession()); - request.setWorld(context.getWorld()); - context.setExtent(extent); - MaskFactory factory = worldEdit.getMaskFactory(); - Mask mask = factory.parseFromInput(split3.get(0), context); - if (mask == null | primary == null || secondary == null) { - throw new SuggestInputParseException(null, "#mask:::"); - } - return new MaskedPattern(mask, extent, secondary); - } - case "#offset": + case "#fullcopy": { + LocalSession session = context.requireSession(); + if (session != null) { try { - List split3 = suggestRemaining(rest, "#offset", "", "", "", ""); - int x = (int) Expression.compile(split3.get(0)).evaluate(); - int y = (int) Expression.compile(split3.get(1)).evaluate(); - int z = (int) Expression.compile(split3.get(2)).evaluate(); - rest = StringMan.join(split3.subList(3, split3.size()), ":"); - Pattern pattern = catchSuggestion(input, rest, context); - return new OffsetPattern(pattern, x, y, z); - } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { - throw new SuggestInputParseException(null, "#offset::::"); - } - case "#surfacespread": { - try { - List split3 = suggestRemaining(rest, "#surfacespread", "", "", "", ""); - int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); - int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); - int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); - rest = StringMan.join(split3.subList(3, split3.size()), ":"); - Pattern pattern = catchSuggestion(input, rest, context); - return new SurfaceRandomOffsetPattern(pattern, x, y, z); - } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { - throw new SuggestInputParseException(null, "#surfacespread::::"); + if (split2.length > 1) { + String location = split2[1]; + try { + ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(context.getActor(), context.requireWorld().getWorldData(), location, true); + if (clipboards == null) { + System.out.println("NULL!"); + throw new InputParseException("#fullcopy:"); + } + boolean random = split2.length == 3 && split2[2].equalsIgnoreCase("true"); + return new RandomFullClipboardPattern(Request.request().getEditSession(), context.requireWorld().getWorldData(), clipboards, random); + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + return new FullClipboardPattern(Request.request().getEditSession(), clipboard); + } catch (EmptyClipboardException e) { + throw new InputParseException("To use #fullcopy, please first copy something to your clipboard"); } + } else { + throw new InputParseException("No session is available, so no clipboard is available"); } - case "#solidspread": { - try { - List split3 = suggestRemaining(rest, "#solidspread", "", "", "", ""); - int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); - int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); - int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); - rest = StringMan.join(split3.subList(3, split3.size()), ":"); - Pattern pattern = catchSuggestion(input, rest, context); - return new SolidRandomOffsetPattern(pattern, x, y, z); - } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { - throw new SuggestInputParseException(null, "#solidspread::::"); - } - } - case "#randomoffset": - case "#spread": { - try { - List split3 = suggestRemaining(rest, "#spread", "", "", "", ""); - int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); - int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); - int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); - rest = StringMan.join(split3.subList(3, split3.size()), ":"); - Pattern pattern = catchSuggestion(input, rest, context); - return new RandomOffsetPattern(pattern, x, y, z); - } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { - throw new SuggestInputParseException(null, "#spread::::"); - } - } - case "#l": - case "#linear": { - ArrayList patterns = new ArrayList<>(); - for (String token : StringMan.split(rest, ',')) { - patterns.add(catchSuggestion(input, token, context)); - } - if (patterns.isEmpty()) { - throw new SuggestInputParseException(null, ALL_PATTERNS).prepend(input); - } - return new LinearBlockPattern(patterns.toArray(new Pattern[patterns.size()])); - } - case "#l3d": - case "#linear3d": { - ArrayList patterns = new ArrayList<>(); - for (String token : StringMan.split(rest, ',')) { - patterns.add(catchSuggestion(input, token, context)); - } - if (patterns.isEmpty()) { - throw new SuggestInputParseException(null, ALL_PATTERNS).prepend(input); - } - return new Linear3DBlockPattern(patterns.toArray(new Pattern[patterns.size()])); - } - default: - throw new SuggestInputParseException(input, DELEGATE_PATTERNS); } + case "#id": { + return new IdPattern(Request.request().getEditSession(), catchSuggestion(input, rest, context)); + } + case "#data": { + return new DataPattern(Request.request().getEditSession(), catchSuggestion(input, rest, context)); + } + case "#biome": { + World world = context.requireWorld(); + BiomeRegistry biomeRegistry = world.getWorldData().getBiomeRegistry(); + List knownBiomes = biomeRegistry.getBiomes(); + BaseBiome biome = Biomes.findBiomeByName(knownBiomes, rest, biomeRegistry); + return new BiomePattern(Request.request().getEditSession(), biome); + } + case "#~": + case "#r": + case "#relative": + case "#rel": { + return new RelativePattern(catchSuggestion(input, rest, context)); + } + case "#!x": + case "#nx": + case "#nox": { + return new NoXPattern(catchSuggestion(input, rest, context)); + } + case "#!y": + case "#ny": + case "#noy": { + return new NoYPattern(catchSuggestion(input, rest, context)); + } + case "#!z": + case "#nz": + case "#noz": { + return new NoZPattern(catchSuggestion(input, rest, context)); + } + case "#mask": { + List split3 = suggestRemaining(rest, "#mask", "", "", ""); + Pattern primary = catchSuggestion(input, split3.get(1), context); + Pattern secondary = catchSuggestion(input, split3.get(2), context); + PatternExtent extent = new PatternExtent(primary); + Request request = Request.request(); + request.setExtent(extent); + request.setSession(context.getSession()); + request.setWorld(context.getWorld()); + context.setExtent(extent); + MaskFactory factory = worldEdit.getMaskFactory(); + Mask mask = factory.parseFromInput(split3.get(0), context); + if (mask == null | primary == null || secondary == null) { + throw new SuggestInputParseException(null, "#mask:::"); + } + return new MaskedPattern(mask, extent, secondary); + } + case "#offset": + try { + List split3 = suggestRemaining(rest, "#offset", "", "", "", ""); + int x = (int) Expression.compile(split3.get(0)).evaluate(); + int y = (int) Expression.compile(split3.get(1)).evaluate(); + int z = (int) Expression.compile(split3.get(2)).evaluate(); + rest = StringMan.join(split3.subList(3, split3.size()), ":"); + Pattern pattern = catchSuggestion(input, rest, context); + return new OffsetPattern(pattern, x, y, z); + } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { + throw new SuggestInputParseException(null, "#offset::::"); + } + case "#surfacespread": { + try { + List split3 = suggestRemaining(rest, "#surfacespread", "", "", "", ""); + int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); + int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); + int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); + rest = StringMan.join(split3.subList(3, split3.size()), ":"); + Pattern pattern = catchSuggestion(input, rest, context); + return new SurfaceRandomOffsetPattern(pattern, x, y, z); + } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { + throw new SuggestInputParseException(null, "#surfacespread::::"); + } + } + case "#solidspread": { + try { + List split3 = suggestRemaining(rest, "#solidspread", "", "", "", ""); + int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); + int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); + int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); + rest = StringMan.join(split3.subList(3, split3.size()), ":"); + Pattern pattern = catchSuggestion(input, rest, context); + return new SolidRandomOffsetPattern(pattern, x, y, z); + } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { + throw new SuggestInputParseException(null, "#solidspread::::"); + } + } + case "#randomoffset": + case "#spread": { + try { + List split3 = suggestRemaining(rest, "#spread", "", "", "", ""); + int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); + int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); + int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); + rest = StringMan.join(split3.subList(3, split3.size()), ":"); + Pattern pattern = catchSuggestion(input, rest, context); + return new RandomOffsetPattern(pattern, x, y, z); + } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { + throw new SuggestInputParseException(null, "#spread::::"); + } + } + case "#l": + case "#linear": { + ArrayList patterns = new ArrayList<>(); + for (String token : StringMan.split(rest, ',')) { + patterns.add(catchSuggestion(input, token, context)); + } + if (patterns.isEmpty()) { + throw new SuggestInputParseException(null, ALL_PATTERNS).prepend(input); + } + return new LinearBlockPattern(patterns.toArray(new Pattern[patterns.size()])); + } + case "#l3d": + case "#linear3d": { + ArrayList patterns = new ArrayList<>(); + for (String token : StringMan.split(rest, ',')) { + patterns.add(catchSuggestion(input, token, context)); + } + if (patterns.isEmpty()) { + throw new SuggestInputParseException(null, ALL_PATTERNS).prepend(input); + } + return new Linear3DBlockPattern(patterns.toArray(new Pattern[patterns.size()])); + } + default: + throw new SuggestInputParseException(input, MainUtil.joinArrayGeneric(SIMPLE_PATTERNS, DELEGATE_PATTERNS)); } - throw new SuggestInputParseException(input, MainUtil.joinArrayGeneric(SIMPLE_PATTERNS, DELEGATE_PATTERNS)); } case '=': { try { diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index 2bc03faa..9cda393a 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -246,7 +246,6 @@ public final class CommandManager { .registerMethods(new ToolCommands(worldEdit)) .registerMethods(new BrushCommands(worldEdit)) .parent().graph().getDispatcher(); - if (platform != null) { platform.registerCommands(dispatcher); } diff --git a/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java index 9ea160ff..6f409cd7 100644 --- a/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java +++ b/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.extent.clipboard.io; +import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; import com.boydti.fawe.jnbt.NBTStreamer; import com.boydti.fawe.object.FaweOutputStream; @@ -27,6 +28,8 @@ import com.boydti.fawe.object.clipboard.AbstractClipboardFormat; import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard; import com.boydti.fawe.object.clipboard.FaweClipboard; import com.boydti.fawe.object.clipboard.IClipboardFormat; +import com.boydti.fawe.object.clipboard.LazyClipboardHolder; +import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.io.PGZIPOutputStream; import com.boydti.fawe.object.io.ResettableFileInputStream; import com.boydti.fawe.object.schematic.FaweFormat; @@ -35,29 +38,43 @@ import com.boydti.fawe.object.schematic.Schematic; import com.boydti.fawe.object.schematic.StructureFormat; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.ReflectionUtils; +import com.google.common.io.ByteSource; +import com.google.common.io.Files; import com.google.gson.Gson; import com.sk89q.jnbt.NBTConstants; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +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.session.ClipboardHolder; +import com.sk89q.worldedit.world.registry.WorldData; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.File; +import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; import javax.annotation.Nullable; @@ -297,6 +314,87 @@ public enum ClipboardFormat { }); } + public ClipboardHolder[] loadAllFromInput(Actor player, WorldData worldData, String input, boolean message) throws IOException { + checkNotNull(player); + checkNotNull(input); + WorldEdit worldEdit = WorldEdit.getInstance(); + LocalConfiguration config = worldEdit.getConfiguration(); + if (input.startsWith("http")) { + URL url = new URL(input); + URL webInterface = new URL(Settings.IMP.WEB.ASSETS); + if (!url.getHost().equalsIgnoreCase(webInterface.getHost())) { + if (message) BBC.WEB_UNAUTHORIZED.send(player, url); + return null; + } + ClipboardHolder[] clipboards = loadAllFromUrl(url, worldData); + return clipboards; + } else { + if (input.contains("../") && !player.hasPermission("worldedit.schematic.load.other")) { + if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.other"); + return null; + } + File working = worldEdit.getWorkingDirectoryFile(config.saveDir); + File dir = new File(working, (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? (player.getUniqueId().toString() + File.separator) : "") + input); + if (!dir.exists()) { + if ((!input.contains("/") && !input.contains("\\")) || player.hasPermission("worldedit.schematic.load.other")) { + dir = new File(worldEdit.getWorkingDirectoryFile(config.saveDir), input); + } + } + if (!dir.exists() || !dir.isDirectory()) { + if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input); + return null; + } + ClipboardHolder[] clipboards = loadAllFromDirectory(dir, worldData); + if (clipboards.length < 1) { + if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input); + return null; + } + return clipboards; + } + } + + public ClipboardHolder[] loadAllFromDirectory(File dir, WorldData worldData) { + File[] files = dir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.getName().endsWith(".schematic"); + } + }); + LazyClipboardHolder[] clipboards = new LazyClipboardHolder[files.length]; + for (int i = 0; i < files.length; i++) { + File file = files[i]; + ByteSource source = Files.asByteSource(file); + clipboards[i] = new LazyClipboardHolder(source, this, worldData, null); + } + return clipboards; + } + + public ClipboardHolder[] loadAllFromUrl(URL url, WorldData worldData) throws IOException { + List clipboards = new ArrayList<>(); + try (ReadableByteChannel rbc = Channels.newChannel(url.openStream())) { + try (InputStream in = Channels.newInputStream(rbc)) { + try (ZipInputStream zip = new ZipInputStream(in)) { + ZipEntry entry; + byte[] buffer = new byte[8192]; + while ((entry = zip.getNextEntry()) != null) { + if (entry.getName().endsWith(".schematic")) { + FastByteArrayOutputStream out = new FastByteArrayOutputStream(); + int len = 0; + while ((len = zip.read(buffer)) > 0) { + out.write(buffer, 0, len); + } + byte[] array = out.toByteArray(); + ByteSource source = ByteSource.wrap(array); + LazyClipboardHolder clipboard = new LazyClipboardHolder(source, this, worldData, null); + clipboards.add(clipboard); + } + } + } + } + } + return clipboards.toArray(new LazyClipboardHolder[clipboards.size()]); + } + private void write(OutputStream value, Clipboard clipboard) { try { try (PGZIPOutputStream gzip = new PGZIPOutputStream(value)) {