Fix some chunk loading issues

Affected 1.8/1.7
Also improves performance for various operations
This commit is contained in:
Jesse Boyd 2017-02-13 02:55:19 +11:00
parent 897d86b5cb
commit 47999d323b
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
24 changed files with 762 additions and 279 deletions

View File

@ -193,7 +193,7 @@ public class BukkitQueue17 extends BukkitQueue_0<net.minecraft.server.v1_7_R4.Ch
net.minecraft.server.v1_7_R4.Chunk chunk;
net.minecraft.server.v1_7_R4.ChunkProviderServer provider = ((org.bukkit.craftbukkit.v1_7_R4.CraftWorld) world).getHandle().chunkProviderServer;
if (generate) {
return provider.getOrCreateChunk(x, z);
return provider.originalGetChunkAt(x, z);
} else {
return provider.loadChunk(x, z);
}

View File

@ -193,7 +193,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<net.minecraft.server.v1_8_R3.
net.minecraft.server.v1_8_R3.Chunk chunk;
net.minecraft.server.v1_8_R3.ChunkProviderServer provider = ((org.bukkit.craftbukkit.v1_8_R3.CraftWorld) world).getHandle().chunkProviderServer;
if (generate) {
return provider.getOrCreateChunk(x, z);
return provider.originalGetChunkAt(x, z);
} else {
return provider.loadChunk(x, z);
}

View File

@ -32,7 +32,7 @@ import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorCompletionService;
import javax.annotation.Nullable;
public abstract class FaweQueue {
public abstract class FaweQueue implements HasFaweQueue {
private World weWorld;
private String world;
@ -70,6 +70,11 @@ public abstract class FaweQueue {
ALL,
}
@Override
public FaweQueue getQueue() {
return this;
}
public Settings getSettings() {
return settings;
}
@ -386,6 +391,7 @@ public abstract class FaweQueue {
try {
return getCombinedId4Data(x, y, z);
} catch (FaweException ignore) {
ignore.printStackTrace();
return def;
}
}

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
@ -12,7 +13,7 @@ import java.io.InputStream;
public class FlattenBrush extends HeightBrush {
public FlattenBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard) {
super(stream, rotation, yscale, tool, clipboard);
super(stream, rotation, yscale, tool, clipboard, ScalableHeightMap.Shape.CYLINDER);
}
@Override

View File

@ -21,6 +21,10 @@ public class HeightBrush implements DoubleActionBrush {
public final DoubleActionBrushTool tool;
public HeightBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard) {
this(stream, rotation, yscale, tool, clipboard, ScalableHeightMap.Shape.CONE);
}
public HeightBrush(InputStream stream, int rotation, double yscale, DoubleActionBrushTool tool, Clipboard clipboard, ScalableHeightMap.Shape shape) {
this.tool = tool;
this.rotation = (rotation / 90) % 4;
this.yscale = yscale;
@ -33,7 +37,7 @@ public class HeightBrush implements DoubleActionBrush {
} else if (clipboard != null) {
heightMap = ScalableHeightMap.fromClipboard(clipboard);
} else {
heightMap = new ScalableHeightMap();
heightMap = ScalableHeightMap.fromShape(shape);
}
}

View File

@ -0,0 +1,17 @@
package com.boydti.fawe.object.brush.heightmap;
public class FlatScalableHeightMap extends ScalableHeightMap {
public FlatScalableHeightMap() {
super();
}
public double getHeight(int x, int z) {
int dx = Math.abs(x);
int dz = Math.abs(z);
int d2 = dx * dx + dz * dz;
if (d2 > size2) {
return 0;
}
return size;
}
}

View File

@ -28,6 +28,11 @@ public class ScalableHeightMap {
public int size2;
public int size;
public enum Shape {
CONE,
CYLINDER,
}
public ScalableHeightMap() {
setSize(5);
}
@ -51,6 +56,16 @@ public class ScalableHeightMap {
return size - MathMan.sqrtApprox(d2);
}
public static ScalableHeightMap fromShape(Shape shape) {
switch (shape) {
default:
case CONE:
return new ScalableHeightMap();
case CYLINDER:
return new FlatScalableHeightMap();
}
}
public static ScalableHeightMap fromClipboard(Clipboard clipboard) {
Vector dim = clipboard.getDimensions();
byte[][] heightArray = new byte[dim.getBlockX()][dim.getBlockZ()];

View File

@ -1,14 +1,19 @@
package com.boydti.fawe.object.clipboard;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
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.function.RegionFunction;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import java.util.List;
@ -43,52 +48,61 @@ public class WorldCopyClipboard extends ReadOnlyClipboard {
}
@Override
public void forEach(RunnableVal2<Vector, BaseBlock> task, boolean air) {
public void forEach(final RunnableVal2<Vector, BaseBlock> task, boolean air) {
MainUtil.stacktrace();
Vector min = region.getMinimumPoint();
Vector max = region.getMaximumPoint();
Vector pos = new Vector();
final Vector pos = new Vector();
if (region instanceof CuboidRegion) {
if (air) {
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
BaseBlock block = getBlockAbs(x, y, z);
pos.mutX(x - mx);
pos.mutY(y - my);
pos.mutZ(z - mz);
CompoundTag tag = block.getNbtData();
if (tag != null) {
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
values.put("x", new IntTag(pos.getBlockX()));
values.put("y", new IntTag(pos.getBlockY()));
values.put("z", new IntTag(pos.getBlockZ()));
}
task.run(pos, block);
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(Vector pos) throws WorldEditException {
int x = pos.getBlockX();
int y = pos.getBlockY();
int z = pos.getBlockZ();
BaseBlock block = getBlockAbs(x, y, z);
pos.mutX(x - mx);
pos.mutY(y - my);
pos.mutZ(z - mz);
CompoundTag tag = block.getNbtData();
if (tag != null) {
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
values.put("x", new IntTag(pos.getBlockX()));
values.put("y", new IntTag(pos.getBlockY()));
values.put("z", new IntTag(pos.getBlockZ()));
}
task.run(pos, block);
return true;
}
}
}, editSession);
Operations.completeBlindly(visitor);
} else {
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
BaseBlock block = getBlockAbs(x, y, z);
if (block == EditSession.nullBlock) {
continue;
}
pos.mutX(x - mx);
pos.mutY(y - my);
pos.mutZ(z - mz);
CompoundTag tag = block.getNbtData();
if (tag != null) {
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
values.put("x", new IntTag(pos.getBlockX()));
values.put("y", new IntTag(pos.getBlockY()));
values.put("z", new IntTag(pos.getBlockZ()));
}
task.run(pos, block);
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(Vector pos) throws WorldEditException {
int x = pos.getBlockX();
int y = pos.getBlockY();
int z = pos.getBlockZ();
BaseBlock block = getBlockAbs(x, y, z);
if (block == EditSession.nullBlock) {
return false;
}
pos.mutX(x - mx);
pos.mutY(y - my);
pos.mutZ(z - mz);
CompoundTag tag = block.getNbtData();
if (tag != null) {
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
values.put("x", new IntTag(pos.getBlockX()));
values.put("y", new IntTag(pos.getBlockY()));
values.put("z", new IntTag(pos.getBlockZ()));
}
task.run(pos, block);
return true;
}
}
}, editSession);
Operations.completeBlindly(visitor);
}
} else {
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {

View File

@ -0,0 +1,29 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.boydti.fawe.object.function.block;
import com.google.common.base.Preconditions;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.patterns.Pattern;
public class LegacyBlockReplace implements RegionFunction {
private final Extent extent;
private Pattern pattern;
public LegacyBlockReplace(Extent extent, Pattern pattern) {
Preconditions.checkNotNull(extent);
Preconditions.checkNotNull(pattern);
this.extent = extent;
this.pattern = pattern;
}
public boolean apply(Vector position) throws WorldEditException {
return this.extent.setBlock(position, this.pattern.next(position));
}
}

View File

@ -0,0 +1,114 @@
package com.boydti.fawe.object.visitor;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.MappedFaweQueue;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.extent.Extent;
import java.util.Iterator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class Fast2DIterator implements Iterable<Vector2D> {
private final Iterable<? extends Vector2D> iterable;
private final MappedFaweQueue queue;
public Fast2DIterator(@Nonnull Iterable<? extends Vector2D> iter, @Nullable EditSession extent) {
this(iter, (HasFaweQueue) extent);
}
public Fast2DIterator(@Nonnull Iterable<? extends Vector2D> iter, @Nullable Extent extent) {
this(iter, (HasFaweQueue) (extent != null ? (extent instanceof HasFaweQueue ? extent : new ExtentTraverser(extent).findAndGet(HasFaweQueue.class)) : null));
}
public Fast2DIterator(@Nonnull Iterable<? extends Vector2D> iter, @Nullable HasFaweQueue editSession) {
this(iter, (FaweQueue) editSession != null ? editSession.getQueue() : null);
}
public Fast2DIterator(@Nonnull Iterable<? extends Vector2D> iter, @Nullable FaweQueue faweQueue) {
this.iterable = iter;
this.queue = faweQueue != null && faweQueue instanceof MappedFaweQueue ? (MappedFaweQueue) faweQueue : null;
}
public Iterable<? extends Vector2D> getIterable() {
return iterable;
}
@Override
public Iterator<Vector2D> iterator() {
if (queue == null || Settings.IMP.QUEUE.PRELOAD_CHUNKS <= 1) {
return (Iterator<Vector2D>) iterable;
}
return new Iterator<Vector2D>() {
Iterator<? extends Vector2D> trailIter = iterable.iterator();
Iterator<? extends Vector2D> leadIter = iterable.iterator();
int lastTrailChunkX = Integer.MIN_VALUE;
int lastTrailChunkZ = Integer.MIN_VALUE;
int lastLeadChunkX = Integer.MIN_VALUE;
int lastLeadChunkZ = Integer.MIN_VALUE;
int loadingTarget = Settings.IMP.QUEUE.PRELOAD_CHUNKS;
int cx,cz;
@Override
public void remove() {
trailIter.remove();
}
@Override
public boolean hasNext() {
return trailIter.hasNext();
}
@Override
public Vector2D next() {
Vector2D pt = trailIter.next();
if (lastTrailChunkX != (lastTrailChunkX = pt.getBlockX() >> 4) || lastTrailChunkZ != (lastTrailChunkZ = pt.getBlockZ() >> 4)) {
if (leadIter.hasNext()) {
try {
int amount;
if (lastLeadChunkX == Integer.MIN_VALUE) {
lastLeadChunkX = cx;
lastLeadChunkZ = cz;
amount = loadingTarget;
} else {
amount = 1;
}
for (int count = 0; count < amount; ) {
Vector2D v = leadIter.next();
int vcx = v.getBlockX() >> 4;
int vcz = v.getBlockZ() >> 4;
if (vcx != lastLeadChunkX || vcz != lastLeadChunkZ) {
lastLeadChunkX = vcx;
lastLeadChunkZ = vcz;
queue.queueChunkLoad(vcx, vcz);
count++;
}
// Skip the next 15 blocks
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
}
} catch (Throwable ignore) {}
}
}
return pt;
}
};
}
}

View File

@ -0,0 +1,77 @@
package com.boydti.fawe.object.visitor;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.MappedFaweQueue;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.extent.Extent;
import java.util.Iterator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class FastChunkIterator implements Iterable<Vector2D> {
private final Iterable<? extends Vector2D> iterable;
private final MappedFaweQueue queue;
public FastChunkIterator(@Nonnull Iterable<? extends Vector2D> iter, @Nullable EditSession extent) {
this(iter, (HasFaweQueue) extent);
}
public FastChunkIterator(@Nonnull Iterable<? extends Vector2D> iter, @Nullable Extent extent) {
this(iter, (HasFaweQueue) (extent != null ? (extent instanceof HasFaweQueue ? extent : new ExtentTraverser(extent).findAndGet(HasFaweQueue.class)) : null));
}
public FastChunkIterator(@Nonnull Iterable<? extends Vector2D> iter, @Nullable HasFaweQueue editSession) {
this(iter, (FaweQueue) editSession != null ? editSession.getQueue() : null);
}
public FastChunkIterator(@Nonnull Iterable<? extends Vector2D> iter, @Nullable FaweQueue faweQueue) {
this.iterable = iter;
this.queue = faweQueue != null && faweQueue instanceof MappedFaweQueue ? (MappedFaweQueue) faweQueue : null;
}
public Iterable<? extends Vector2D> getIterable() {
return iterable;
}
@Override
public Iterator<Vector2D> iterator() {
if (queue == null || Settings.IMP.QUEUE.PRELOAD_CHUNKS <= 1) {
return (Iterator<Vector2D>) iterable;
}
final Iterator<? extends Vector2D> trailIter = iterable.iterator();
final Iterator<? extends Vector2D> leadIter = iterable.iterator();
int amount = Settings.IMP.QUEUE.PRELOAD_CHUNKS;
for (int i = 0; i < Settings.IMP.QUEUE.PRELOAD_CHUNKS && leadIter.hasNext(); i++) {
Vector2D toLoad = leadIter.next();
queue.queueChunkLoad(toLoad.getBlockX(), toLoad.getBlockZ());
}
if (!leadIter.hasNext()) {
return (Iterator<Vector2D>) trailIter;
}
return new Iterator<Vector2D>() {
@Override
public void remove() {
trailIter.remove();
}
@Override
public boolean hasNext() {
return trailIter.hasNext();
}
@Override
public Vector2D next() {
if (leadIter.hasNext()) {
Vector2D toLoad = leadIter.next();
queue.queueChunkLoad(toLoad.getBlockX(), toLoad.getBlockZ());
}
return trailIter.next();
}
};
}
}

View File

@ -0,0 +1,114 @@
package com.boydti.fawe.object.visitor;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.MappedFaweQueue;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import java.util.Iterator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class FastIterator implements Iterable<Vector> {
private final Iterable<? extends Vector> iterable;
private final MappedFaweQueue queue;
public FastIterator(@Nonnull Iterable<? extends Vector> iter, @Nullable EditSession extent) {
this(iter, (HasFaweQueue) extent);
}
public FastIterator(@Nonnull Iterable<? extends Vector> iter, @Nullable Extent extent) {
this(iter, (HasFaweQueue) (extent != null ? (extent instanceof HasFaweQueue ? extent : new ExtentTraverser(extent).findAndGet(HasFaweQueue.class)) : null));
}
public FastIterator(@Nonnull Iterable<? extends Vector> iter, @Nullable HasFaweQueue editSession) {
this(iter, (FaweQueue) editSession != null ? editSession.getQueue() : null);
}
public FastIterator(@Nonnull Iterable<? extends Vector> iter, @Nullable FaweQueue faweQueue) {
this.iterable = iter;
this.queue = faweQueue != null && faweQueue instanceof MappedFaweQueue ? (MappedFaweQueue) faweQueue : null;
}
public Iterable<? extends Vector> getIterable() {
return iterable;
}
@Override
public Iterator<Vector> iterator() {
if (queue == null || Settings.IMP.QUEUE.PRELOAD_CHUNKS <= 1) {
return (Iterator<Vector>) iterable;
}
return new Iterator<Vector>() {
Iterator<? extends Vector> trailIter = iterable.iterator();
Iterator<? extends Vector> leadIter = iterable.iterator();
int lastTrailChunkX = Integer.MIN_VALUE;
int lastTrailChunkZ = Integer.MIN_VALUE;
int lastLeadChunkX = Integer.MIN_VALUE;
int lastLeadChunkZ = Integer.MIN_VALUE;
int loadingTarget = Settings.IMP.QUEUE.PRELOAD_CHUNKS;
int cx,cz;
@Override
public void remove() {
trailIter.remove();
}
@Override
public boolean hasNext() {
return trailIter.hasNext();
}
@Override
public Vector next() {
Vector pt = trailIter.next();
if (lastTrailChunkX != (lastTrailChunkX = pt.getBlockX() >> 4) || lastTrailChunkZ != (lastTrailChunkZ = pt.getBlockZ() >> 4)) {
if (leadIter.hasNext()) {
try {
int amount;
if (lastLeadChunkX == Integer.MIN_VALUE) {
lastLeadChunkX = cx;
lastLeadChunkZ = cz;
amount = loadingTarget;
} else {
amount = 1;
}
for (int count = 0; count < amount; ) {
Vector v = leadIter.next();
int vcx = v.getBlockX() >> 4;
int vcz = v.getBlockZ() >> 4;
if (vcx != lastLeadChunkX || vcz != lastLeadChunkZ) {
lastLeadChunkX = vcx;
lastLeadChunkZ = vcz;
queue.queueChunkLoad(vcx, vcz);
count++;
}
// Skip the next 15 blocks
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
leadIter.next();
}
} catch (Throwable ignore) {}
}
}
return pt;
}
};
}
}

View File

@ -50,6 +50,11 @@ public class ExtentTraverser<T extends Extent> {
}
}
public <U> U findAndGet(Class<U> clazz) {
ExtentTraverser<Extent> traverser = find(clazz);
return (traverser != null) ? (U) traverser.get() : null;
}
public <U extends Extent> ExtentTraverser<U> find(Class<U> clazz) {
try {
ExtentTraverser<T> value = this;

View File

@ -72,7 +72,6 @@ public final class NBTOutputStream implements Closeable {
public void writeNamedTag(String name, Tag tag) throws IOException {
checkNotNull(name);
checkNotNull(tag);
int type = NBTUtils.getTypeCode(tag.getClass());
writeNamedTagName(name, type);
if (type == NBTConstants.TYPE_END) {

View File

@ -52,8 +52,10 @@ import com.boydti.fawe.object.extent.ProcessedWEExtent;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.object.extent.SlowExtent;
import com.boydti.fawe.object.extent.SourceMaskExtent;
import com.boydti.fawe.object.function.block.LegacyBlockReplace;
import com.boydti.fawe.object.mask.ResettableMask;
import com.boydti.fawe.object.progress.DefaultProgressTracker;
import com.boydti.fawe.object.visitor.FastChunkIterator;
import com.boydti.fawe.util.ExtentTraverser;
import com.boydti.fawe.util.MaskTraverser;
import com.boydti.fawe.util.MemUtil;
@ -76,6 +78,7 @@ import com.sk89q.worldedit.extent.MaskingExtent;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.extent.world.SurvivalModeExtent;
import com.sk89q.worldedit.function.GroundFunction;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.RegionMaskingFilter;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.block.Naturalizer;
@ -106,6 +109,7 @@ import com.sk89q.worldedit.history.change.BlockChange;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.internal.expression.runtime.RValue;
import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation;
import com.sk89q.worldedit.math.interpolation.Node;
@ -216,20 +220,6 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
player = FawePlayer.wrap(event.getActor());
}
this.player = player;
if (changeSet == null) {
if (Settings.IMP.HISTORY.USE_DISK) {
UUID uuid = player == null ? CONSOLE : player.getUUID();
if (Settings.IMP.HISTORY.USE_DATABASE) {
changeSet = new RollbackOptimizedHistory(world, uuid);
} else {
changeSet = new DiskStorageHistory(world, uuid);
}
} else if (Settings.IMP.HISTORY.COMBINE_STAGES && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) {
changeSet = new CPUOptimizedChangeSet(world);
} else {
changeSet = new MemoryOptimizedHistory(world);
}
}
if (limit == null) {
if (player == null) {
limit = FaweLimit.MAX;
@ -286,7 +276,21 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), bus, event, Stage.BEFORE_CHANGE);
this.bypassHistory = (this.extent = wrapExtent(bypassAll, bus, event, Stage.BEFORE_REORDER));
if (!fastmode) {
if (!fastmode || changeSet != null) {
if (changeSet == null) {
if (Settings.IMP.HISTORY.USE_DISK) {
UUID uuid = player == null ? CONSOLE : player.getUUID();
if (Settings.IMP.HISTORY.USE_DATABASE) {
changeSet = new RollbackOptimizedHistory(world, uuid);
} else {
changeSet = new DiskStorageHistory(world, uuid);
}
} else if (Settings.IMP.HISTORY.COMBINE_STAGES && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) {
changeSet = new CPUOptimizedChangeSet(world);
} else {
changeSet = new MemoryOptimizedHistory(world);
}
}
if (limit.SPEED_REDUCTION > 0) {
this.bypassHistory = new SlowExtent(this.bypassHistory, limit.SPEED_REDUCTION);
}
@ -610,6 +614,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
public void addTransform(ResettableExtent transform) {
wrapped = true;
if (transform == null) {
ExtentTraverser<AbstractDelegateExtent> traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class);
AbstractDelegateExtent next = extent;
@ -1152,9 +1157,9 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
*/
@SuppressWarnings("deprecation")
private int setBlocks(final Set<Vector> vset, final Pattern pattern) throws MaxChangedBlocksException {
for (final Vector v : vset) {
changes += this.setBlock(v, pattern) ? 1 : 0;
}
RegionVisitor visitor = new RegionVisitor(vset, new LegacyBlockReplace(extent, pattern), this);
Operations.completeBlindly(visitor);
changes += visitor.getAffected();
return changes;
}
@ -1219,12 +1224,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
context.setExtent(editSession.bypassAll);
ChangeSet changeSet = getChangeSet();
editSession.getQueue().setChangeTask(null);
Operations.completeSmart(ChangeSetExecutor.create(changeSet, context, ChangeSetExecutor.Type.UNDO, editSession.getBlockBag(), editSession.getLimit().INVENTORY_MODE), new Runnable() {
@Override
public void run() {
editSession.flushQueue();
}
}, true);
Operations.completeBlindly(ChangeSetExecutor.create(changeSet, context, ChangeSetExecutor.Type.UNDO, editSession.getBlockBag(), editSession.getLimit().INVENTORY_MODE));
editSession.changes = 1;
}
@ -1238,12 +1238,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
context.setExtent(editSession.bypassAll);
ChangeSet changeSet = getChangeSet();
editSession.getQueue().setChangeTask(null);
Operations.completeSmart(ChangeSetExecutor.create(changeSet, context, ChangeSetExecutor.Type.REDO, editSession.getBlockBag(), editSession.getLimit().INVENTORY_MODE), new Runnable() {
@Override
public void run() {
editSession.flushQueue();
}
}, true);
Operations.completeBlindly(ChangeSetExecutor.create(changeSet, context, ChangeSetExecutor.Type.REDO, editSession.getBlockBag(), editSession.getLimit().INVENTORY_MODE));
editSession.changes = 1;
}
@ -1340,12 +1335,15 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
return 0;
}
if (searchIDs.size() == 1) {
int count = 0;
int id = searchIDs.iterator().next();
for (final Vector pt : region) {
if (this.getBlockType(pt) == id) count++;
}
return count;
final int id = searchIDs.iterator().next();
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(Vector position) throws WorldEditException {
return getBlockType(position) == id;
}
}, this);
Operations.completeBlindly(visitor);
return visitor.getAffected();
}
final boolean[] ids = new boolean[256];
for (final int id : searchIDs) {
@ -1357,14 +1355,14 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
public int countBlock(final Region region, final boolean[] ids) {
int count = 0;
for (final Vector pt : region) {
final int id = this.getBlockType(pt);
if (ids[id]) {
count++;
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(Vector position) throws WorldEditException {
return ids[getBlockType(position)];
}
}
return count;
}, this);
Operations.completeBlindly(visitor);
return visitor.getAffected();
}
/**
@ -1375,42 +1373,48 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
* @return the number of blocks that matched the pattern
*/
public int countBlocks(final Region region, final Set<BaseBlock> searchBlocks) {
BlockMask mask = new BlockMask(extent, searchBlocks);
int count = 0;
for (final Vector pt : region) {
if (mask.test(pt)) {
count++;
final BlockMask mask = new BlockMask(extent, searchBlocks);
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(Vector position) throws WorldEditException {
return mask.test(position);
}
}
return count;
}, this);
Operations.completeBlindly(visitor);
return visitor.getAffected();
}
public int fall(final Region region, boolean fullHeight, BaseBlock replace) {
public int fall(final Region region, boolean fullHeight, final BaseBlock replace) {
FlatRegion flat = asFlatRegion(region);
int startPerformY = region.getMinimumPoint().getBlockY();
int startCheckY = fullHeight ? 0 : startPerformY;
int endY = region.getMaximumPoint().getBlockY();
for (BlockVector pos : flat) {
int x = pos.getBlockX();
int z = pos.getBlockZ();
int freeSpot = startCheckY;
for (int y = startCheckY; y <= endY; y++) {
if (y < startPerformY) {
if (getLazyBlock(x, y, z) != EditSession.nullBlock) {
freeSpot = y + 1;
final int startPerformY = region.getMinimumPoint().getBlockY();
final int startCheckY = fullHeight ? 0 : startPerformY;
final int endY = region.getMaximumPoint().getBlockY();
RegionVisitor visitor = new RegionVisitor(flat, new RegionFunction() {
@Override
public boolean apply(Vector pos) throws WorldEditException {
int x = pos.getBlockX();
int z = pos.getBlockZ();
int freeSpot = startCheckY;
for (int y = startCheckY; y <= endY; y++) {
if (y < startPerformY) {
if (getLazyBlock(x, y, z) != EditSession.nullBlock) {
freeSpot = y + 1;
}
continue;
}
continue;
}
BaseBlock block = getLazyBlock(x, y, z);
if (block != EditSession.nullBlock) {
if (freeSpot != y) {
setBlock(x, freeSpot, z, block);
setBlock(x, y, z, replace);
BaseBlock block = getLazyBlock(x, y, z);
if (block != EditSession.nullBlock) {
if (freeSpot != y) {
setBlock(x, freeSpot, z, block);
setBlock(x, y, z, replace);
}
freeSpot++;
}
freeSpot++;
}
return true;
}
}
}, this);
Operations.completeBlindly(visitor);
return this.changes;
}
@ -1466,12 +1470,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
visitor.visit(origin);
// Execute
Operations.completeSmart(visitor, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(visitor);
return this.changes = visitor.getAffected();
}
@ -1565,6 +1564,10 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
return true;
}
public boolean hasExtraExtents() {
return wrapped || getMask() != null || getSourceMask() != null || history != null;
}
/**
* Sets all the blocks inside a region to a given block type.
*
@ -1580,11 +1583,17 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
if (canBypassAll(region, false, true) && !block.hasNbtData()) {
return changes = queue.setBlocks((CuboidRegion) region, block.getId(), block.getData());
}
Iterator<BlockVector> iter = region.iterator();
try {
while (iter.hasNext()) {
if (this.extent.setBlock(iter.next(), block)) {
changes++;
if (hasExtraExtents()) {
RegionVisitor visitor = new RegionVisitor(region, new LegacyBlockReplace(extent, new SingleBlockPattern(block)), this);
Operations.completeBlindly(visitor);
this.changes += visitor.getAffected();
} else {
Iterator<BlockVector> iter = region.iterator();
while (iter.hasNext()) {
if (this.extent.setBlock(iter.next(), block)) {
changes++;
}
}
}
} catch (final MaxChangedBlocksException e) {
@ -1612,12 +1621,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
final BlockReplace replace = new BlockReplace(EditSession.this, Patterns.wrap(pattern));
final RegionVisitor visitor = new RegionVisitor(region, replace, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null);
Operations.completeSmart(visitor, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(visitor);
return this.changes = visitor.getAffected();
}
@ -1682,12 +1686,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final BlockReplace replace = new BlockReplace(EditSession.this, Patterns.wrap(pattern));
final RegionMaskingFilter filter = new RegionMaskingFilter(mask, replace);
final RegionVisitor visitor = new RegionVisitor(region, filter, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null);
Operations.completeSmart(visitor, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(visitor);
return this.changes = visitor.getAffected();
}
@ -1866,12 +1865,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final RegionOffset offset = new RegionOffset(new Vector(0, 1, 0), replace);
final GroundFunction ground = new GroundFunction(new ExistingBlockMask(EditSession.this), offset);
final LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground);
Operations.completeSmart(visitor, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(visitor);
return this.changes = ground.getAffected();
}
@ -1888,12 +1882,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final Naturalizer naturalizer = new Naturalizer(EditSession.this);
final FlatRegion flatRegion = Regions.asFlatRegion(region);
final LayerVisitor visitor = new LayerVisitor(flatRegion, minimumBlockY(region), maximumBlockY(region), naturalizer);
Operations.completeSmart(visitor, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(visitor);
return this.changes = naturalizer.getAffected();
}
@ -1925,12 +1914,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
if (!copyAir) {
copy.setSourceMask(new ExistingBlockMask(EditSession.this));
}
Operations.completeSmart(copy, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(copy);
return this.changes = copy.getAffected();
}
@ -1982,12 +1966,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
if (!copyAir) {
copy.setSourceMask(new ExistingBlockMask(EditSession.this));
}
Operations.completeSmart(copy, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(copy);
return this.changes = copy.getAffected();
}
@ -2044,12 +2023,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
}
Operations.completeSmart(visitor, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(visitor);
return this.changes = visitor.getAffected();
}
@ -2108,12 +2082,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
}
Operations.completeSmart(visitor, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(visitor);
return visitor.getAffected();
}
@ -2524,12 +2493,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final GroundFunction ground = new GroundFunction(new ExistingBlockMask(EditSession.this), generator);
final LayerVisitor visitor = new LayerVisitor(region, minimumBlockY(region), maximumBlockY(region), ground);
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
Operations.completeSmart(visitor, new Runnable() {
@Override
public void run() {
EditSession.this.flushQueue();
}
}, true);
Operations.completeBlindly(visitor);
return this.changes = ground.getAffected();
}
@ -2734,18 +2698,32 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final RValue z = expression.getVariable("z", false);
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero);
expression.setEnvironment(environment);
for (BlockVector position : region) {
// offset, scale
final Vector scaled = position.subtract(zero).divide(unit);
// transform
expression.evaluate(scaled.getX(), scaled.getY(), scaled.getZ());
final BlockVector sourcePosition = environment.toWorld(x.getValue(), y.getValue(), z.getValue());
// read block from world
BaseBlock material = FaweCache.CACHE_BLOCK[this.queue.getCombinedId4DataDebug(sourcePosition.getBlockX(), sourcePosition.getBlockY(), sourcePosition.getBlockZ(), 0, this)];
// queue operation
this.setBlockFast(position, material);
}
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
private MutableBlockVector mutable = new MutableBlockVector();
@Override
public boolean apply(Vector position) throws WorldEditException {
try {
int mx = (position.getBlockX() - zero.getBlockX()) / unit.getBlockX();
int my = (position.getBlockY() - zero.getBlockY()) / unit.getBlockY();
int mz = (position.getBlockZ() - zero.getBlockZ()) / unit.getBlockZ();
mutable.setComponents(mx, my, mz);
// final Vector scaled = position.subtract(zero).divide(unit);
// transform
expression.evaluate(mutable.getX(), mutable.getY(), mutable.getZ());
final BlockVector sourcePosition = environment.toWorld(x.getValue(), y.getValue(), z.getValue());
// read block from world
BaseBlock material = FaweCache.CACHE_BLOCK[queue.getCombinedId4DataDebug(sourcePosition.getBlockX(), sourcePosition.getBlockY(), sourcePosition.getBlockZ(), 0, EditSession.this)];
// queue operation
return extent.setBlock(position, material);
} catch (EvaluationException e) {
throw new RuntimeException(e);
}
}
}, this);
Operations.completeBlindly(visitor);
changes += visitor.getAffected();
return changes;
}
@ -3044,7 +3022,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
for (final Vector recurseDirection : this.recurseDirections) {
queue.addLast(current.add(recurseDirection).toBlockVector());
}
} // while
}
}
public int makeBiomeShape(final Region region, final Vector zero, final Vector unit, final BaseBiome biomeType, final String expressionString, final boolean hollow) throws ExpressionException,
@ -3160,7 +3138,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
}
final Set<Vector2D> chunks = region.getChunks();
for (Vector2D chunk : chunks) {
for (Vector2D chunk : new FastChunkIterator(chunks, this)) {
final int cx = chunk.getBlockX();
final int cz = chunk.getBlockZ();
final int bx = cx << 4;

View File

@ -439,7 +439,7 @@ public class LocalSession {
return null;
}
public void remember(final EditSession editSession, final boolean append, final boolean sendMessage, int limitMb) {
public synchronized void remember(final EditSession editSession, final boolean append, final boolean sendMessage, int limitMb) {
// It should have already been flushed, but just in case!
editSession.flushQueue();
if (editSession == null || editSession.getChangeSet() == null || limitMb == 0 || ((historySize >> 20) > limitMb && !append)) {

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.visitor.Fast2DIterator;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
@ -33,23 +34,26 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.FlatRegionFunction;
import com.sk89q.worldedit.function.FlatRegionMaskingFilter;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.biome.BiomeReplace;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.Regions;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.BiomeData;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@ -124,11 +128,12 @@ public class BiomeCommands {
max = 0
)
@CommandPermissions("worldedit.biome.info")
public void biomeInfo(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void biomeInfo(Player player, LocalSession session, final EditSession editSession, CommandContext args) throws WorldEditException {
BiomeRegistry biomeRegistry = player.getWorld().getWorldData().getBiomeRegistry();
Set<BaseBiome> biomes = new HashSet<BaseBiome>();
String qualifier;
final int[] biomes = new int[256];
final String qualifier;
int size = 0;
if (args.hasFlag('t')) {
Vector blockPosition = player.getBlockTrace(300);
if (blockPosition == null) {
@ -137,34 +142,53 @@ public class BiomeCommands {
}
BaseBiome biome = player.getWorld().getBiome(blockPosition.toVector2D());
biomes.add(biome);
biomes[biome.getId()]++;
size = 1;
} else if (args.hasFlag('p')) {
BaseBiome biome = player.getWorld().getBiome(player.getPosition().toVector2D());
biomes.add(biome);
biomes[biome.getId()]++;
size = 1;
} else {
World world = player.getWorld();
Region region = session.getSelection(world);
if (region instanceof FlatRegion) {
for (Vector2D pt : ((FlatRegion) region).asFlatRegion()) {
biomes.add(world.getBiome(pt));
for (Vector2D pt : new Fast2DIterator(((FlatRegion) region).asFlatRegion(), editSession)) {
biomes[editSession.getBiome(pt).getId()]++;
size++;
}
} else {
for (Vector pt : region) {
biomes.add(world.getBiome(pt.toVector2D()));
}
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(Vector position) throws WorldEditException {
biomes[editSession.getBiome(position.toVector2D()).getId()]++;
return true;
}
}, editSession);
Operations.completeBlindly(visitor);
size += visitor.getAffected();
}
}
BBC.BIOME_LIST_HEADER.send(player, 1, 1);
for (BaseBiome biome : biomes) {
BiomeData data = biomeRegistry.getData(biome);
if (data != null) {
player.print(BBC.getPrefix() + " " + data.getName());
} else {
player.print(BBC.getPrefix() + " <? #" + biome.getId() + ">");
List<Countable<BaseBiome>> distribution = new ArrayList<>();
for (int i = 0; i < biomes.length; i++) {
int count = biomes[i];
if (count != 0) {
distribution.add(new Countable<BaseBiome>(new BaseBiome(i), count));
}
}
Collections.sort(distribution);
for (Countable<BaseBiome> c : distribution) {
BiomeData data = biomeRegistry.getData(c.getID());
String str = String.format("%-7s (%.3f%%) %s #%d",
String.valueOf(c.getAmount()),
c.getAmount() / (double) size * 100,
data == null ? "Unknown" : data.getName(),
c.getID().getId());
player.print(BBC.getPrefix() + str);
}
}
@Command(

View File

@ -35,7 +35,6 @@ import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
@ -48,6 +47,7 @@ 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,6 +55,7 @@ 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;
@ -69,7 +70,6 @@ import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import static com.google.common.base.Preconditions.checkNotNull;
@ -379,10 +379,10 @@ public class ClipboardCommands {
@CommandPermissions("worldedit.clipboard.place")
@Logging(PLACEMENT)
public void place(Player player, LocalSession session, final EditSession editSession,
@Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin,
@Switch('a') final boolean ignoreAirBlocks, @Switch('o') boolean atOrigin,
@Switch('s') boolean selectPasted) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
final Clipboard clipboard = holder.getClipboard();
Region region = clipboard.getRegion().clone();
final int maxY = editSession.getMaxY();
@ -412,20 +412,23 @@ public class ClipboardCommands {
final int relx = to.getBlockX() - origin.getBlockX();
final int rely = to.getBlockY() - origin.getBlockY();
final int relz = to.getBlockZ() - origin.getBlockZ();
Iterator<BlockVector> iter = region.iterator();
while (iter.hasNext()) {
BlockVector mutable = iter.next();
BaseBlock block = clipboard.getBlock(mutable);
if (block == EditSession.nullBlock && ignoreAirBlocks) {
continue;
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;
}
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);
}
}
}, 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();

View File

@ -204,8 +204,10 @@ public class SchematicCommands {
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
player.printError("Unknown filename: " + filename);
} catch (IOException e) {
e.printStackTrace();
player.printError("Schematic could not written: " + e.getMessage());
log.log(Level.WARNING, "Failed to write a saved clipboard", e);
}

View File

@ -32,7 +32,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.google.common.base.Preconditions.checkNotNull;
@ -139,6 +138,10 @@ public class SchematicWriter implements ClipboardWriter {
}
final DataOutputStream rawStream = outputStream.getOutputStream();
outputStream.writeLazyCompoundTag("Schematic", new NBTOutputStream.LazyWrite() {
private boolean hasAdd = false;
private boolean hasTile = false;
private boolean hasData = false;
@Override
public void write(NBTOutputStream out) throws IOException {
int volume = width * height * length;
@ -154,28 +157,20 @@ public class SchematicWriter implements ClipboardWriter {
out.writeNamedTag("WEOffsetY", new IntTag(offset.getBlockY()));
out.writeNamedTag("WEOffsetZ", new IntTag(offset.getBlockZ()));
out.writeNamedTagName("Data", NBTConstants.TYPE_BYTE_ARRAY);
out.getOutputStream().writeInt(volume);
clipboard.IMP.streamDatas(new NBTStreamer.ByteReader() {
@Override
public void run(int index, int byteValue) {
try {
rawStream.writeByte(byteValue);
} catch (IOException e) {
e.printStackTrace();
}
}
});
out.writeNamedTagName("Blocks", NBTConstants.TYPE_BYTE_ARRAY);
out.getOutputStream().writeInt(volume);
final AtomicBoolean hasAdd = new AtomicBoolean(false);
clipboard.IMP.streamIds(new NBTStreamer.ByteReader() {
@Override
public void run(int index, int byteValue) {
try {
if (byteValue >= 256) {
hasAdd.set(true);
hasAdd = true;
}
if (FaweCache.hasData(byteValue)) {
hasData = true;
}
if (FaweCache.hasNBT(byteValue)) {
hasTile = true;
}
rawStream.writeByte(byteValue);
} catch (IOException e) {
@ -184,7 +179,26 @@ public class SchematicWriter implements ClipboardWriter {
}
});
if (hasAdd.get()) {
out.writeNamedTagName("Data", NBTConstants.TYPE_BYTE_ARRAY);
out.getOutputStream().writeInt(volume);
if (hasData) {
clipboard.IMP.streamDatas(new NBTStreamer.ByteReader() {
@Override
public void run(int index, int byteValue) {
try {
rawStream.writeByte(byteValue);
} catch (IOException e) {
e.printStackTrace();
}
}
});
} else {
for (int i = 0; i < volume; i++) {
rawStream.write(0);
}
}
if (hasAdd) {
out.writeNamedTagName("AddBlocks", NBTConstants.TYPE_BYTE_ARRAY);
out.getOutputStream().writeInt(volume);
clipboard.IMP.streamIds(new NBTStreamer.ByteReader() {
@ -199,8 +213,10 @@ public class SchematicWriter implements ClipboardWriter {
});
}
final List<CompoundTag> tileEntities = clipboard.IMP.getTileEntities();
out.writeNamedTag("TileEntities", new ListTag(CompoundTag.class, tileEntities));
if (hasTile) {
final List<CompoundTag> tileEntities = clipboard.IMP.getTileEntities();
out.writeNamedTag("TileEntities", new ListTag(CompoundTag.class, tileEntities));
}
List<Tag> entities = new ArrayList<Tag>();
for (Entity entity : clipboard.getEntities()) {

View File

@ -23,6 +23,7 @@ import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.MappedFaweQueue;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
@ -41,6 +42,7 @@ import java.util.List;
public class RegionVisitor implements Operation {
public final Region region;
public final Iterable<? extends Vector> iterable;
public final RegionFunction function;
private final MappedFaweQueue queue;
public int affected = 0;
@ -60,9 +62,14 @@ public class RegionVisitor implements Operation {
}
public RegionVisitor(Region region, RegionFunction function, FaweQueue queue) {
this.region = region;
this((Iterable<BlockVector>) region, function, queue);
}
public RegionVisitor(Iterable<? extends Vector> iterable, RegionFunction function, HasFaweQueue hasQueue) {
region = (iterable instanceof Region) ? (Region) iterable : null;
this.iterable = iterable;
this.function = function;
this.queue = queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null;
this.queue = hasQueue != null && hasQueue.getQueue() instanceof MappedFaweQueue ? (MappedFaweQueue) hasQueue.getQueue() : null;
}
/**
@ -76,7 +83,7 @@ public class RegionVisitor implements Operation {
@Override
public Operation resume(final RunContext run) throws WorldEditException {
if (queue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS <= 1) {
if (queue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS > 1) {
/*
* The following is done to reduce iteration cost
* - Preload chunks just in time
@ -84,8 +91,8 @@ public class RegionVisitor implements Operation {
* - Stop iteration on exception instead of hasNext
* - Do not calculate the stacktrace as it is expensive
*/
Iterator<BlockVector> trailIter = region.iterator();
Iterator<BlockVector> leadIter = region.iterator();
Iterator<? extends Vector> trailIter = iterable.iterator();
Iterator<? extends Vector> leadIter = iterable.iterator();
int lastTrailChunkX = Integer.MIN_VALUE;
int lastTrailChunkZ = Integer.MIN_VALUE;
int lastLeadChunkX = Integer.MIN_VALUE;
@ -93,8 +100,8 @@ public class RegionVisitor implements Operation {
int loadingTarget = Settings.IMP.QUEUE.PRELOAD_CHUNKS;
try {
for (;;) {
BlockVector pt = trailIter.next();
function.apply(pt);
Vector pt = trailIter.next();
apply(pt);
int cx = pt.getBlockX() >> 4;
int cz = pt.getBlockZ() >> 4;
if (cx != lastTrailChunkX || cz != lastTrailChunkZ) {
@ -109,7 +116,7 @@ public class RegionVisitor implements Operation {
amount = 1;
}
for (int count = 0; count < amount;) {
BlockVector v = leadIter.next();
Vector v = leadIter.next();
int vcx = v.getBlockX() >> 4;
int vcz = v.getBlockZ() >> 4;
if (vcx != lastLeadChunkX || vcz != lastLeadChunkZ) {
@ -136,40 +143,43 @@ public class RegionVisitor implements Operation {
leadIter.next();
}
}
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
function.apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
}
} catch (Throwable ignore) {}
try {
for (;;) {
function.apply(trailIter.next());
function.apply(trailIter.next());
apply(trailIter.next());
apply(trailIter.next());
}
} catch (Throwable ignore) {}
affected = region.getArea();
} else {
for (Vector pt : region) {
if (function.apply(pt)) {
affected++;
}
for (Vector pt : iterable) {
apply(pt);
}
}
return null;
}
private void apply(Vector pt) throws WorldEditException {
if (function.apply(pt)) {
affected++;
}
}
@Override
public void cancel() {}

View File

@ -0,0 +1,55 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.patterns;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseBlock;
/**
* @deprecated See {@link com.sk89q.worldedit.function.pattern.Pattern}
*/
@Deprecated
public interface Pattern { //extends com.sk89q.worldedit.function.pattern.Pattern {
/**
* Get a block for a position. This return value of this method does
* not have to be consistent for the same position.
*
* @param position the position where a block is needed
* @return a block
*/
public BaseBlock next(Vector position);
/**
* Get a block for a position. This return value of this method does
* not have to be consistent for the same position.
*
* @param x the X coordinate
* @param y the Y coordinate
* @param z the Z coordinate
* @return a block
*/
public BaseBlock next(int x, int y, int z);
// @Override
// default BaseBlock apply(Vector position) {
// return next(position);
// }
}

View File

@ -129,7 +129,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
public Chunk loadChunk(World world, int x, int z, boolean generate) {
ChunkProviderServer provider = (ChunkProviderServer) world.getChunkProvider();
if (generate) {
return provider.provideChunk(x, z);
return provider.originalLoadChunk(x, z);
} else {
return provider.loadChunk(x, z);
}

View File

@ -98,7 +98,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
public Chunk loadChunk(World world, int x, int z, boolean generate) {
ChunkProviderServer provider = (ChunkProviderServer) world.getChunkProvider();
if (generate) {
return provider.provideChunk(x, z);
return provider.originalLoadChunk(x, z);
} else {
return provider.loadChunk(x, z);
}