diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/util/image/BukkitImageListener.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/util/image/BukkitImageListener.java index 7c15a6f9..caacf900 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/util/image/BukkitImageListener.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/util/image/BukkitImageListener.java @@ -54,7 +54,7 @@ public class BukkitImageListener implements Listener { Bukkit.getPluginManager().registerEvents(this, plugin); } - @EventHandler(priority = EventPriority.LOWEST) + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onPlayerInteractEntity(AsyncPlayerChatEvent event) { Set recipients = event.getRecipients(); Iterator iter = recipients.iterator(); diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 96d8f90e..a4a8286b 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -21,8 +21,12 @@ import com.boydti.fawe.util.chat.ChatManager; import com.boydti.fawe.util.chat.PlainChatManager; import com.boydti.fawe.util.cui.CUI; import com.boydti.fawe.util.metrics.BStats; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.CompoundTagBuilder; +import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.BlockWorldVector; import com.sk89q.worldedit.CuboidClipboard; @@ -118,6 +122,8 @@ import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; import com.sk89q.worldedit.internal.expression.runtime.For; import com.sk89q.worldedit.internal.expression.runtime.Functions; +import com.sk89q.worldedit.internal.expression.runtime.SimpleFor; +import com.sk89q.worldedit.internal.expression.runtime.While; import com.sk89q.worldedit.math.convolution.HeightMap; import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; import com.sk89q.worldedit.math.transform.AffineTransform; @@ -647,6 +653,8 @@ public class Fawe { Expression.inject(); // Optimizations Functions.inject(); // Optimizations For.inject(); // Fixes + SimpleFor.inject(); // Fixes + While.inject(); // Fixes // BlockData BlockData.inject(); // Temporary fix for 1.9.4 BundledBlockData.inject(); // Add custom rotation @@ -663,6 +671,10 @@ public class Fawe { // NBT NBTInputStream.inject(); // Add actual streaming + Optimizations + New methods NBTOutputStream.inject(); // New methods + Tag.inject(); // Expose raw data + CompoundTag.inject(); // Expose raw data + CompoundTagBuilder.inject(); // make accessible + ListTag.inject(); // Expose raw data // Math KochanekBartelsInterpolation.inject(); // Optimizations AffineTransform.inject(); // Optimizations diff --git a/core/src/main/java/com/boydti/fawe/command/CFICommands.java b/core/src/main/java/com/boydti/fawe/command/CFICommands.java index 5cbe3a28..cce463a8 100644 --- a/core/src/main/java/com/boydti/fawe/command/CFICommands.java +++ b/core/src/main/java/com/boydti/fawe/command/CFICommands.java @@ -7,6 +7,7 @@ import com.boydti.fawe.config.Commands; import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.RunnableVal; +import com.boydti.fawe.object.clipboard.MultiClipboardHolder; import com.boydti.fawe.util.CleanTextureUtil; import com.boydti.fawe.util.FilteredTextureUtil; import com.boydti.fawe.util.ImgurUtility; @@ -452,14 +453,14 @@ public class CFICommands extends MethodCommands { World world = fp.getWorld(); WorldData wd = world.getWorldData(); - ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(fp.getPlayer(), wd, schematic, true); - if (clipboards == null) { + MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(fp.getPlayer(), wd, schematic, true); + if (multi == null) { return; } if (imageMask == null) { - gen.addSchems(mask, wd, clipboards, rarity, distance, rotate); + gen.addSchems(mask, wd, multi.getHolders(), rarity, distance, rotate); } else { - gen.addSchems(imageMask, mask, wd, clipboards, rarity, distance, rotate); + gen.addSchems(imageMask, mask, wd, multi.getHolders(), rarity, distance, rotate); } msg("Added schematics!").send(fp); populate(fp); diff --git a/core/src/main/java/com/boydti/fawe/config/BBC.java b/core/src/main/java/com/boydti/fawe/config/BBC.java index 93f21260..787494da 100644 --- a/core/src/main/java/com/boydti/fawe/config/BBC.java +++ b/core/src/main/java/com/boydti/fawe/config/BBC.java @@ -194,6 +194,7 @@ public enum BBC { SCHEMATIC_LIST("Available files (Filename: Format) [%s0/%s1]:", "Worldedit.Schematic"), SCHEMATIC_LIST_ELEM("&8 - &a%s0 &8- &7%s1", "Worldedit.Schematic"), + CLIPBOARD_URI_NOT_FOUND("You do not have %s0 loaded", "WorldEdit.Clipboard"), CLIPBOARD_CLEARED("Clipboard cleared", "WorldEdit.Clipboard"), CLIPBOARD_INVALID_FORMAT("Unknown clipboard format: %s0", "WorldEdit.Clipboard"), diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java index a8971224..ace9a2e6 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java @@ -34,6 +34,7 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.util.Arrays; +import java.util.List; public class HeightMapMCAGenerator extends MCAWriter implements Extent { private final MutableBlockVector mutable = new MutableBlockVector(); @@ -238,13 +239,13 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent { } @Deprecated - public void addSchems(Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, boolean rotate) throws WorldEditException { + public void addSchems(Mask mask, WorldData worldData, List clipboards, int rarity, boolean rotate) throws WorldEditException { CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength())); addSchems(region, mask, worldData, clipboards, rarity, rotate); update(); } - public void addSchems(BufferedImage img, Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException { + public void addSchems(BufferedImage img, Mask mask, WorldData worldData, List clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException { if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!"); double doubleRarity = rarity / 100d; @@ -268,7 +269,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent { continue; } placed.add(x, z); - ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)]; + ClipboardHolder holder = clipboards.get(PseudoRandom.random.random(clipboards.size())); if (randomRotate) { int rotate = PseudoRandom.random.random(4) * 90; if (rotate != 0) { @@ -296,7 +297,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent { update(); } - public void addSchems(Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException { + public void addSchems(Mask mask, WorldData worldData, List clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException { int scaledRarity = (256 * rarity) / 100; int index = 0; AffineTransform identity = new AffineTransform(); @@ -318,7 +319,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent { } mutable.mutY(y + 1); placed.add(x, z); - ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)]; + ClipboardHolder holder = clipboards.get(PseudoRandom.random.random(clipboards.size())); if (randomRotate) { int rotate = PseudoRandom.random.random(4) * 90; if (rotate != 0) { diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/SchemGen.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/SchemGen.java index 5336597a..1aa8df7a 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/SchemGen.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/generator/SchemGen.java @@ -11,18 +11,19 @@ import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.registry.WorldData; +import java.util.List; public class SchemGen extends Resource { private final Extent extent; private final WorldData worldData; - private final ClipboardHolder[] clipboards; + private final List clipboards; private final boolean randomRotate; private final Mask mask; private MutableBlockVector mutable = new MutableBlockVector(); - public SchemGen(Mask mask, Extent extent, WorldData worldData, ClipboardHolder[] clipboards, boolean randomRotate) { + public SchemGen(Mask mask, Extent extent, WorldData worldData, List clipboards, boolean randomRotate) { this.mask = mask; this.extent = extent; this.worldData = worldData; @@ -41,7 +42,7 @@ public class SchemGen extends Resource { return false; } mutable.mutY(y + 1); - ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)]; + ClipboardHolder holder = clipboards.get(PseudoRandom.random.random(clipboards.size())); if (randomRotate) { holder.setTransform(new AffineTransform().rotateY(PseudoRandom.random.random(4) * 90)); } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/PopulateSchem.java b/core/src/main/java/com/boydti/fawe/object/brush/PopulateSchem.java index 0d7304fe..67c4230b 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/PopulateSchem.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/PopulateSchem.java @@ -11,14 +11,15 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.session.ClipboardHolder; +import java.util.List; public class PopulateSchem implements Brush { private final Mask mask; private final boolean randomRotate; - private final ClipboardHolder[] clipboards; + private final List clipboards; private final int rarity; - public PopulateSchem(Mask mask, ClipboardHolder[] clipboards, int rarity, boolean randomRotate) { + public PopulateSchem(Mask mask, List clipboards, int rarity, boolean randomRotate) { this.mask = mask; this.clipboards = clipboards; this.rarity = rarity; diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java index bb73d8e0..8a414ad8 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollAction.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object.brush.scroll; import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.clipboard.MultiClipboardHolder; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -11,7 +12,6 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.session.ClipboardHolder; import java.io.IOException; public abstract class ScrollAction implements ScrollTool { @@ -34,11 +34,11 @@ public abstract class ScrollAction implements ScrollTool { } String filename = split[1]; try { - ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), filename, message); - if (clipboards == null) { + MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), filename, message); + if (multi == null) { return null; } - return (new ScrollClipboard(tool, session, clipboards)); + return (new ScrollClipboard(tool, session, multi.getHolders())); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollClipboard.java b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollClipboard.java index 7bfe77a3..f6275bc7 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/scroll/ScrollClipboard.java @@ -5,13 +5,14 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.session.ClipboardHolder; +import java.util.List; public class ScrollClipboard extends ScrollAction { - private final ClipboardHolder[] clipboards; + private final List clipboards; private final LocalSession session; int index = 0; - public ScrollClipboard(BrushTool tool, LocalSession session, ClipboardHolder[] clipboards) { + public ScrollClipboard(BrushTool tool, LocalSession session, List clipboards) { super(tool); this.clipboards = clipboards; this.session = session; @@ -19,8 +20,8 @@ public class ScrollClipboard extends ScrollAction { @Override public boolean increment(Player player, int amount) { - index = MathMan.wrap(index + amount, 0, clipboards.length - 1); - ClipboardHolder clipboard = clipboards[index]; + index = MathMan.wrap(index + amount, 0, clipboards.size() - 1); + ClipboardHolder clipboard = clipboards.get(index); session.setClipboard(clipboard); return true; } diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java index 8f013e64..8ee7baa1 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java @@ -88,6 +88,10 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { } } + public File getFile() { + return file; + } + private void init() throws IOException { if (this.fc == null) { this.fc = braf.getChannel(); @@ -280,6 +284,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void close() { + MainUtil.stacktrace(); try { if (mbb != null) { mbb.force(); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java index 2a6801ca..5013f7be 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/EmptyClipboard.java @@ -13,7 +13,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BaseBiome; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.annotation.Nullable; @@ -26,17 +26,17 @@ public class EmptyClipboard implements Clipboard { @Override public Region getRegion() { - return new CuboidRegion(new Vector(), new Vector()); + return new CuboidRegion(Vector.ZERO, Vector.ZERO); } @Override public Vector getDimensions() { - return new Vector(); + return Vector.ZERO; } @Override public Vector getOrigin() { - return new Vector(); + return Vector.ZERO; } @Override @@ -45,22 +45,22 @@ public class EmptyClipboard implements Clipboard { @Override public Vector getMinimumPoint() { - return new Vector(); + return Vector.ZERO; } @Override public Vector getMaximumPoint() { - return new Vector(); + return Vector.ZERO; } @Override public List getEntities(Region region) { - return new ArrayList<>(); + return Collections.emptyList(); } @Override public List getEntities() { - return new ArrayList<>(); + return Collections.emptyList(); } @Nullable diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/LazyClipboardHolder.java b/core/src/main/java/com/boydti/fawe/object/clipboard/LazyClipboardHolder.java index c3b68d14..06f87f04 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/LazyClipboardHolder.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/LazyClipboardHolder.java @@ -2,16 +2,17 @@ package com.boydti.fawe.object.clipboard; import com.boydti.fawe.object.schematic.StructureFormat; import com.google.common.io.ByteSource; +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.ClipboardReader; import com.sk89q.worldedit.extent.clipboard.io.SchematicReader; -import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.registry.WorldData; import java.io.InputStream; +import java.net.URI; import java.util.UUID; -public class LazyClipboardHolder extends ClipboardHolder { +public class LazyClipboardHolder extends URIClipboardHolder { private final ByteSource source; private final ClipboardFormat format; private final UUID uuid; @@ -22,16 +23,20 @@ public class LazyClipboardHolder extends ClipboardHolder { * * @param worldData the mapping of blocks, entities, and so on */ - public LazyClipboardHolder(ByteSource source, ClipboardFormat format, WorldData worldData, UUID uuid) { - super(EmptyClipboard.INSTANCE, worldData); + public LazyClipboardHolder(URI uri, ByteSource source, ClipboardFormat format, WorldData worldData, UUID uuid) { + super(uri, EmptyClipboard.INSTANCE, worldData); this.source = source; this.format = format; this.uuid = uuid != null ? uuid : UUID.randomUUID(); } + @Override + public boolean contains(Clipboard clipboard) { + return this.clipboard == clipboard; + } @Override - public Clipboard getClipboard() { + public synchronized Clipboard getClipboard() { if (clipboard == null) { try { try (InputStream in = source.openBufferedStream()) { @@ -51,4 +56,12 @@ public class LazyClipboardHolder extends ClipboardHolder { } return clipboard; } + + @Override + public synchronized void close() { + if (clipboard instanceof BlockArrayClipboard) { + ((BlockArrayClipboard) clipboard).close(); + } + clipboard = null; + } } diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/MultiClipboardHolder.java b/core/src/main/java/com/boydti/fawe/object/clipboard/MultiClipboardHolder.java index afc2a0fc..3dee5b3e 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/MultiClipboardHolder.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/MultiClipboardHolder.java @@ -1,43 +1,149 @@ package com.boydti.fawe.object.clipboard; import com.boydti.fawe.object.PseudoRandom; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.registry.WorldData; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; -public class MultiClipboardHolder extends ClipboardHolder { - private final ClipboardHolder[] holders; - private ClipboardHolder holder; +import static com.google.common.base.Preconditions.checkNotNull; - public MultiClipboardHolder(WorldData worldData, ClipboardHolder... holders) { - super(holders[0].getClipboard(), worldData); - holder = holders[0]; - this.holders = holders; +public class MultiClipboardHolder extends URIClipboardHolder { + private final List holders; + private Clipboard[] cached; + + public MultiClipboardHolder(WorldData worldData) { + this(URI.create(""), worldData); } + public MultiClipboardHolder(URI uri, WorldData worldData) { + super(uri, EmptyClipboard.INSTANCE, worldData); + holders = new ArrayList<>(); + } + + public MultiClipboardHolder(URI uri, WorldData worldData, URIClipboardHolder... addHolders) { + this(uri, worldData); + for (URIClipboardHolder h : addHolders) add(h); + } + + public MultiClipboardHolder(Clipboard clipboard, WorldData worldData) { + super(URI.create(""), EmptyClipboard.INSTANCE, worldData); + holders = new ArrayList<>(); + URI uri = URI.create(""); + if (clipboard instanceof BlockArrayClipboard) { + FaweClipboard fc = ((BlockArrayClipboard) clipboard).IMP; + if (fc instanceof DiskOptimizedClipboard) { + uri = ((DiskOptimizedClipboard) fc).getFile().toURI(); + } + } + add(uri, clipboard); + } + + public void remove(URI uri) { + cached = null; + if (getUri().equals(uri)) { + for (ClipboardHolder holder : holders) holder.close(); + holders.clear(); + return; + } + for (int i = holders.size() - 1; i >= 0; i--) { + URIClipboardHolder holder = holders.get(i); + if (holder.contains(uri)) { + if (holder instanceof MultiClipboardHolder) { + ((MultiClipboardHolder) holder).remove(uri); + } else { + holders.remove(i).close(); + } + } + } + } + + public void add(URIClipboardHolder holder) { + add((ClipboardHolder) holder); + } + + @Override + public boolean contains(Clipboard clipboard) { + for (ClipboardHolder holder : holders) { + if (holder.contains(clipboard)) return true; + } + return false; + } + + @Deprecated + public void add(ClipboardHolder holder) { + checkNotNull(holder); + if (holder instanceof URIClipboardHolder) { + holders.add((URIClipboardHolder) holder); + } else { + URI uri = URI.create(UUID.randomUUID().toString()); + if (!contains(uri)) { + holders.add(new URIClipboardHolder(uri, holder.getClipboard(), holder.getWorldData())); + } + } + cached = null; + } + + public void add(URI uri, Clipboard clip) { + checkNotNull(clip); + checkNotNull(uri); + add(new URIClipboardHolder(uri, clip, getWorldData())); + } + + @Override + public List getClipboards() { + ArrayList all = new ArrayList<>(); + for (ClipboardHolder holder : holders) { + all.addAll(holder.getClipboards()); + } + return all; + } + + @Override + public List getHolders() { + ArrayList holders = new ArrayList<>(); + for (ClipboardHolder holder : holders) { + holders.addAll(holder.getHolders()); + } + return holders; + } + + @Override + public boolean contains(URI uri) { + if (getUri().equals(uri)) { + return true; + } + for (URIClipboardHolder uch : holders) { + if (uch.contains(uri)) return true; + } + return false; + } @Override public Clipboard getClipboard() { - holder = holders[PseudoRandom.random.nextInt(holders.length)]; - return holder.getClipboard(); - } + Clipboard[] available = cached; + if (available == null) { + cached = available = getClipboards().toArray(new Clipboard[0]); + } + switch (available.length) { + case 0: return EmptyClipboard.INSTANCE; + case 1: return available[0]; + } - @Override - public Transform getTransform() { - return holder.getTransform(); - } - - @Override - public void setTransform(Transform transform) { - holder.setTransform(transform); + int index = PseudoRandom.random.nextInt(available.length); + return available[index]; } @Override public void close() { + cached = null; for (ClipboardHolder holder : holders) { - if (holder != null) holder.close(); + holder.close(); } } } \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/URIClipboardHolder.java b/core/src/main/java/com/boydti/fawe/object/clipboard/URIClipboardHolder.java new file mode 100644 index 00000000..de1db2c5 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/URIClipboardHolder.java @@ -0,0 +1,33 @@ +package com.boydti.fawe.object.clipboard; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.world.registry.WorldData; +import java.net.URI; + + +import static com.google.common.base.Preconditions.checkNotNull; + +public class URIClipboardHolder extends ClipboardHolder { + private final URI uri; + + public URIClipboardHolder(URI uri, Clipboard clipboard, WorldData worldData) { + super(clipboard, worldData); + checkNotNull(uri); + this.uri = uri; + } + + public boolean contains(URI uri) { + checkNotNull(uri); + return this.uri.equals(uri); + } + + /** + * @deprecated If a holder has multiple sources, this will return an empty URI + * @return The original source of this clipboard (usually a file or url) + */ + @Deprecated + public URI getUri() { + return uri; + } +} 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 index 39629c49..d0c0e24e 100644 --- a/core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java +++ b/core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java @@ -15,19 +15,20 @@ import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.registry.WorldData; import java.io.IOException; import java.io.NotSerializableException; +import java.util.List; 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 final List clipboards; private boolean randomRotate; private boolean randomFlip; private WorldData worldData; - public RandomFullClipboardPattern(Extent extent, WorldData worldData, ClipboardHolder[] clipboards, boolean randomRotate, boolean randomFlip) { + public RandomFullClipboardPattern(Extent extent, WorldData worldData, List clipboards, boolean randomRotate, boolean randomFlip) { checkNotNull(clipboards); this.clipboards = clipboards; this.extent = extent; @@ -37,7 +38,7 @@ public class RandomFullClipboardPattern extends AbstractPattern { @Override public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException { - ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)]; + ClipboardHolder holder = clipboards.get(PseudoRandom.random.random(clipboards.size())); AffineTransform transform = new AffineTransform(); if (randomRotate) { transform = transform.rotateY(PseudoRandom.random.random(4) * 90); diff --git a/core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java b/core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java index a221e9f6..701b92ee 100644 --- a/core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java +++ b/core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java @@ -67,6 +67,10 @@ public class ReflectionUtils { } } + public static T as(Class t, Object o) { + return t.isInstance(o) ? t.cast(o) : null; + } + @SuppressWarnings("unchecked") public static > T addEnum(Class enumType, String enumName) { @@ -186,6 +190,7 @@ public class ReflectionUtils { public static List getList(List list) { try { Class clazz = (Class) Class.forName("java.util.Collections$UnmodifiableList"); + if (!clazz.isInstance(list)) return list; Field m = clazz.getDeclaredField("list"); m.setAccessible(true); return (List) m.get(list); diff --git a/core/src/main/java/com/boydti/fawe/util/chat/Message.java b/core/src/main/java/com/boydti/fawe/util/chat/Message.java index 563d92b7..b96444ac 100644 --- a/core/src/main/java/com/boydti/fawe/util/chat/Message.java +++ b/core/src/main/java/com/boydti/fawe/util/chat/Message.java @@ -47,6 +47,10 @@ public class Message { return this; } + public boolean supportsInteraction() { + return active; + } + public Message text(BBC caption, Object... args) { return text(caption.format(args)); } diff --git a/core/src/main/java/com/boydti/fawe/util/image/ImageUtil.java b/core/src/main/java/com/boydti/fawe/util/image/ImageUtil.java index e32c5da2..34a83a43 100644 --- a/core/src/main/java/com/boydti/fawe/util/image/ImageUtil.java +++ b/core/src/main/java/com/boydti/fawe/util/image/ImageUtil.java @@ -80,8 +80,8 @@ public class ImageUtil { throw new IOException("Failed to read " + url + ", please try again later"); } return img; - } else if (arg.startsWith("file://")) { - arg = arg.substring(7); + } else if (arg.startsWith("file:/")) { + arg = arg.replaceFirst("file:/+", ""); File file = MainUtil.getFile(MainUtil.getFile(Fawe.imp().getDirectory(), com.boydti.fawe.config.Settings.IMP.PATHS.HEIGHTMAP), arg); return MainUtil.readImage(file); } else { diff --git a/core/src/main/java/com/sk89q/jnbt/CompoundTag.java b/core/src/main/java/com/sk89q/jnbt/CompoundTag.java index a1131935..cdd59aa5 100644 --- a/core/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/core/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -1,5 +1,6 @@ package com.sk89q.jnbt; +import com.sk89q.worldedit.function.entity.ExtentEntityCopy; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -406,4 +407,7 @@ public final class CompoundTag extends Tag { return bldr.toString(); } + public static Class inject() { + return CompoundTag.class; + } } \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java b/core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java index 34b515dd..0e6de34d 100644 --- a/core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java +++ b/core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java @@ -201,4 +201,7 @@ public class CompoundTagBuilder { return new CompoundTagBuilder(); } + public static Class inject() { + return CompoundTagBuilder.class; + } } \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/jnbt/ListTag.java b/core/src/main/java/com/sk89q/jnbt/ListTag.java index 7d81afe9..c0d2188e 100644 --- a/core/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/core/src/main/java/com/sk89q/jnbt/ListTag.java @@ -419,4 +419,8 @@ public final class ListTag extends Tag { return bldr.toString(); } + public static Class inject() { + return ListTag.class; + } + } \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/jnbt/NamedData.java b/core/src/main/java/com/sk89q/jnbt/NamedData.java index e2930385..fbedac28 100644 --- a/core/src/main/java/com/sk89q/jnbt/NamedData.java +++ b/core/src/main/java/com/sk89q/jnbt/NamedData.java @@ -5,9 +5,9 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Some data with a name */ -public class NamedData { +public class NamedData { private final String name; - private final Object data; + private final T data; /** * Create a new named tag. @@ -15,7 +15,7 @@ public class NamedData { * @param name the name * @param data the data */ - public NamedData(String name, Object data) { + public NamedData(String name, T data) { checkNotNull(name); this.name = name; this.data = data; @@ -35,7 +35,7 @@ public class NamedData { * * @return the tag */ - public Object getValue() { + public T getValue() { return data; } } diff --git a/core/src/main/java/com/sk89q/jnbt/Tag.java b/core/src/main/java/com/sk89q/jnbt/Tag.java index 35af4529..ff19d3c6 100644 --- a/core/src/main/java/com/sk89q/jnbt/Tag.java +++ b/core/src/main/java/com/sk89q/jnbt/Tag.java @@ -35,4 +35,7 @@ public abstract class Tag { return getValue(); } + public static Class inject() { + return Tag.class; + } } \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/worldedit/LocalSession.java b/core/src/main/java/com/sk89q/worldedit/LocalSession.java index 12ca7fcf..a543038a 100644 --- a/core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -789,8 +789,12 @@ public class LocalSession { * @param clipboard the clipboard, or null if the clipboard is to be cleared */ public void setClipboard(@Nullable ClipboardHolder clipboard) { + if (this.clipboard == clipboard) return; + if (this.clipboard != null) { - this.clipboard.close(); + if (clipboard == null || !clipboard.contains(this.clipboard.getClipboard())) { + this.clipboard.close(); + } } this.clipboard = clipboard; } 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 b2efe8b4..b4012c93 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -51,6 +51,7 @@ import com.boydti.fawe.object.brush.SurfaceSphereBrush; import com.boydti.fawe.object.brush.SurfaceSpline; import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap; import com.boydti.fawe.object.brush.sweep.SweepBrush; +import com.boydti.fawe.object.clipboard.MultiClipboardHolder; import com.boydti.fawe.object.mask.IdMask; import com.boydti.fawe.util.ColorUtil; import com.boydti.fawe.util.MathMan; @@ -471,12 +472,12 @@ public class BrushCommands extends MethodCommands { try { - ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), clipboard, true); + MultiClipboardHolder clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), clipboard, true); if (clipboards == null) { return null; } return get(context) - .setBrush(new PopulateSchem(mask, clipboards, (int) density, rotate)) + .setBrush(new PopulateSchem(mask, clipboards.getHolders(), (int) density, rotate)) .setSize(radius); } 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 d328d72e..d1b97d66 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -437,7 +437,10 @@ public class ClipboardCommands extends MethodCommands { @Switch('a') final boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, @Switch('s') boolean selectPasted) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); + System.out.println(holder); final Clipboard clipboard = holder.getClipboard(); + System.out.println(clipboard.getDimensions()); + System.out.println(clipboard.getClass()); final Vector origin = clipboard.getOrigin(); final Vector to = atOrigin ? origin : session.getPlacementPosition(player); @@ -500,6 +503,7 @@ public class ClipboardCommands extends MethodCommands { BBC.COMMAND_FLIPPED.send(player); } + @Deprecated // See SchematicCommands#clear @Command( aliases = {"clearclipboard"}, usage = "", diff --git a/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java b/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java index 314ffdf8..e8ceeb06 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java @@ -3,6 +3,7 @@ package com.sk89q.worldedit.command; import com.boydti.fawe.Fawe; import com.boydti.fawe.object.DataAnglePattern; import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.clipboard.MultiClipboardHolder; import com.boydti.fawe.object.collection.RandomCollection; import com.boydti.fawe.object.pattern.AngleColorPattern; import com.boydti.fawe.object.pattern.AverageColorPattern; @@ -59,6 +60,8 @@ import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.biome.BaseBiome; import java.awt.Color; import java.io.IOException; +import java.util.Collections; +import java.util.List; import java.util.Set; @Command(aliases = {"patterns"}, @@ -209,7 +212,7 @@ public class PatternCommands extends MethodCommands { max = 2 ) public Pattern fullcopy(Player player, Extent extent, LocalSession session, @Optional("#copy") String location, @Optional("false") boolean rotate, @Optional("false") boolean flip) throws EmptyClipboardException, InputParseException, IOException { - ClipboardHolder[] clipboards; + List clipboards; switch (location.toLowerCase()) { case "#copy": case "#clipboard": @@ -220,10 +223,11 @@ public class PatternCommands extends MethodCommands { if (!rotate && !flip) { return new FullClipboardPattern(extent, clipboard.getClipboard()); } - clipboards = new ClipboardHolder[]{clipboard}; + clipboards = Collections.singletonList(clipboard); break; default: - clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), location, true); + MultiClipboardHolder multi = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), location, true); + clipboards = multi != null ? multi.getHolders() : null; break; } if (clipboards == null) { diff --git a/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 3f4ce47d..f11046ab 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -23,8 +23,11 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; import com.boydti.fawe.config.Settings; -import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.RunnableVal3; import com.boydti.fawe.object.clipboard.MultiClipboardHolder; +import com.boydti.fawe.object.clipboard.URIClipboardHolder; +import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper; import com.boydti.fawe.object.schematic.StructureFormat; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.chat.Message; @@ -56,6 +59,8 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; @@ -65,10 +70,13 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; + +import static com.boydti.fawe.util.ReflectionUtils.as; + /** * Commands that work with schematic files. */ -@Command(aliases = {"schematic", "schem", "/schematic", "/schem"}, desc = "Commands that work with schematic files") +@Command(aliases = {"schematic", "schem", "/schematic", "/schem", "clipboard", "/clipboard"}, desc = "Commands that work with schematic files") public class SchematicCommands extends MethodCommands { private static final Logger log = Logger.getLogger(SchematicCommands.class.getCanonicalName()); @@ -99,10 +107,22 @@ public class SchematicCommands extends MethodCommands { } try { WorldData wd = player.getWorld().getWorldData(); - session.setClipboard(null); - ClipboardHolder[] all = format.loadAllFromInput(player, wd, filename, true); + + MultiClipboardHolder all = format.loadAllFromInput(player, wd, filename, true); if (all != null) { - MultiClipboardHolder multi = new MultiClipboardHolder(wd, all); + ClipboardHolder existing = session.getExistingClipboard(); + MultiClipboardHolder multi; + if (existing instanceof MultiClipboardHolder) { + multi = (MultiClipboardHolder) existing; + for (ClipboardHolder holder : all.getHolders()) { + multi.add(holder); + } + } else { + multi = all; + if (existing != null) { + multi.add(existing); + } + } session.setClipboard(multi); BBC.SCHEMATIC_LOADED.send(player, filename); } @@ -111,6 +131,57 @@ public class SchematicCommands extends MethodCommands { } } + @Command( + aliases = {"clear"}, + usage = "", + desc = "Clear your clipboard", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.clipboard.clear", "worldedit.schematic.clear"}) + public void clear(Player player, LocalSession session) throws WorldEditException { + session.setClipboard(null); + BBC.CLIPBOARD_CLEARED.send(player); + } + + @Command( + aliases = {"unload"}, + usage = "[file]", + desc = "Remove a clipboard from your multi-clipboard", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.clipboard.clear", "worldedit.schematic.clear"}) + public void unload(Player player, LocalSession session, String fileName) throws WorldEditException { + URI uri; + if (fileName.startsWith("file:/") || fileName.startsWith("http://") || fileName.startsWith("https://")) { + uri = URI.create(fileName); + } else { + final LocalConfiguration config = this.worldEdit.getConfiguration(); + File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir); + File root = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working; + uri = new File(root, fileName).toURI(); + } + + boolean removed = false; + ClipboardHolder clipboard = session.getClipboard(); + if (clipboard instanceof URIClipboardHolder) { + URIClipboardHolder identifiable = (URIClipboardHolder) clipboard; + if (identifiable.contains(uri)) { + if (identifiable instanceof MultiClipboardHolder) { + MultiClipboardHolder multi = (MultiClipboardHolder) identifiable; + multi.remove(uri); + if (multi.getHolders().isEmpty()) session.setClipboard(null); + } else { + session.setClipboard(null); + } + BBC.CLIPBOARD_CLEARED.send(player); + return; + } + } + BBC.CLIPBOARD_URI_NOT_FOUND.send(player, fileName); + } + @Command( aliases = {"remap"}, help = "Remap a clipboard between MCPE/PC values\n", @@ -119,12 +190,15 @@ public class SchematicCommands extends MethodCommands { @Deprecated @CommandPermissions({"worldedit.schematic.remap"}) public void remap(final Player player, final LocalSession session) throws WorldEditException { - ClipboardHolder holder = session.getClipboard(); - Clipboard clipboard = holder.getClipboard(); + ClipboardRemapper remapper; if (Fawe.imp().getPlatform().equalsIgnoreCase("nukkit")) { - new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PC, ClipboardRemapper.RemapPlatform.PE).apply(clipboard); + remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PC, ClipboardRemapper.RemapPlatform.PE); } else { - new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PE, ClipboardRemapper.RemapPlatform.PC).apply(clipboard); + remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PE, ClipboardRemapper.RemapPlatform.PC); + } + + for (Clipboard clip : session.getClipboard().getClipboards()) { + remapper.apply(clip); } player.print(BBC.getPrefix() + "Remapped schematic"); } @@ -141,6 +215,7 @@ public class SchematicCommands extends MethodCommands { } InputStream in = null; try { + URI uri; if (filename.startsWith("url:")) { if (!player.hasPermission("worldedit.schematic.upload")) { BBC.NO_PERM.send(player, "worldedit.schematic.upload"); @@ -151,6 +226,7 @@ public class SchematicCommands extends MethodCommands { URL url = new URL(base, "uploads/" + uuid + ".schematic"); ReadableByteChannel rbc = Channels.newChannel(url.openStream()); in = Channels.newInputStream(rbc); + uri = url.toURI(); } else { if (!player.hasPermission("worldedit.schematic.load") && !player.hasPermission("worldedit.clipboard.load")) { BBC.NO_PERM.send(player, "worldedit.clipboard.load"); @@ -195,6 +271,8 @@ public class SchematicCommands extends MethodCommands { return; } in = new FileInputStream(f); + + uri = f.toURI(); } final ClipboardReader reader = format.getReader(in); final WorldData worldData = player.getWorld().getWorldData(); @@ -207,11 +285,11 @@ public class SchematicCommands extends MethodCommands { } else { clipboard = reader.read(player.getWorld().getWorldData()); } - session.setClipboard(new ClipboardHolder(clipboard, worldData)); + session.setClipboard(new URIClipboardHolder(uri, clipboard, worldData)); BBC.SCHEMATIC_LOADED.send(player, filename); } catch (IllegalArgumentException e) { player.printError("Unknown filename: " + filename); - } catch (IOException e) { + } catch (URISyntaxException | IOException e) { player.printError("File could not be read or it does not exist: " + e.getMessage()); log.log(Level.WARNING, "Failed to load a saved clipboard", e); } finally { @@ -345,12 +423,10 @@ public class SchematicCommands extends MethodCommands { m.send(actor); } - // schem list all|mine|global page - @Command( - aliases = {"list", "all", "ls"}, + aliases = {"list", "ls", "all"}, desc = "List saved schematics", - usage = "[mine|] [page=1]", + usage = "[global|mine|] [page=1]", min = 0, max = -1, flags = "dnp", @@ -359,10 +435,69 @@ public class SchematicCommands extends MethodCommands { " -f restricts by format\n" ) @CommandPermissions("worldedit.schematic.list") - public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page, @Switch('f') String formatName) throws WorldEditException { - String baseCmd = Commands.getAlias(SchematicCommands.class, "schematic") + " " + Commands.getAlias(SchematicCommands.class, "load"); - File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir); - UtilityCommands.list(dir, actor, args, page, formatName, Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS, baseCmd); + public void list(FawePlayer fp, Actor actor, CommandContext args, @Switch('p') @Optional("1") int page, @Switch('f') String formatName) throws WorldEditException { + if (args.argsLength() == 0) { + BBC.COMMAND_SYNTAX.send(fp, getCommand().usage()); + return; + } + LocalConfiguration config = worldEdit.getConfiguration(); + String prefix = config.noDoubleSlash ? "" : "/"; + File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); + + String schemCmd = prefix + Commands.getAlias(SchematicCommands.class, "schematic"); + String loadSingle = schemCmd + " " + Commands.getAlias(SchematicCommands.class, "load"); + String loadMulti = schemCmd + " " + Commands.getAlias(SchematicCommands.class, "loadall"); + String unload = schemCmd + " " + Commands.getAlias(SchematicCommands.class, "unload"); + String delete = schemCmd + " " + Commands.getAlias(SchematicCommands.class, "delete"); + String list = schemCmd + " " + Commands.getAlias(SchematicCommands.class, "list"); + + URIClipboardHolder multi = as(URIClipboardHolder.class, fp.getSession().getExistingClipboard()); + + UtilityCommands.list(dir, actor, args, page, formatName, Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS, new RunnableVal3() { + @Override + public void run(Message msg, URI uri, String relFilePath) { + boolean isDir = false; + boolean loaded = multi != null && multi.contains(uri); + + String name = relFilePath; + String color; + String uriStr = uri.toString(); + if (uriStr.startsWith("file:/")) { + File file = new File(uri.getPath()); + name = file.getName(); + if (file.isDirectory()) { + isDir = true; + color = "&6"; + } else { + color = "&a"; + } + } else if (uriStr.startsWith("http://") || uriStr.startsWith("https://")) { + // url + color = "&9"; + } else { + color = "&7"; + } + + msg.text("&8 - "); + + if (msg.supportsInteraction()) { + if (loaded) { + msg.text("&7[&c-&7]").command(unload + " " + relFilePath).tooltip("Unload this schematic"); + } else { + msg.text("&7[&a+&7]").command(loadMulti + " " + relFilePath).tooltip("(WIP) Append this to your clipboard"); + } + if (!isDir) msg.text("&7[&cX&7]").suggestTip("/" + delete + " " + relFilePath); + msg.text(color + relFilePath); + if (isDir) { + msg.cmdTip(list + " " + args.getJoinedStrings(0) + " " + relFilePath); + } else { + msg.cmdTip(loadSingle + " " + relFilePath); + } + } else { + msg.text(color).text(name); + } + } + }); } public static Class inject() { diff --git a/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 0d8c23e8..c5db8445 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.command; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.clipboard.URIClipboardHolder; import com.boydti.fawe.object.mask.IdMask; import com.boydti.fawe.object.regions.selector.FuzzyRegionSelector; import com.boydti.fawe.object.regions.selector.PolyhedralRegionSelector; @@ -62,6 +63,10 @@ import com.sk89q.worldedit.util.formatting.StyledFragment; import com.sk89q.worldedit.util.formatting.component.CommandListBox; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.storage.ChunkStore; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -578,16 +583,44 @@ public class SelectionCommands { @CommandPermissions("worldedit.selection.size") public void size(Player player, LocalSession session, CommandContext args) throws WorldEditException { if (args.hasFlag('c')) { - ClipboardHolder holder = session.getClipboard(); - Clipboard clipboard = holder.getClipboard(); - Region region = clipboard.getRegion(); - Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()); - Vector origin = clipboard.getOrigin(); + ClipboardHolder root = session.getClipboard(); +// Clipboard clipboard = holder.getClipboard(); + int index = 0; + for (ClipboardHolder holder : root.getHolders()) { + Clipboard clipboard = holder.getClipboard(); + String name; + if (holder instanceof URIClipboardHolder) { + URI uri = ((URIClipboardHolder) holder).getUri(); + if (uri.toString().startsWith("file:/")) { + name = new File(uri.getPath()).getName(); + } else { + name = uri.getFragment(); + } + } else { + name = Integer.toString(index); + } - player.print(BBC.getPrefix() + "Cuboid dimensions (max - min): " + size); - player.print(BBC.getPrefix() + "Offset: " + origin); - player.print(BBC.getPrefix() + "Cuboid distance: " + size.distance(Vector.ONE)); - player.print(BBC.getPrefix() + "# of blocks: " + (int) (size.getX() * size.getY() * size.getZ())); + Region region = clipboard.getRegion(); + Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(Vector.ONE); + Vector origin = clipboard.getOrigin(); + + String sizeStr = size.getBlockX() + "*" + size.getBlockY() + "*" + size.getBlockZ(); + String originStr = origin.getBlockX() + "," + origin.getBlockY() + "," + origin.getBlockZ(); + + long numBlocks = ((long) size.getBlockX() * size.getBlockY() * size.getBlockZ()); + + String msg = String.format("%1$s: %2$s @ %3$s (%4$d blocks)", name, sizeStr, originStr, numBlocks); + player.print(BBC.getPrefix() + msg); + + index++; + } + + + +// player.print(BBC.getPrefix() + "Cuboid dimensions (max - min): " + size); +// player.print(BBC.getPrefix() + "Offset: " + origin); +// player.print(BBC.getPrefix() + "Cuboid distance: " + size.distance(Vector.ONE)); +// player.print(BBC.getPrefix() + "# of blocks: " + (int) (size.getX() * size.getY() * size.getZ())); return; } diff --git a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index e5eade68..d26ef0df 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -19,11 +19,13 @@ package com.sk89q.worldedit.command; +import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Commands; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.RunnableVal3; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.StringMan; import com.boydti.fawe.util.chat.Message; @@ -75,6 +77,7 @@ import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.util.command.parametric.ParametricCallable; import com.sk89q.worldedit.world.World; import java.io.File; +import java.io.FileFilter; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -87,7 +90,13 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.UUID; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; @@ -632,43 +641,98 @@ public class UtilityCommands extends MethodCommands { } public static void list(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, String formatName, boolean playerFolder, String onClickCmd) { - List fileList = new ArrayList<>(); + list(dir, actor, args, page, formatName, playerFolder, new RunnableVal3() { + @Override + public void run(Message m, URI uri, String fileName) { + m.text(BBC.SCHEMATIC_LIST_ELEM, fileName, ""); + if (onClickCmd != null) m.cmdTip(onClickCmd + " " + fileName); + } + }); + } + + public static void list(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, String formatName, boolean playerFolder, RunnableVal3 eachMsg) { int len = args.argsLength(); List filters = new ArrayList<>(); - boolean mine = false; + + String dirFilter = File.separator; + + boolean listMine = false; + boolean listGlobal = false; if (len > 0) { int max = len; if (MathMan.isInteger(args.getString(len - 1))) { page = args.getInteger(--len); } for (int i = 0; i < len; i++) { - switch (args.getString(i).toLowerCase()) { + String arg = args.getString(i); + switch (arg.toLowerCase()) { case "me": case "mine": - mine = true; + case "local": + case "private": + listMine = true; + break; + case "public": + case "global": + listGlobal = true; + break; + case "all": + listMine = true; + listGlobal = true; break; default: - filters.add(args.getString(i)); + if (arg.endsWith("/") || arg.endsWith(File.separator)) { + arg = arg.replace("/", File.separator); + String newDirFilter = dirFilter + arg; + boolean exists = new File(dir, newDirFilter).exists() || playerFolder && new File(dir, actor.getUniqueId() + newDirFilter).exists(); + if (!exists) { + arg = arg.substring(0, arg.length() - File.separator.length()); + if (arg.length() > 3 && arg.length() <= 16) { + UUID fromName = Fawe.imp().getUUID(arg); + if (fromName != null) { + newDirFilter = dirFilter + fromName + File.separator; + listGlobal = true; + } + } + } + dirFilter = newDirFilter; + } + else { + filters.add(arg); + } break; } } } + if (!listMine && !listGlobal) { + listMine = true; + } + + FileFilter ignoreUUIDs = f -> { + try { + if (f.isDirectory()) { + UUID uuid = UUID.fromString(f.getName()); + return false; + } + } catch (IllegalArgumentException exception) {} + return true; + }; + + List fileList = new ArrayList<>(); if (playerFolder) { - File playerDir = new File(dir, actor.getUniqueId().toString()); - if (playerDir.exists()) { - fileList.addAll(allFiles(playerDir, true)); + if (listMine) { + File playerDir = new File(dir, actor.getUniqueId() + dirFilter); + if (playerDir.exists()) fileList.addAll(allFiles(playerDir.listFiles(), false)); } - if (!mine) { - fileList.addAll(allFiles(dir, false)); + if (listGlobal) { + File rel = new File(dir, dirFilter); + if (rel.exists()) fileList.addAll(allFiles(rel.listFiles(ignoreUUIDs), false)); } } else { - fileList.addAll(allFiles(dir, true)); - } - if (!filters.isEmpty()) { - for (String filter : filters) { - fileList.removeIf(file -> !file.getPath().contains(filter)); - } + File rel = new File(dir, dirFilter); + if (rel.exists()) fileList.addAll(allFiles(rel.listFiles(), false)); } + if (fileList.isEmpty()) { BBC.SCHEMATIC_NONE.send(actor); return; @@ -680,10 +744,10 @@ public class UtilityCommands extends MethodCommands { .collect(Collectors.toList()); } - File[] files = new File[fileList.size()]; - fileList.toArray(files); + fileList = filter(fileList, filters); + final int perPage = actor instanceof Player ? 12 : 20; // More pages for console - int pageCount = (files.length + perPage - 1) / perPage; + int pageCount = (fileList.size() + perPage - 1) / perPage; if (page < 1) { BBC.SCHEMATIC_PAGE.send(actor, ">0"); return; @@ -695,9 +759,12 @@ public class UtilityCommands extends MethodCommands { final int sortType = args.hasFlag('d') ? -1 : args.hasFlag('n') ? 1 : 0; // cleanup file list - Arrays.sort(files, new Comparator() { + Collections.sort(fileList, new Comparator() { @Override public int compare(File f1, File f2) { + boolean dir1 = f1.isDirectory(); + boolean dir2 = f2.isDirectory(); + if (dir1 != dir2) return dir1 ? -1 : 1; int res; if (sortType == 0) { // use name by default int p = f1.getParent().compareTo(f2.getParent()); @@ -714,10 +781,9 @@ public class UtilityCommands extends MethodCommands { } }); - List schematics = listFiles(dir, files, playerFolder ? actor.getUniqueId() : null); int offset = (page - 1) * perPage; - int limit = Math.min(offset + perPage, schematics.size()); + int limit = Math.min(offset + perPage, fileList.size()); String fullArgs = (String) args.getLocals().get("arguments"); String baseCmd = null; @@ -726,12 +792,11 @@ public class UtilityCommands extends MethodCommands { } Message m = new Message(BBC.SCHEMATIC_LIST, page, pageCount); + UUID uuid = playerFolder ? actor.getUniqueId() : null; for (int i = offset; i < limit; i++) { - String[] fileinfo = schematics.get(i); - String fileName = fileinfo[0]; - String fileFormat = fileinfo[1]; - m.newline().text(BBC.SCHEMATIC_LIST_ELEM, fileName, fileFormat); - if (onClickCmd != null) m.cmdTip(onClickCmd + " " + fileName); + m.newline(); + File file = fileList.get(i); + eachMsg.run(m, file.toURI(), getPath(dir, file, uuid)); } if (baseCmd != null) { m.newline().paginate(baseCmd, page, pageCount); @@ -739,16 +804,57 @@ public class UtilityCommands extends MethodCommands { m.send(actor); } - private static List allFiles(File root, boolean recursive) { - File[] files = root.listFiles(); - if (files == null) return new ArrayList<>(); + private static List filter(List fileList, List filters) { + + String[] normalizedNames = new String[fileList.size()]; + for (int i = 0; i < fileList.size(); i++) { + String normalized = fileList.get(i).getName().toLowerCase(); + if (normalized.startsWith("../")) normalized = normalized.substring(3); + normalizedNames[i] = normalized.replace("/", File.separator); + } + + for (String filter : filters) { + if (fileList.isEmpty()) return fileList; + String lowerFilter = filter.toLowerCase().replace("/", File.separator); + List newList = new ArrayList<>(); + + for (int i = 0; i < normalizedNames.length; i++) { + if (normalizedNames[i].startsWith(lowerFilter)) newList.add(fileList.get(i)); + } + if (newList.isEmpty()) { + for (int i = 0; i < normalizedNames.length; i++) { + if (normalizedNames[i].contains(lowerFilter)) newList.add(fileList.get(i)); + } + + if (newList.isEmpty()) { + String checkName = filter.replace("\\", "/").split("/")[0]; + if (checkName.length() > 3 && checkName.length() <= 16) { + UUID fromName = Fawe.imp().getUUID(checkName); + if (fromName != null) { + lowerFilter = filter.replaceFirst(checkName, fromName.toString()).toLowerCase(); + for (int i = 0; i < normalizedNames.length; i++) { + if (normalizedNames[i].startsWith(lowerFilter)) newList.add(fileList.get(i)); + } + } + } + } + } + fileList = newList; + } + return fileList; + } + + private static List allFiles(File[] files, boolean recursive) { + if (files == null || files.length == 0) return Arrays.asList(); List fileList = new ArrayList(); for (File f : files) { if (f.isDirectory()) { if (recursive) { - List subFiles = allFiles(f, recursive); + List subFiles = allFiles(f.listFiles(), recursive); if (subFiles == null || subFiles.isEmpty()) continue; // empty subdir fileList.addAll(subFiles); + } else { + fileList.add(f); } } else { fileList.add(f); @@ -757,34 +863,23 @@ public class UtilityCommands extends MethodCommands { return fileList; } - private static List listFiles(File root, File[] files, UUID uuid) { - // List Elem [ File Name, Format Name ] + private static String getPath(File root, File file, UUID uuid) { File dir; if (uuid != null) { dir = new File(root, uuid.toString()); } else { dir = root; } - List result = new ArrayList<>(); - for (File file : files) { - ClipboardFormat format = ClipboardFormat.findByFile(file); - URI relative = dir.toURI().relativize(file.toURI()); - String name = ""; - if (relative.isAbsolute()) { - relative = root.toURI().relativize(file.toURI()); - name += "../"; - } - name += relative.getPath(); - String formatName; - if (format == null) { - String[] split = file.getName().split("\\."); - formatName = split.length > 1 ? split[split.length - 1].toUpperCase() : "Unknown"; - } else { - formatName = format.toString(); - } - result.add(new String[] {name, formatName} ); + + ClipboardFormat format = ClipboardFormat.findByFile(file); + URI relative = dir.toURI().relativize(file.toURI()); + StringBuilder name = new StringBuilder(); + if (relative.isAbsolute()) { + relative = root.toURI().relativize(file.toURI()); + name.append("../"); } - return result; + name.append(relative.getPath()); + return name.toString(); } public static void help(CommandContext args, WorldEdit we, Actor actor) { diff --git a/core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java index 76fefc43..890aa731 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -207,7 +207,6 @@ public class WorldEditCommands { min = 0, max = -1 ) - @CommandPermissions("worldedit.help") public void help(Actor actor, CommandContext args) throws WorldEditException { UtilityCommands.help(args, we, actor); } diff --git a/core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/core/src/main/java/com/sk89q/worldedit/extent/Extent.java index e9329a2a..5df7c228 100644 --- a/core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -152,7 +152,7 @@ public interface Extent extends InputExtent, OutputExtent { } } - default public void addSchems(Region region, Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, boolean rotate) throws WorldEditException { + default public void addSchems(Region region, Mask mask, WorldData worldData, List clipboards, int rarity, boolean rotate) throws WorldEditException { spawnResource(region, new SchemGen(mask, this, worldData, clipboards, rotate), rarity, 1); } 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 5994b8e5..fa3735ea 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 @@ -29,6 +29,8 @@ 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.clipboard.MultiClipboardHolder; +import com.boydti.fawe.object.clipboard.URIClipboardHolder; import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.io.PGZIPOutputStream; import com.boydti.fawe.object.io.ResettableFileInputStream; @@ -50,7 +52,6 @@ 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; @@ -61,6 +62,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; @@ -315,7 +318,7 @@ public enum ClipboardFormat { }); } - public ClipboardHolder[] loadAllFromInput(Actor player, WorldData worldData, String input, boolean message) throws IOException { + public MultiClipboardHolder loadAllFromInput(Actor player, WorldData worldData, String input, boolean message) throws IOException { checkNotNull(player); checkNotNull(input); WorldEdit worldEdit = WorldEdit.getInstance(); @@ -327,7 +330,7 @@ public enum ClipboardFormat { if (message) BBC.WEB_UNAUTHORIZED.send(player, url); return null; } - ClipboardHolder[] clipboards = loadAllFromUrl(url, worldData); + MultiClipboardHolder clipboards = loadAllFromUrl(url, worldData); return clipboards; } else { if (input.contains("../") && !player.hasPermission("worldedit.schematic.load.other")) { @@ -353,18 +356,19 @@ public enum ClipboardFormat { } if (!dir.isDirectory()) { ByteSource source = Files.asByteSource(dir); - return new ClipboardHolder[]{new LazyClipboardHolder(source, this, worldData, null)}; + URI uri = dir.toURI(); + return new MultiClipboardHolder(uri, worldData, new LazyClipboardHolder(dir.toURI(), source, this, worldData, null)); } - ClipboardHolder[] clipboards = loadAllFromDirectory(dir, worldData); + URIClipboardHolder[] clipboards = loadAllFromDirectory(dir, worldData); if (clipboards.length < 1) { if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input); return null; } - return clipboards; + return new MultiClipboardHolder(dir.toURI(), worldData, clipboards); } } - public ClipboardHolder[] loadAllFromDirectory(File dir, WorldData worldData) { + public URIClipboardHolder[] loadAllFromDirectory(File dir, WorldData worldData) { if (worldData == null) { try { worldData = WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData(); @@ -381,12 +385,12 @@ public enum ClipboardFormat { 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); + clipboards[i] = new LazyClipboardHolder(file.toURI(), source, this, worldData, null); } return clipboards; } - public ClipboardHolder[] loadAllFromUrl(URL url, WorldData worldData) throws IOException { + public MultiClipboardHolder loadAllFromUrl(URL url, WorldData worldData) throws IOException { List clipboards = new ArrayList<>(); try (ReadableByteChannel rbc = Channels.newChannel(url.openStream())) { try (InputStream in = Channels.newInputStream(rbc)) { @@ -402,14 +406,23 @@ public enum ClipboardFormat { } byte[] array = out.toByteArray(); ByteSource source = ByteSource.wrap(array); - LazyClipboardHolder clipboard = new LazyClipboardHolder(source, this, worldData, null); + LazyClipboardHolder clipboard = new LazyClipboardHolder(url.toURI(), source, this, worldData, null); clipboards.add(clipboard); } } + } catch (URISyntaxException e) { + e.printStackTrace(); } } } - return clipboards.toArray(new LazyClipboardHolder[clipboards.size()]); + LazyClipboardHolder[] arr = clipboards.toArray(new LazyClipboardHolder[clipboards.size()]); + try { + MultiClipboardHolder multi = new MultiClipboardHolder(url.toURI(), worldData); + for (LazyClipboardHolder h : arr) multi.add(h); + return multi; + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } } private void write(OutputStream value, Clipboard clipboard) { diff --git a/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java b/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java index 4d4cb485..a1708345 100644 --- a/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java +++ b/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java @@ -1,6 +1,5 @@ package com.sk89q.worldedit.internal.expression.runtime; -import com.sk89q.worldedit.command.UtilityCommands; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.parser.ParserException; @@ -31,7 +30,7 @@ public class For extends Node { } if(Thread.currentThread().isInterrupted()){ - throw new EvaluationException(this.getPosition(), "Thread has been interuppted."); + throw new EvaluationException(this.getPosition(), "Thread has been interrupted."); } ++iterations; diff --git a/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java b/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java new file mode 100644 index 00000000..ae1aac9e --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java @@ -0,0 +1,107 @@ +/* + * 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 Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A simple-style for loop. + */ +public class SimpleFor extends Node { + + LValue counter; + RValue first; + RValue last; + RValue body; + + public SimpleFor(int position, LValue counter, RValue first, RValue last, RValue body) { + super(position); + + this.counter = counter; + this.first = first; + this.last = last; + this.body = body; + } + + @Override + public double getValue() throws EvaluationException { + int iterations = 0; + double ret = 0.0; + + double firstValue = first.getValue(); + double lastValue = last.getValue(); + + for (double i = firstValue; i <= lastValue; ++i) { + if (iterations > 256) { + throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); + } + if(Thread.currentThread().isInterrupted()){ + throw new EvaluationException(this.getPosition(), "Thread has been interrupted."); + } + ++iterations; + + try { + counter.assign(i); + ret = body.getValue(); + } catch (BreakException e) { + if (e.doContinue) { + //noinspection UnnecessaryContinue + continue; + } else { + break; + } + } + } + + return ret; + } + + @Override + public char id() { + return 'S'; + } + + @Override + public String toString() { + return "for (" + counter + " = " + first + ", " + last + ") { " + body + " }"; + } + + @Override + public RValue optimize() throws EvaluationException { + // TODO: unroll small loops into Sequences + + return new SimpleFor(getPosition(), counter.optimize(), first.optimize(), last.optimize(), body.optimize()); + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + counter = counter.bindVariables(expression, true); + first = first.bindVariables(expression, false); + last = last.bindVariables(expression, false); + body = body.bindVariables(expression, false); + + return this; + } + + public static Class inject() { + return SimpleFor.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java b/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java new file mode 100644 index 00000000..54c50825 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java @@ -0,0 +1,136 @@ +/* + * 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 Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.internal.expression.runtime; + +import com.sk89q.worldedit.internal.expression.Expression; +import com.sk89q.worldedit.internal.expression.parser.ParserException; + +/** + * A while loop. + */ +public class While extends Node { + + RValue condition; + RValue body; + boolean footChecked; + + public While(int position, RValue condition, RValue body, boolean footChecked) { + super(position); + + this.condition = condition; + this.body = body; + this.footChecked = footChecked; + } + + @Override + public double getValue() throws EvaluationException { + int iterations = 0; + double ret = 0.0; + + if (footChecked) { + do { + if (iterations > 256) { + throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); + } + if(Thread.currentThread().isInterrupted()){ + throw new EvaluationException(this.getPosition(), "Thread has been interrupted."); + } + ++iterations; + + try { + ret = body.getValue(); + } catch (BreakException e) { + if (e.doContinue) { + continue; + } else { + break; + } + } + } while (condition.getValue() > 0.0); + } else { + while (condition.getValue() > 0.0) { + if (iterations > 256) { + throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); + } + if(Thread.currentThread().isInterrupted()){ + throw new EvaluationException(this.getPosition(), "Thread has been interrupted."); + } + ++iterations; + + try { + ret = body.getValue(); + } catch (BreakException e) { + if (e.doContinue) { + //noinspection UnnecessaryContinue + continue; + } else { + break; + } + } + } + } + + return ret; + } + + @Override + public char id() { + return 'w'; + } + + @Override + public String toString() { + if (footChecked) { + return "do { " + body + " } while (" + condition + ")"; + } else { + return "while (" + condition + ") { " + body + " }"; + } + } + + @Override + public RValue optimize() throws EvaluationException { + final RValue newCondition = condition.optimize(); + + if (newCondition instanceof Constant && newCondition.getValue() <= 0) { + // If the condition is always false, the loop can be flattened. + if (footChecked) { + // Foot-checked loops run at least once. + return body.optimize(); + } else { + // Loops that never run always return 0.0. + return new Constant(getPosition(), 0.0); + } + } + + return new While(getPosition(), newCondition, body.optimize(), footChecked); + } + + @Override + public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { + condition = condition.bindVariables(expression, false); + body = body.bindVariables(expression, false); + + return this; + } + + public static Class inject() { + return While.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java b/core/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java index f3bc99ff..215b1ae9 100644 --- a/core/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java +++ b/core/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java @@ -25,6 +25,8 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.world.registry.WorldData; +import java.util.Collections; +import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; @@ -33,7 +35,6 @@ import static com.google.common.base.Preconditions.checkNotNull; * Holds the clipboard and the current transform on the clipboard. */ public class ClipboardHolder { - private final WorldData worldData; private Clipboard clipboard; private Transform transform = new Identity(); @@ -70,12 +71,36 @@ public class ClipboardHolder { * If there is a transformation applied, the returned clipboard will * not contain its effect. * + * @deprecated FAWE supports multiple loaded schematics {@link #getClipboards()} * @return the clipboard */ + @Deprecated public Clipboard getClipboard() { return clipboard; } + /** + * Get all currently held clipboards + * @return + */ + public List getClipboards() { + return Collections.singletonList(getClipboard()); + } + + public boolean contains(Clipboard clipboard) { + return this.clipboard == clipboard; + } + + /** + * Get all end ClipboardHolders
+ * - Usually this will return itself.
+ * - If this is a multi clipboard, it will return the children + * @return Set of end ClipboardHolders + */ + public List getHolders() { + return Collections.singletonList(this); + } + /** * Set the transform. * diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/LevelDBToMCAFile.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/LevelDBToMCAFile.java index f43d3cce..2f036141 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/LevelDBToMCAFile.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/core/converter/LevelDBToMCAFile.java @@ -164,7 +164,6 @@ public class LevelDBToMCAFile extends MapConverter { case PendingTicks: break; case BlockExtraData: - System.out.println("EXTRA " + chunk.getX() + "," + chunk.getZ()); break; case LegacyTerrain: case Data2DLegacy: diff --git a/settings.gradle b/settings.gradle index 6e74cb23..47c92782 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,3 @@ rootProject.name = 'FastAsyncWorldEdit' -include 'core', 'bukkit', 'favs', 'nukkit'//, 'forge1710', 'forge189', 'forge194', 'forge110', 'forge111', 'sponge', 'forge112', 'sponge111' \ No newline at end of file +include 'core', 'bukkit', 'favs', 'nukkit', 'forge1710', 'forge189', 'forge194', 'forge110', 'forge111', 'sponge', 'forge112', 'sponge111' \ No newline at end of file diff --git a/sponge/build.gradle b/sponge/build.gradle index a49680b4..4d6fdbee 100644 --- a/sponge/build.gradle +++ b/sponge/build.gradle @@ -22,7 +22,7 @@ buildscript { } plugins { - id 'org.spongepowered.plugin' version '0.6' + id 'org.spongepowered.plugin' version '0.8.1' } apply plugin: 'net.minecrell.vanilla.server.library' @@ -49,15 +49,14 @@ repositories { dependencies { compile project(':core') - compile 'org.spongepowered:spongeapi:6.1.0-SNAPSHOT' - compile 'org.spongepowered:mixin:0.7-SNAPSHOT' - compile 'com.sk89q.worldedit:worldedit-sponge:6.1.7-SNAPSHOT' - compile name: 'worldedit-core-6.1.7-SNAPSHOT-dist' + compile 'org.spongepowered:spongeapi:7.0.0-SNAPSHOT' + compile name: 'worldedit-sponge-6.1.9-SNAPSHOT-dist' + compile name: 'worldedit-core-6.1.9-SNAPSHOT-dist' } minecraft { version = "1.12" - mappings = "snapshot_20170726" + mappings = "snapshot_20170713" runDir = 'run' } diff --git a/sponge/lib/worldedit-core-6.1.9-SNAPSHOT-dist.jar b/sponge/lib/worldedit-core-6.1.9-SNAPSHOT-dist.jar new file mode 100644 index 00000000..3890b704 Binary files /dev/null and b/sponge/lib/worldedit-core-6.1.9-SNAPSHOT-dist.jar differ diff --git a/sponge/lib/worldedit-core-6.1.7-SNAPSHOT-dist.jar b/sponge/lib/worldedit-sponge-6.1.9-SNAPSHOT-dist.jar similarity index 85% rename from sponge/lib/worldedit-core-6.1.7-SNAPSHOT-dist.jar rename to sponge/lib/worldedit-sponge-6.1.9-SNAPSHOT-dist.jar index 2551c6fd..66cf0382 100644 Binary files a/sponge/lib/worldedit-core-6.1.7-SNAPSHOT-dist.jar and b/sponge/lib/worldedit-sponge-6.1.9-SNAPSHOT-dist.jar differ diff --git a/sponge/src/main/java/com/boydti/fawe/sponge/v1_12/SpongeChunk_1_12.java b/sponge/src/main/java/com/boydti/fawe/sponge/v1_12/SpongeChunk_1_12.java index a86755ef..eb848c08 100644 --- a/sponge/src/main/java/com/boydti/fawe/sponge/v1_12/SpongeChunk_1_12.java +++ b/sponge/src/main/java/com/boydti/fawe/sponge/v1_12/SpongeChunk_1_12.java @@ -258,24 +258,26 @@ public class SpongeChunk_1_12 extends CharFaweChunk { } // Trim tiles if (!tiles.isEmpty()) { - Set> entryset = tiles.entrySet(); - Iterator> iterator = entryset.iterator(); - while (iterator.hasNext()) { - Map.Entry tile = iterator.next(); - BlockPos pos = tile.getKey(); - int lx = pos.getX() & 15; - int ly = pos.getY(); - int lz = pos.getZ() & 15; - int j = FaweCache.CACHE_I[ly][lz][lx]; - char[] array = this.getIdArray(j); - if (array == null) { - continue; - } - int k = FaweCache.CACHE_J[ly][lz][lx]; - if (array[k] != 0) { - synchronized (SpongeChunk_1_12.class) { - iterator.remove(); - tile.getValue().invalidate(); + synchronized (SpongeChunk_1_12.class) { + Set> entryset = tiles.entrySet(); + Iterator> iterator = entryset.iterator(); + while (iterator.hasNext()) { + Map.Entry tile = iterator.next(); + BlockPos pos = tile.getKey(); + int lx = pos.getX() & 15; + int ly = pos.getY(); + int lz = pos.getZ() & 15; + int j = FaweCache.CACHE_I[ly][lz][lx]; + char[] array = this.getIdArray(j); + if (array == null) { + continue; + } + int k = FaweCache.CACHE_J[ly][lz][lx]; + if (array[k] != 0) { + synchronized (SpongeChunk_1_12.class) { + iterator.remove(); + tile.getValue().invalidate(); + } } } } diff --git a/sponge/src/main/resources/config.yml b/sponge/src/main/resources/config.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/sponge111/src/main/java/com/boydti/fawe/sponge/v1_11/SpongeChunk_1_11.java b/sponge111/src/main/java/com/boydti/fawe/sponge/v1_11/SpongeChunk_1_11.java index e2dc5646..c6ea5dd0 100644 --- a/sponge111/src/main/java/com/boydti/fawe/sponge/v1_11/SpongeChunk_1_11.java +++ b/sponge111/src/main/java/com/boydti/fawe/sponge/v1_11/SpongeChunk_1_11.java @@ -258,24 +258,26 @@ public class SpongeChunk_1_11 extends CharFaweChunk { } // Trim tiles if (!tiles.isEmpty()) { - Set> entryset = tiles.entrySet(); - Iterator> iterator = entryset.iterator(); - while (iterator.hasNext()) { - Map.Entry tile = iterator.next(); - BlockPos pos = tile.getKey(); - int lx = pos.getX() & 15; - int ly = pos.getY(); - int lz = pos.getZ() & 15; - int j = FaweCache.CACHE_I[ly][lz][lx]; - char[] array = this.getIdArray(j); - if (array == null) { - continue; - } - int k = FaweCache.CACHE_J[ly][lz][lx]; - if (array[k] != 0) { - synchronized (SpongeChunk_1_11.class) { - iterator.remove(); - tile.getValue().invalidate(); + synchronized (SpongeChunk_1_11.class) { + Set> entryset = tiles.entrySet(); + Iterator> iterator = entryset.iterator(); + while (iterator.hasNext()) { + Map.Entry tile = iterator.next(); + BlockPos pos = tile.getKey(); + int lx = pos.getX() & 15; + int ly = pos.getY(); + int lz = pos.getZ() & 15; + int j = FaweCache.CACHE_I[ly][lz][lx]; + char[] array = this.getIdArray(j); + if (array == null) { + continue; + } + int k = FaweCache.CACHE_J[ly][lz][lx]; + if (array[k] != 0) { + synchronized (SpongeChunk_1_11.class) { + iterator.remove(); + tile.getValue().invalidate(); + } } } }