Various minor

add debug command moveto512
main command aliases are now configurable
clean thread pools when discarded
switch to BaseBlock and deprecate BlockPattern
Add SparseBlockSet
- uncompressed, memory efficient set of arbitrary bit length numbers
- if access is sequencial, use a compressed data structure instead
change SetQueue time allocation algorithm
This commit is contained in:
Jesse Boyd 2017-06-26 17:56:07 +10:00
parent a7cd6c8715
commit d7d897d11b
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
34 changed files with 662 additions and 152 deletions

View File

@ -378,6 +378,7 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
iter.remove();
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool.shutdown();
}
synchronized (lock) {
lock.notifyAll();

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.object.collection.LocalBlockVector2DSet;
import com.boydti.fawe.object.collection.SummedAreaTable;
import com.boydti.fawe.object.schematic.Schematic;
@ -20,7 +21,6 @@ import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
@ -562,8 +562,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setOverlay(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockPattern) {
setOverlay(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
if (pattern instanceof BaseBlock) {
setOverlay(img, (char) ((BaseBlock) pattern).getCombined(), white);
return;
}
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
@ -584,8 +584,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setMain(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockPattern) {
setMain(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
if (pattern instanceof BaseBlock) {
setMain(img, (char) ((BaseBlock) pattern).getCombined(), white);
return;
}
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
@ -606,8 +606,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setFloor(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockPattern) {
setFloor(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
if (pattern instanceof BaseBlock) {
setFloor(img, (char) ((BaseBlock) pattern).getCombined(), white);
return;
}
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
@ -627,8 +627,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setColumn(BufferedImage img, Pattern pattern, boolean white) {
if (pattern instanceof BlockPattern) {
setColumn(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
if (pattern instanceof BaseBlock) {
setColumn(img, (char) ((BaseBlock) pattern).getCombined(), white);
return;
}
if (img.getWidth() != getWidth() || img.getHeight() != getLength())
@ -651,8 +651,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setOverlay(Mask mask, Pattern pattern) {
if (pattern instanceof BlockPattern) {
setOverlay(mask, (char) ((BlockPattern) pattern).getBlock().getCombined());
if (pattern instanceof BaseBlock) {
setOverlay(mask, (char) ((BaseBlock) pattern).getCombined());
return;
}
int index = 0;
@ -671,8 +671,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setFloor(Mask mask, Pattern pattern) {
if (pattern instanceof BlockPattern) {
setFloor(mask, (char) ((BlockPattern) pattern).getBlock().getCombined());
if (pattern instanceof BaseBlock) {
setFloor(mask, (char) ((BaseBlock) pattern).getCombined());
return;
}
int index = 0;
@ -690,8 +690,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setMain(Mask mask, Pattern pattern) {
if (pattern instanceof BlockPattern) {
setMain(mask, (char) ((BlockPattern) pattern).getBlock().getCombined());
if (pattern instanceof BaseBlock) {
setMain(mask, (char) ((BaseBlock) pattern).getCombined());
return;
}
modifiedMain = true;
@ -710,8 +710,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setColumn(Mask mask, Pattern pattern) {
if (pattern instanceof BlockPattern) {
setColumn(mask, (char) ((BlockPattern) pattern).getBlock().getCombined());
if (pattern instanceof BaseBlock) {
setColumn(mask, (char) ((BaseBlock) pattern).getCombined());
return;
}
modifiedMain = true;
@ -736,8 +736,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setFloor(Pattern value) {
if (value instanceof BlockPattern) {
setFloor(((BlockPattern) value).getBlock().getCombined());
if (value instanceof BaseBlock) {
setFloor(((BaseBlock) value).getCombined());
return;
}
int index = 0;
@ -753,8 +753,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setColumn(Pattern value) {
if (value instanceof BlockPattern) {
setColumn(((BlockPattern) value).getBlock().getCombined());
if (value instanceof BaseBlock) {
setColumn(((BaseBlock) value).getCombined());
return;
}
int index = 0;
@ -772,8 +772,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
public void setMain(Pattern value) {
if (value instanceof BlockPattern) {
setMain(((BlockPattern) value).getBlock().getCombined());
if (value instanceof BaseBlock) {
setMain(((BaseBlock) value).getCombined());
return;
}
int index = 0;
@ -790,8 +790,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
public void setOverlay(Pattern value) {
if (overlay == null) overlay = new char[getArea()];
if (value instanceof BlockPattern) {
setOverlay(((BlockPattern) value).getBlock().getCombined());
if (value instanceof BaseBlock) {
setOverlay(((BaseBlock) value).getCombined());
return;
}
int index = 0;
@ -1180,4 +1180,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
}
}
}
@Override
protected void finalize() throws Throwable {
IterableThreadLocal.clean(indexStore);
super.finalize();
}
}

View File

@ -9,11 +9,14 @@ import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.util.ArrayUtil;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTConstants;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.Tag;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@ -267,6 +270,27 @@ public class MCAChunk extends FaweChunk<Void> {
}
}
}
if (!other.tiles.isEmpty()) {
for (Map.Entry<Short, CompoundTag> entry : other.tiles.entrySet()) {
int key = entry.getKey();
int x = MathMan.untripleBlockCoordX(key);
int y = MathMan.untripleBlockCoordY(key);
int z = MathMan.untripleBlockCoordZ(key);
if (x < minX || x > maxX) continue;
if (z < minZ || z > maxZ) continue;
if (y < minY || y > maxY) continue;
x += offsetX;
y += offsetY;
z += offsetZ;
short pair = MathMan.tripleBlockCoord(x, y, z);
CompoundTag tag = entry.getValue();
Map<String, Tag> map = ReflectionUtils.getMap(tag.getValue());
map.put("x", new IntTag(x + (getX() << 4)));
map.put("y", new IntTag(y));
map.put("z", new IntTag(z + (getZ() << 4)));
tiles.put(pair, tag);
}
}
}
public void copyFrom(MCAChunk other, int minY, int maxY, int offsetY) {
@ -746,6 +770,57 @@ public class MCAChunk extends FaweChunk<Void> {
entities.remove(uuid);
}
private final boolean idsEqual(byte[] a, byte[] b) {
// Assumes both are null, or none are (idsEqual - 2d array)
// Assumes length is 4096
if (a == b) return true;
for (char i = 0; i < 4096; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
private final boolean idsEqual(byte[][] a, byte[][] b, boolean matchNullToAir) {
// Assumes length is 16
for (byte i = 0; i < 16; i++) {
if ((a[i] == null) != (b[i] == null)) {
if (matchNullToAir) {
if (b[i] != null) {
for (byte c : b[i]) {
if (c != 0) return false;
}
} else if (a[i] != null) {
for (byte c : a[i]) {
if (c != 0) return false;
}
}
}
return false;
}
}
// Check the chunks close to the ground first
for (byte i = 4; i < 8; i++) {
if (!idsEqual(a[i], b[i])) return false;
}
for (byte i = 3; i >= 0; i--) {
if (!idsEqual(a[i], b[i])) return false;
}
for (byte i = 8; i < 16; i++) {
if (!idsEqual(a[i], b[i])) return false;
}
return true;
}
/**
* Check if the ids match the ids in the other chunk
* @param other
* @param matchNullToAir
* @return
*/
public boolean idsEqual(MCAChunk other, boolean matchNullToAir) {
return idsEqual(other.ids, this.ids, matchNullToAir);
}
@Override
public Void getChunk() {
throw new UnsupportedOperationException("Not applicable for this");

View File

@ -5,6 +5,7 @@ import com.boydti.fawe.jnbt.NBTStreamer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.RunnableVal4;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
import com.boydti.fawe.object.io.FastByteArrayInputStream;
@ -97,6 +98,14 @@ public class MCAFile {
locations = null;
}
@Override
protected void finalize() throws Throwable {
IterableThreadLocal.clean(byteStore1);
IterableThreadLocal.clean(byteStore2);
IterableThreadLocal.clean(byteStore3);
super.finalize();
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
@ -573,5 +582,8 @@ public class MCAFile {
}
}
}
IterableThreadLocal.clean(byteStore1);
IterableThreadLocal.clean(byteStore2);
IterableThreadLocal.clean(byteStore3);
}
}

View File

@ -10,6 +10,7 @@ import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.RunnableVal4;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.Vector;
@ -38,6 +39,12 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
}
};
@Override
protected void finalize() throws Throwable {
IterableThreadLocal.clean(blockStore);
super.finalize();
}
public MCAQueue(FaweQueue parent) {
super(parent.getWEWorld(), new MCAQueueMap());
this.parent = parent;
@ -82,6 +89,59 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
}
}
/**
*
* @param newChunk
* @param bx
* @param tx
* @param bz
* @param tz
* @param oX
* @param oZ
* @return true if the newChunk has been changed
*/
public boolean copyTo(MCAChunk newChunk, int bx, int tx, int bz, int tz, int oX, int oZ) {
int obx = bx - oX;
int obz = bz - oZ;
int otx = tx - oX;
int otz = tz - oZ;
int otherBCX = (obx) >> 4;
int otherBCZ = (obz) >> 4;
int otherTCX = (otx) >> 4;
int otherTCZ = (otz) >> 4;
int cx = newChunk.getX();
int cz = newChunk.getZ();
int cbx = (cx << 4) - oX;
int cbz = (cz << 4) - oZ;
boolean changed = false;
for (int otherCZ = otherBCZ; otherCZ <= otherTCZ; otherCZ++) {
for (int otherCX = otherBCX; otherCX <= otherTCX; otherCX++) {
FaweChunk chunk;
synchronized (this) {
chunk = this.getFaweChunk(otherCX, otherCZ);
}
if (!(chunk instanceof NullFaweChunk)) {
changed = true;
MCAChunk other = (MCAChunk) chunk;
int ocbx = otherCX << 4;
int ocbz = otherCZ << 4;
int octx = ocbx + 15;
int octz = ocbz + 15;
int offsetY = 0;
int minX = obx > ocbx ? (obx - ocbx) & 15 : 0;
int maxX = otx < octx ? (otx - ocbx) : 15;
int minZ = obz > ocbz ? (obz - ocbz) & 15 : 0;
int maxZ = otz < octz ? (otz - ocbz) : 15;
int offsetX = ocbx - cbx;
int offsetZ = ocbz - cbz;
newChunk.copyFrom(other, minX, maxX, 0, 255, minZ, maxZ, offsetX, offsetY, offsetZ);
}
}
}
return changed;
}
public void pasteRegion(MCAQueue from, final RegionWrapper regionFrom, Vector offset) throws IOException {
int oX = offset.getBlockX();
int oZ = offset.getBlockZ();
@ -206,6 +266,7 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
}
from.clear();
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool.shutdown();
}
public <G, T extends MCAFilter<G>> T filterRegion(final T filter, final RegionWrapper region) {

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
import com.boydti.fawe.util.MainUtil;
import java.io.File;
@ -103,8 +104,8 @@ public abstract class MCAWriter {
byte[] fileBuf = new byte[1 << 16];
int mcaXMin = 0;
int mcaZMin = 0;
int mcaXMax = mcaXMin + width >> 9;
int mcaZMax = mcaZMin + length >> 9;
int mcaXMax = mcaXMin + ((width - 1) >> 9);
int mcaZMax = mcaZMin + ((length - 1) >> 9);
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) {
@ -208,5 +209,9 @@ public abstract class MCAWriter {
}
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool.shutdown();
IterableThreadLocal.clean(byteStore1);
IterableThreadLocal.clean(byteStore2);
IterableThreadLocal.clean(deflateStore);
}
}

View File

@ -12,7 +12,6 @@ import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
import java.util.Arrays;
@ -33,7 +32,7 @@ public class SplatterBrush extends ScatterBrush {
if (solid) {
Pattern tmp;
try {
tmp = new BlockPattern(p.apply(position));
tmp = p.apply(position);
} catch (BiomePattern.BiomePatternException ignore) {
tmp = ignore.getPattern();
}

View File

@ -1,5 +1,9 @@
package com.boydti.fawe.object.collection;
import java.lang.ref.Reference;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@ -30,7 +34,86 @@ public abstract class IterableThreadLocal<T> extends ThreadLocal<T> implements I
return null;
}
public void clean() {
IterableThreadLocal.clean(this);
}
public static void clean(ThreadLocal instance) {
try {
ThreadGroup rootGroup = Thread.currentThread( ).getThreadGroup( );
ThreadGroup parentGroup;
while ( ( parentGroup = rootGroup.getParent() ) != null ) {
rootGroup = parentGroup;
}
Thread[] threads = new Thread[ rootGroup.activeCount() ];
if (threads.length != 0) {
while (rootGroup.enumerate(threads, true) == threads.length) {
threads = new Thread[threads.length * 2];
}
}
Field tl = Thread.class.getDeclaredField("threadLocals");
tl.setAccessible(true);
Method methodRemove = null;
for (Thread thread : threads) {
if (thread != null) {
Object tlm = tl.get(thread);
if (tlm != null) {
if (methodRemove == null) {
methodRemove = tlm.getClass().getDeclaredMethod("remove", ThreadLocal.class);
methodRemove.setAccessible(true);
}
methodRemove.invoke(tlm, instance);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void cleanAll() {
try {
// Get a reference to the thread locals table of the current thread
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalTable = threadLocalsField.get(thread);
// Get a reference to the array holding the thread local variables inside the
// ThreadLocalMap of the current thread
Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapClass.getDeclaredField("table");
tableField.setAccessible(true);
Object table = tableField.get(threadLocalTable);
// The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
// is a reference to the actual ThreadLocal variable
Field referentField = Reference.class.getDeclaredField("referent");
referentField.setAccessible(true);
for (int i = 0; i < Array.getLength(table); i++) {
// Each entry in the table array of ThreadLocalMap is an Entry object
// representing the thread local reference and its value
Object entry = Array.get(table, i);
if (entry != null) {
// Get a reference to the thread local object and remove it from the table
ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
clean(threadLocal);
}
}
} catch(Exception e) {
// We will tolerate an exception here and just log it
throw new IllegalStateException(e);
}
}
public final Collection<T> getAll() {
return Collections.unmodifiableCollection(allValues);
}
@Override
protected void finalize() throws Throwable {
clean(this);
super.finalize();
}
}

View File

@ -47,7 +47,7 @@ import java.io.Serializable;
* @version 1.0, 2009-03-17
* @since 1.6
*/
public class SparseBitSet implements Cloneable, Serializable {
public final class SparseBitSet implements Cloneable, Serializable {
/* My apologies for listing all the additional authors, but concepts, code,
and even comments have been re-used in this class definition from code in
the JDK that was written and/or maintained by these people. I owe a debt,
@ -541,14 +541,6 @@ public class SparseBitSet implements Cloneable, Serializable {
return cache.cardinality;
}
/**
* Sets the bit at the specified index to <code>false</code>.
*
* @param i a bit index.
* @throws IndexOutOfBoundsException if the specified index is negative
* or equal to Integer.MAX_VALUE.
* @since 1.6
*/
public void clear(int i) {
/* In the interests of speed, no check is made here on whether the
level3 block goes to all zero. This may be found and corrected
@ -559,13 +551,14 @@ public class SparseBitSet implements Cloneable, Serializable {
return;
final int w = i >> SHIFT3;
long[][] a2;
if ((a2 = bits[w >> SHIFT1]) == null)
int ws1 = w >> SHIFT1;
if (bits.length <= ws1 || (a2 = bits[ws1]) == null)
return;
long[] a3;
if ((a3 = a2[(w >> SHIFT2) & MASK2]) == null)
return;
a3[w & MASK3] &= ~(1L << i); // Clear the indicated bit
cache.hash = 0; // Invalidate size, etc.,
cache.hash = 0; // Invalidate size, etc.,
}
/**
@ -1798,6 +1791,7 @@ public class SparseBitSet implements Cloneable, Serializable {
long[][] a2;
long[] a3;
long word;
int last = 0;
for (int w1 = 0; w1 != aLength1; ++w1)
if ((a2 = a1[w1]) != null)
for (int w2 = 0; w2 != LENGTH2; ++w2)
@ -1805,7 +1799,7 @@ public class SparseBitSet implements Cloneable, Serializable {
final int base = (w1 << SHIFT1) + (w2 << SHIFT2);
for (int w3 = 0; w3 != LENGTH3; ++w3)
if ((word = a3[w3]) != 0) {
s.writeInt(base + w3);
s.writeInt(-last + (last = (base + w3)));
s.writeLong(word);
--count;
}
@ -1844,8 +1838,9 @@ public class SparseBitSet implements Cloneable, Serializable {
/* Read the keys and values, them into the set array, areas, and blocks. */
long[][] a2;
long[] a3;
int w = 0;
for (int n = 0; n != count; ++n) {
final int w = s.readInt();
w += s.readInt();
final int w3 = w & MASK3;
final int w2 = (w >> SHIFT2) & MASK2;
final int w1 = w >> SHIFT1;

View File

@ -0,0 +1,36 @@
package com.boydti.fawe.object.collection;
import java.io.Serializable;
public class SparseBlockSet implements Serializable {
private SparseBitSet[] sets;
public SparseBlockSet(int depth) {
sets = new SparseBitSet[depth];
for (int i = 0; i < sets.length; i++) {
sets[i] = new SparseBitSet();
}
}
public void setBlock(int index, int id) {
for (int i = 0; i < sets.length; i++) {
SparseBitSet set = sets[i];
if (((id >> i) & 1) == 1) {
set.set(index);
} else {
set.clear(index);
}
}
}
public int getBlock(int index) {
int id = 0;
for (int i = 0; i < sets.length; i++) {
SparseBitSet set = sets[i];
if (set.get(index)) {
id += 1 << i;
}
}
return id;
}
}

View File

@ -60,7 +60,7 @@ import javax.imageio.ImageIO;
aliases = {"createfromheightmap", "createfromimage", "cfhm"},
category = CommandCategory.APPEARANCE,
requiredType = RequiredType.NONE,
description = "Generate a world from an image heightmap: [More info](https://www.youtube.com/watch?v=cJZk1GTig7A)",
description = "Generate a world from an image heightmap: [More info](https://goo.gl/friFbV)",
usage = "/plots cfi [url or dimensions]"
)
public class CreateFromImage extends Command {

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.regions.general.plot;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.example.NullFaweChunk;
import com.boydti.fawe.jnbt.anvil.MCAChunk;
import com.boydti.fawe.jnbt.anvil.MCAQueue;
@ -13,6 +14,8 @@ import com.intellectualcrafters.plot.commands.CommandCategory;
import com.intellectualcrafters.plot.commands.MainCommand;
import com.intellectualcrafters.plot.commands.RequiredType;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.database.DBFunc;
import com.intellectualcrafters.plot.database.SQLManager;
import com.intellectualcrafters.plot.generator.HybridPlotWorld;
import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot;
@ -27,6 +30,11 @@ import com.plotsquared.general.commands.Command;
import com.plotsquared.general.commands.CommandDeclaration;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.World;
@CommandDeclaration(
command = "moveto512",
@ -41,8 +49,107 @@ public class MoveTo512 extends Command {
super(MainCommand.getInstance(), true);
}
public static void main(String[] args) {
private MCAChunk emptyPlot(MCAChunk chunk, HybridPlotWorld hpw) {
int maxLayer = (hpw.PLOT_HEIGHT) >> 4;
for (int i = maxLayer + 1; i < chunk.ids.length; i++) {
chunk.ids[i] = null;
chunk.data[i] = null;
}
for (int layer = 0; layer <= maxLayer; layer++) {
byte[] ids = chunk.ids[layer];
if (ids == null) {
ids = chunk.ids[layer] = new byte[4096];
chunk.data[layer] = new byte[2048];
chunk.skyLight[layer] = new byte[2048];
chunk.blockLight[layer] = new byte[2048];
} else {
Arrays.fill(ids, (byte) 0);
Arrays.fill(chunk.data[layer], (byte) 0);
Arrays.fill(chunk.skyLight[layer], (byte) 0);
Arrays.fill(chunk.blockLight[layer], (byte) 0);
}
if (layer == maxLayer) {
int yMax = hpw.PLOT_HEIGHT & 15;
for (int y = yMax + 1; y < 15; y++) {
Arrays.fill(chunk.skyLight[layer], y << 7, (y << 7) + 128, (byte) 255);
}
if (layer == 0) {
Arrays.fill(ids, 0, 256, (byte) 7);
for (int y = 1; y < yMax; y++) {
int y8 = y << 8;
Arrays.fill(ids, y8, y8 + 256, (byte) 3);
}
} else {
for (int y = 0; y < yMax; y++) {
int y8 = y << 8;
Arrays.fill(ids, y8, y8 + 256, (byte) 3);
}
}
int yMax15 = yMax & 15;
int yMax158 = yMax15 << 8;
Arrays.fill(ids, yMax158, yMax158 + 256, (byte) 2);
if (yMax != 15) {
Arrays.fill(ids, yMax158 + 256, 4096, (byte) 0);
}
} else if (layer == 0){
Arrays.fill(ids, 256, 4096, (byte) 3);
Arrays.fill(ids, 0, 256, (byte) 7);
} else {
Arrays.fill(ids, (byte) 3);
}
}
return chunk;
}
private MCAChunk emptyRoad(MCAChunk chunk, HybridPlotWorld hpw) {
int maxLayer = (hpw.ROAD_HEIGHT) >> 4;
for (int i = maxLayer + 1; i < chunk.ids.length; i++) {
chunk.ids[i] = null;
chunk.data[i] = null;
}
for (int layer = 0; layer <= maxLayer; layer++) {
byte[] ids = chunk.ids[layer];
if (ids == null) {
ids = chunk.ids[layer] = new byte[4096];
chunk.data[layer] = new byte[2048];
chunk.skyLight[layer] = new byte[2048];
chunk.blockLight[layer] = new byte[2048];
} else {
Arrays.fill(ids, (byte) 0);
Arrays.fill(chunk.data[layer], (byte) 0);
Arrays.fill(chunk.skyLight[layer], (byte) 0);
Arrays.fill(chunk.blockLight[layer], (byte) 0);
}
if (layer == maxLayer) {
int yMax = hpw.ROAD_HEIGHT & 15;
for (int y = yMax + 1; y < 15; y++) {
Arrays.fill(chunk.skyLight[layer], y << 7, (y << 7) + 128, (byte) 255);
}
if (layer == 0) {
Arrays.fill(ids, 0, 256, (byte) 7);
for (int y = 1; y <= yMax; y++) {
int y8 = y << 8;
Arrays.fill(ids, y8, y8 + 256, (byte) hpw.ROAD_BLOCK.id);
}
} else {
for (int y = 0; y <= yMax; y++) {
int y8 = y << 8;
Arrays.fill(ids, y8, y8 + 256, (byte) hpw.ROAD_BLOCK.id);
}
}
if (yMax != 15) {
int yMax15 = yMax & 15;
int yMax158 = yMax15 << 8;
Arrays.fill(ids, yMax158 + 256, 4096, (byte) 0);
}
} else if (layer == 0){
Arrays.fill(ids, 256, 4096, (byte) hpw.ROAD_BLOCK.id);
Arrays.fill(ids, 0, 256, (byte) 7);
} else {
Arrays.fill(ids, (byte) hpw.ROAD_BLOCK.id);
}
}
return chunk;
}
@Override
@ -52,46 +159,92 @@ public class MoveTo512 extends Command {
check(area, C.COMMAND_SYNTAX, getUsage());
checkTrue(area instanceof HybridPlotWorld, C.NOT_VALID_HYBRID_PLOT_WORLD);
for (World world : Bukkit.getWorlds()) {
world.save();
}
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(area.worldname, true, false);
MCAQueue queueFrom = new MCAQueue(area.worldname, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
String world = args[0];
File folder = new File(PS.imp().getWorldContainer(), world);
File folder = new File(PS.imp().getWorldContainer(), world + File.separator + "region");
checkTrue(!folder.exists(), C.SETUP_WORLD_TAKEN, world);
HybridPlotWorld hpw = (HybridPlotWorld) area;
int minRoad = 5;
int pLen = Math.max(hpw.PLOT_WIDTH, 512 - minRoad);
int roadWidth = pLen - 512;
int minRoad = 7;
int pLen = Math.min(hpw.PLOT_WIDTH, 512 - minRoad);
int roadWidth = 512 - pLen;
int roadPosLower;
if ((roadWidth & 1) == 0) {
roadPosLower = (short) (Math.floor(roadWidth / 2) - 1);
} else {
roadPosLower = (short) Math.floor(roadWidth / 2);
}
int roadPosUpper = 512 - roadWidth + roadPosLower;
int roadPosUpper = 512 - roadWidth + roadPosLower + 1;
final ThreadLocal<boolean[]> roadCache = new ThreadLocal<boolean[]>() {
@Override
protected boolean[] initialValue() {
return new boolean[64];
}
};
MCAChunk reference = new MCAChunk(null, 0, 0);
{
reference.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0);
reference.fillCuboid(0, 15, 1, hpw.PLOT_HEIGHT - 1, 0, 15, 3, (byte) 0);
reference.fillCuboid(0, 15, hpw.PLOT_HEIGHT, hpw.PLOT_HEIGHT, 0, 15, 2, (byte) 0);
}
Map<PlotId, Plot> rawPlots = area.getPlotsRaw();
ArrayList<Plot> plots = new ArrayList(rawPlots.values());
int size = plots.size();
PlotId nextId = new PlotId(0, 0);
for (Plot plot : area.getPlots()) {
long start = System.currentTimeMillis();
int percent = 0;
for (Plot plot : plots) {
Fawe.debug(((percent += 100) / size) + "% complete!");
Location bot = plot.getBottomAbs();
Location top = plot.getTopAbs();
int oX = roadPosLower - bot.getX();
int oZ = roadPosLower - bot.getZ();
int oX = roadPosLower - bot.getX() + 1;
int oZ = roadPosLower - bot.getZ() + 1;
{ // Move
PlotId id = plot.getId();
Fawe.debug("Moving " + plot.getId() + " to " + nextId);
id.x = nextId.x;
id.y = nextId.y;
id.recalculateHash();
}
MCAWriter writer = new MCAWriter(512, 512, folder) {
@Override
public boolean shouldWrite(int chunkX, int chunkZ) {
return true;
int bx = chunkX << 4;
int bz = chunkZ << 4;
int tx = bx + 15;
int tz = bz + 15;
return !(tx < roadPosLower || tz < roadPosLower || bx > roadPosUpper || bz > roadPosUpper);
}
@Override
public MCAChunk write(MCAChunk newChunk, int bx, int tx, int bz, int tz) {
Arrays.fill(newChunk.biomes, (byte) 4);
if (!newChunk.tiles.isEmpty()) newChunk.tiles.clear();
if (tx < roadPosLower || tz < roadPosLower || bx > roadPosUpper || bz > roadPosUpper) {
newChunk.fillCuboid(0, 15, 0, hpw.ROAD_HEIGHT, 0, 15, hpw.ROAD_BLOCK.id, hpw.ROAD_BLOCK.data);
newChunk.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0);
return emptyRoad(newChunk, hpw);
} else {
boolean partRoad = (bx <= roadPosLower || bz <= roadPosLower || tx >= roadPosUpper || tz >= roadPosUpper);
boolean changed = false;
emptyPlot(newChunk, hpw);
int obx = bx - oX;
int obz = bz - oZ;
int otx = tx - oX;
@ -102,13 +255,17 @@ public class MoveTo512 extends Command {
int otherTCZ = (otz) >> 4;
int cx = newChunk.getX();
int cz = newChunk.getZ();
int cbx = (cx << 4) - oX;
int cbz = (cz << 4) - oZ;
for (int otherCZ = otherBCZ; otherCZ <= otherTCZ; otherCZ++) {
for (int otherCX = otherBCX; otherCX <= otherTCX; otherCX++) {
FaweChunk chunk = queueFrom.getFaweChunk(otherCX, otherCZ);
FaweChunk chunk;
synchronized (queueFrom) {
chunk = queueFrom.getFaweChunk(otherCX, otherCZ);
}
if (!(chunk instanceof NullFaweChunk)) {
changed = true;
MCAChunk other = (MCAChunk) chunk;
int ocbx = otherCX << 4;
int ocbz = otherCZ << 4;
@ -125,43 +282,50 @@ public class MoveTo512 extends Command {
}
}
}
if (bx < roadPosLower || bz < roadPosLower || tx > roadPosUpper || tz > roadPosUpper) {
boolean[] gx = new boolean[16];
boolean[] wx = new boolean[16];
boolean[] gz = new boolean[16];
boolean[] wz = new boolean[16];
if (!changed || reference.idsEqual(newChunk, false)) {
return null;
}
if (partRoad) {
boolean[] rwp = roadCache.get();
for (short i = 0; i < 16; i++) {
int vx = bx + i;
int vz = bz + i;
gz[i] = vz < roadPosLower || vz > roadPosUpper;
wz[i] = vz == roadPosLower || vz == roadPosUpper;
gx[i] = vx < roadPosLower || vx > roadPosUpper;
wx[i] = vx == roadPosLower || vx == roadPosUpper;
rwp[i] = vx < roadPosLower || vx > roadPosUpper;
rwp[i + 32] = vx == roadPosLower || vx == roadPosUpper;
rwp[i + 16] = vz < roadPosLower || vz > roadPosUpper;
rwp[i + 48] = vz == roadPosLower || vz == roadPosUpper;
}
for (int z = 0; z < 16; z++) {
final boolean rwpz16 = rwp[z + 16];
final boolean rwpz48 = rwp[z + 48];
for (int x = 0; x < 16; x++) {
if (gx[x] || gz[z]) {
for (int y = 1; y < hpw.ROAD_HEIGHT; y++) {
if (rwpz16 || rwp[x]) {
for (int y = 1; y <= hpw.ROAD_HEIGHT; y++) {
newChunk.setBlock(x, y, z, hpw.ROAD_BLOCK.id, hpw.ROAD_BLOCK.data);
}
} else if (wx[x] || wz[z]) {
for (int y = 1; y < hpw.WALL_HEIGHT; y++) {
for (int y = hpw.ROAD_HEIGHT + 1; y < 256; y++) {
newChunk.setBlock(x, y, z, 0, 0);
}
} else if (rwpz48 || rwp[x + 32]) {
for (int y = 1; y <= hpw.WALL_HEIGHT; y++) {
newChunk.setBlock(x, y, z, hpw.WALL_FILLING.id, hpw.WALL_FILLING.data);
}
newChunk.setBlock(x, hpw.WALL_HEIGHT, z, hpw.CLAIMED_WALL_BLOCK.id, hpw.CLAIMED_WALL_BLOCK.data);
for (int y = hpw.WALL_HEIGHT + 2; y < 256; y++) {
newChunk.setBlock(x, y, z, 0, 0);
}
newChunk.setBlock(x, hpw.WALL_HEIGHT + 1, z, hpw.CLAIMED_WALL_BLOCK.id, hpw.CLAIMED_WALL_BLOCK.data);
}
}
}
newChunk.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0);
}
}
return newChunk;
}
};
writer.setMCAOffset(nextId.x, nextId.y);
writer.setMCAOffset(nextId.x - 1, nextId.y - 1);
try {
writer.generate();
System.gc();
} catch (IOException e) {
e.printStackTrace();
return;
@ -169,7 +333,28 @@ public class MoveTo512 extends Command {
queueFrom.clear();
nextId = nextId.getNextId(1);
}
Fawe.debug("Anvil copy completed in " + ((System.currentTimeMillis() - start) / 1000d) + "s");
Fawe.debug("Updating database, please wait...");
rawPlots.clear();
for (Plot plot : plots) {
rawPlots.put(plot.getId(), plot);
DBFunc.movePlot(plot, plot);
}
SQLManager db = (SQLManager) DBFunc.dbManager;
db.addNotifyTask(new Runnable() {
@Override
public void run() {
Fawe.debug("Instructions");
Fawe.debug(" - Stop the server");
Fawe.debug(" - Rename the folder for the new world to the current world");
Fawe.debug(" - Change the plot size to " + pLen);
Fawe.debug(" - Change the road size to " + roadWidth);
Fawe.debug(" - Start the server");
}
});
ConfigurationSection section = PS.get().worlds.getConfigurationSection("worlds." + world);
if (section == null) section = PS.get().worlds.createSection("worlds." + world);
area.saveConfiguration(section);
section.set("plot.size", pLen);
section.set("road.width", roadWidth);

View File

@ -36,10 +36,10 @@ public class PlotSquaredFeature extends FaweMaskManager {
new PlotSetBiome();
}
try {
new MoveTo512();
if (Settings.Enabled_Components.WORLDS) {
new CreateFromImage();
new ReplaceAll();
new MoveTo512();
}
} catch (Throwable e) {
Fawe.debug("You need to update PlotSquared to access the CFI and REPLACEALL commands");

View File

@ -34,7 +34,7 @@ public class SetQueue {
* Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the server
*/
private long last;
private long secondLast;
private long allocate = 50;
private long lastSuccess;
/**
@ -78,6 +78,7 @@ public class SetQueue {
@Override
public void run() {
try {
long now = System.currentTimeMillis();
targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0);
do {
Runnable task = tasks.poll();
@ -88,13 +89,15 @@ public class SetQueue {
}
} while (Fawe.get().getTimer().isAbove(targetTPS));
if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) {
lastSuccess = System.currentTimeMillis();
last = lastSuccess = now;
runEmptyTasks();
return;
}
if (!MemUtil.isMemoryFree()) {
final int mem = MemUtil.calculateMemory();
if (mem != Integer.MAX_VALUE) {
last = now;
allocate = Math.max(5, allocate - 1);
if ((mem <= 1) && Settings.IMP.PREVENT_CRASHES) {
for (FaweQueue queue : getAllQueues()) {
queue.saveMemory();
@ -110,13 +113,26 @@ public class SetQueue {
}
}
FaweQueue queue = getNextQueue();
if (queue == null || !Fawe.get().getTimer().isAbove(targetTPS)) {
if (queue == null) {
last = now;
return;
}
if (!Fawe.get().getTimer().isAbove(targetTPS)) {
allocate = Math.max(5, allocate - 1);
last = now;
return;
}
if (Thread.currentThread() != Fawe.get().getMainThread()) {
throw new IllegalStateException("This shouldn't be possible for placement to occur off the main thread");
}
long time = Settings.IMP.QUEUE.EXTRA_TIME_MS + 50 + Math.min((50 + SetQueue.this.last) - (SetQueue.this.last = System.currentTimeMillis()), SetQueue.this.secondLast - System.currentTimeMillis());
long diff = (50 + SetQueue.this.last) - (SetQueue.this.last = now);
long absDiff = Math.abs(diff);
if (diff == 0) {
allocate = Math.min(50, allocate + 1);
} else if (diff < 0) {
allocate = Math.max(5, allocate + diff);
}
long time = Settings.IMP.QUEUE.EXTRA_TIME_MS + allocate - absDiff - System.currentTimeMillis() + now;
// Disable the async catcher as it can't discern async vs parallel
boolean parallel = Settings.IMP.QUEUE.PARALLEL_THREADS > 1;
queue.startSet(parallel);
@ -142,7 +158,6 @@ public class SetQueue {
// completer = new ExecutorCompletionService(pool);
// }
}
secondLast = System.currentTimeMillis();
queue.endSet(parallel);
} catch (Throwable e) {
e.printStackTrace();

View File

@ -1444,7 +1444,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
*/
@SuppressWarnings("deprecation")
public int fillXZ(final Vector origin, final BaseBlock block, final double radius, final int depth, final boolean recursive) throws MaxChangedBlocksException {
return this.fillXZ(origin, new BlockPattern(block), radius, depth, recursive);
return this.fillXZ(origin, (Pattern) block, radius, depth, recursive);
}
/**
@ -1562,7 +1562,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final Region region = new CuboidRegion(this.getWorld(), // Causes clamping of Y range
position.add(-apothem + 1, 0, -apothem + 1), position.add(apothem - 1, height - 1, apothem - 1));
final Pattern pattern = new BlockPattern(new BaseBlock(BlockID.AIR));
final Pattern pattern = (new BaseBlock(BlockID.AIR));
return this.setBlocks(region, pattern);
}
@ -1583,7 +1583,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final Region region = new CuboidRegion(this.getWorld(), // Causes clamping of Y range
position.add(-apothem + 1, 0, -apothem + 1), position.add(apothem - 1, -height + 1, apothem - 1));
final Pattern pattern = new BlockPattern(new BaseBlock(BlockID.AIR));
final Pattern pattern = (new BaseBlock(BlockID.AIR));
return this.setBlocks(region, pattern);
}
@ -1605,7 +1605,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final Vector adjustment = new Vector(1, 1, 1).multiply(apothem - 1);
final Region region = new CuboidRegion(this.getWorld(), // Causes clamping of Y range
position.add(adjustment.multiply(-1)), position.add(adjustment));
final Pattern pattern = new BlockPattern(new BaseBlock(BlockID.AIR));
final Pattern pattern = (new BaseBlock(BlockID.AIR));
return this.replaceBlocks(region, mask, pattern);
}
@ -1657,7 +1657,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
}
try {
if (hasExtraExtents()) {
RegionVisitor visitor = new RegionVisitor(region, new BlockReplace(extent, new BlockPattern(block)), this);
RegionVisitor visitor = new RegionVisitor(region, new BlockReplace(extent, (block)), this);
Operations.completeBlindly(visitor);
this.changes += visitor.getAffected();
} else {
@ -1689,7 +1689,10 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
checkNotNull(region);
checkNotNull(pattern);
if (pattern instanceof BlockPattern) {
return setBlocks(region, ((BlockPattern) pattern).getBlock());
return setBlocks(region, ((BaseBlock) pattern));
}
if (pattern instanceof BaseBlock) {
return setBlocks(region, (BaseBlock) pattern);
}
final BlockReplace replace = new BlockReplace(EditSession.this, pattern);
final RegionVisitor visitor = new RegionVisitor(region, replace, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null);
@ -1714,7 +1717,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
// return changes = region.getArea();
// }
// TODO fast replace
return this.replaceBlocks(region, filter, new BlockPattern(replacement));
return this.replaceBlocks(region, filter, (replacement));
}
@ -1730,8 +1733,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
*/
@SuppressWarnings("deprecation")
public int replaceBlocks(final Region region, final Set<BaseBlock> filter, final Pattern pattern) throws MaxChangedBlocksException {
// if (pattern instanceof BlockPattern) {
// return replaceBlocks(region, filter, ((BlockPattern) pattern).getBlock());
// if (pattern instanceof BaseBlock) {
// return replaceBlocks(region, filter, ((BaseBlock) pattern));
// }
final Mask mask = filter == null ? new ExistingBlockMask(this) : new FuzzyBlockMask(this, filter);
return this.replaceBlocks(region, mask, pattern);
@ -1794,7 +1797,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
*/
@SuppressWarnings("deprecation")
public int makeCuboidFaces(final Region region, final BaseBlock block) throws MaxChangedBlocksException {
return this.makeCuboidFaces(region, new BlockPattern(block));
return this.makeCuboidFaces(region, (Pattern) (block));
}
/**
@ -1848,7 +1851,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
*/
@SuppressWarnings("deprecation")
public int makeCuboidWalls(final Region region, final BaseBlock block) throws MaxChangedBlocksException {
return this.makeCuboidWalls(region, new BlockPattern(block));
return this.makeCuboidWalls(region, (Pattern) (block));
}
/**
@ -1917,7 +1920,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
@SuppressWarnings("deprecation")
public int overlayCuboidBlocks(final Region region, final BaseBlock block) throws MaxChangedBlocksException {
checkNotNull(block);
return this.overlayCuboidBlocks(region, new BlockPattern(block));
return this.overlayCuboidBlocks(region, (Pattern) (block));
}
/**
@ -2013,7 +2016,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
final Vector to = region.getMinimumPoint();
final ForwardExtentCopy copy = new ForwardExtentCopy(EditSession.this, region, EditSession.this, to);
final com.sk89q.worldedit.function.pattern.Pattern pattern = replacement != null ? new BlockPattern(replacement) : new BlockPattern(new BaseBlock(BlockID.AIR));
final com.sk89q.worldedit.function.pattern.Pattern pattern = replacement != null ? replacement : (new BaseBlock(BlockID.AIR));
final BlockReplace remove = new BlockReplace(EditSession.this, pattern) {
private MutableBlockVector mutable = new MutableBlockVector();
@ -2089,7 +2092,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
new EllipsoidRegion(null, origin,
new Vector(radius, radius, radius))), liquidMask);
final BlockReplace replace = new BlockReplace(EditSession.this, new BlockPattern(new BaseBlock(BlockID.AIR)));
final BlockReplace replace = new BlockReplace(EditSession.this, new BaseBlock(BlockID.AIR));
final RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this);
// Around the origin in a 3x3 block
@ -2148,7 +2151,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))),
blockMask);
BlockReplace replace = new BlockReplace(this, new BlockPattern(FaweCache.getBlock(stationary, 0)));
BlockReplace replace = new BlockReplace(this, (FaweCache.getBlock(stationary, 0)));
NonRisingVisitor visitor = new NonRisingVisitor(mask, replace, (int) (radius * 2 + 1), this);
// Around the origin in a 3x3 block

View File

@ -80,7 +80,6 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.InvalidUsageException;
@ -102,7 +101,7 @@ import javafx.scene.paint.Color;
* Commands to set brush shape.
*/
@Command(aliases = {"brush", "br", "/b"},
desc = "Commands to build and draw from far away. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Brushes)"
desc = "Commands to build and draw from far away. [More Info](https://git.io/vSPYf)"
)
public class BrushCommands extends MethodCommands {
@ -287,8 +286,8 @@ public class BrushCommands extends MethodCommands {
} else {
brush = new SphereBrush();
}
if (fill instanceof BlockPattern) {
BaseBlock block = ((BlockPattern) fill).getBlock();
if (fill instanceof BaseBlock) {
BaseBlock block = (BaseBlock) fill;
switch (block.getId()) {
case BlockID.SAND:
case BlockID.GRAVEL:
@ -595,7 +594,7 @@ public class BrushCommands extends MethodCommands {
public BrushSettings extinguishBrush(Player player, LocalSession session, EditSession editSession, @Optional("5") double radius, CommandContext context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
Pattern fill = new BlockPattern(new BaseBlock(0));
Pattern fill = (new BaseBlock(0));
return get(context)
.setBrush(new SphereBrush())
.setSize(radius)

View File

@ -45,7 +45,8 @@ import java.util.zip.GZIPInputStream;
/**
* Tool commands.
*/
@Command(aliases = {}, desc = "Tool commands")
@Command(aliases = {"brush", "br", "/b"}, desc = "Tool commands")
public class BrushOptionsCommands extends MethodCommands {
public BrushOptionsCommands(WorldEdit we) {

View File

@ -73,7 +73,7 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
/**
* Clipboard commands.
*/
@Command(aliases = {}, desc = "Related commands to copy and pasting blocks: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Clipboard)")
@Command(aliases = {}, desc = "Related commands to copy and pasting blocks: [More Info](https://goo.gl/z2ScQR)")
public class ClipboardCommands {
private final WorldEdit worldEdit;

View File

@ -68,7 +68,7 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
/**
* Commands for the generation of shapes and other objects.
*/
@Command(aliases = {}, desc = "Create structures and features: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Generation)")
@Command(aliases = {}, desc = "Create structures and features: [More Info](https://goo.gl/KuLFRW)")
public class GenerationCommands {
private final WorldEdit worldEdit;
@ -125,8 +125,8 @@ public class GenerationCommands {
public void image(Player player, LocalSession session, EditSession editSession, String arg, @Optional("true") boolean randomize, @Optional("100") int threshold) throws WorldEditException, ParameterException, IOException {
TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold);
URL url = new URL(arg);
if (!url.getHost().equalsIgnoreCase("i.imgur.com")) {
throw new IOException("Only i.imgur.com links are allowed!");
if (!url.getHost().equalsIgnoreCase("i.imgur.com") && !url.getHost().equalsIgnoreCase("empcraft.com")) {
throw new IOException("Only i.imgur.com or empcraft.com/ui links are allowed!");
}
FawePlayer<Object> fp = FawePlayer.wrap(player);
BufferedImage image = MainUtil.toRGB(ImageIO.read(url));

View File

@ -46,7 +46,7 @@ import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.biome.BaseBiome;
@Command(aliases = {"masks"},
desc = "Help for the various masks. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit---FAWE-mask-list)"
desc = "Help for the various masks. [More Info](https://git.io/v9r4K)"
)
public class MaskCommands extends MethodCommands {
public MaskCommands(WorldEdit worldEdit) {

View File

@ -43,7 +43,7 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
/**
* Commands for moving the player around.
*/
@Command(aliases = {}, desc = "Commands for moving the player around: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Getting_around)")
@Command(aliases = {}, desc = "Commands for moving the player around: [More Info](https://goo.gl/uQTUiT)")
public class NavigationCommands {
@SuppressWarnings("unused")

View File

@ -58,7 +58,7 @@ import java.util.Set;
import javafx.scene.paint.Color;
@Command(aliases = {"patterns"},
desc = "Help for the various patterns. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit-and-FAWE-patterns)"
desc = "Help for the various patterns. [More Info](https://git.io/vSPmA)"
)
public class PatternCommands extends MethodCommands {
public PatternCommands(WorldEdit worldEdit) {

View File

@ -53,7 +53,6 @@ import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.NoiseFilter2D;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.LayerVisitor;
import com.sk89q.worldedit.internal.annotation.Direction;
@ -330,11 +329,7 @@ public class RegionCommands extends MethodCommands {
public void set(FawePlayer player, LocalSession session, EditSession editSession, @Selection Region selection, Pattern to, CommandContext context) throws WorldEditException {
player.checkConfirmation(getArguments(context));
int affected;
if (to instanceof BlockPattern) {
affected = editSession.setBlocks(selection, ((BlockPattern) to).getBlock());
} else {
affected = editSession.setBlocks(selection, to);
}
affected = editSession.setBlocks(selection, to);
if (affected != 0) {
BBC.OPERATION.send(player, affected);
if (!player.hasPermission("fawe.tips"))

View File

@ -37,7 +37,7 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
/**
* Commands related to scripting.
*/
@Command(aliases = {}, desc = "Run craftscripts: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Scripting)")
@Command(aliases = {}, desc = "Run craftscripts: [More Info](https://goo.gl/dHDxLG)")
public class ScriptingCommands {
private final WorldEdit worldEdit;

View File

@ -32,7 +32,7 @@ import com.sk89q.worldedit.command.tool.RecursivePickaxe;
import com.sk89q.worldedit.command.tool.SinglePickaxe;
import com.sk89q.worldedit.entity.Player;
@Command(aliases = {"superpickaxe", "pickaxe", "sp"}, desc = "Super-pickaxe commands: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Super_pickaxe)")
@Command(aliases = {"superpickaxe", "pickaxe", "sp"}, desc = "Super-pickaxe commands: [More Info](https://goo.gl/aBtGHo)")
public class SuperPickaxeCommands {
private final WorldEdit we;

View File

@ -44,7 +44,7 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.command.parametric.Optional;
@Command(aliases = {"brush", "br", "/b", "tool"}, desc = "Bind functions to held items: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Tools)")
@Command(aliases = {"brush", "br", "/b", "tool"}, desc = "Bind functions to held items: [More Info](https://goo.gl/xPnPxj)")
public class ToolCommands {
private final WorldEdit we;

View File

@ -22,7 +22,7 @@ import com.sk89q.worldedit.util.command.parametric.Optional;
import java.util.Set;
@Command(aliases = {"transforms"},
desc = "Help for the various transforms. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Transforms)"
desc = "Help for the various transforms. [More Info](https://git.io/v9KHO)"
)
public class TransformCommands extends MethodCommands {
public TransformCommands(WorldEdit worldEdit) {

View File

@ -51,7 +51,6 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.internal.expression.Expression;
@ -116,8 +115,8 @@ public class UtilityCommands extends MethodCommands {
worldEdit.checkMaxRadius(radius);
Vector pos = session.getPlacementPosition(player);
int affected = 0;
if (pattern instanceof BlockPattern) {
affected = editSession.fillXZ(pos, ((BlockPattern) pattern).getBlock(), radius, (int) depth, false);
if (pattern instanceof BaseBlock) {
affected = editSession.fillXZ(pos, ((BaseBlock) pattern), radius, (int) depth, false);
} else {
affected = editSession.fillXZ(pos, pattern, radius, (int) depth, false);
}
@ -137,8 +136,8 @@ public class UtilityCommands extends MethodCommands {
worldEdit.checkMaxRadius(radius);
Vector pos = session.getPlacementPosition(player);
int affected = 0;
if (pattern instanceof BlockPattern) {
affected = editSession.fillXZ(pos, ((BlockPattern) pattern).getBlock(), radius, (int) depth, true);
if (pattern instanceof BaseBlock) {
affected = editSession.fillXZ(pos, ((BaseBlock) pattern), radius, (int) depth, true);
} else {
affected = editSession.fillXZ(pos, pattern, radius, (int) depth, true);
}

View File

@ -45,7 +45,6 @@ import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.regions.CuboidRegion;
@ -106,8 +105,8 @@ public class SelectionCommand extends SimpleCommand<Operation> {
Field field = replace.getClass().getDeclaredField("pattern");
field.setAccessible(true);
Pattern pattern = (Pattern) field.get(replace);
if (pattern instanceof BlockPattern) {
BaseBlock block = ((BlockPattern) pattern).getBlock();
if (pattern instanceof BaseBlock) {
BaseBlock block = ((BaseBlock) pattern);
final FaweQueue queue = editSession.getQueue();
final int minY = cuboid.getMinimumY();
final int maxY = cuboid.getMaximumY();

View File

@ -13,7 +13,6 @@ import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
import com.sk89q.worldedit.world.World;
@ -53,7 +52,7 @@ public class RecursivePickaxe implements BlockTool {
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
final int radius = (int) range;
final BlockReplace replace = new BlockReplace(editSession, new BlockPattern(editSession.nullBlock));
final BlockReplace replace = new BlockReplace(editSession, (editSession.nullBlock));
editSession.setMask((Mask) null);
RecursiveVisitor visitor = new RecursiveVisitor(new IdMask(editSession), replace, radius, editSession);
visitor.visit(pos);

View File

@ -238,13 +238,10 @@ public final class CommandManager {
.registerMethods(new BrushOptionsCommands(worldEdit))
.registerMethods(new ToolCommands(worldEdit))
.registerMethods(new UtilityCommands(worldEdit))
.group("worldedit", "we", "fawe")
.describeAs("FAWE commands")
.registerMethods(new WorldEditCommands(worldEdit)).parent().group("schematic", "schem", "/schematic", "/schem")
.describeAs("Schematic commands for saving/loading areas")
.registerMethods(new SchematicCommands(worldEdit)).parent().group("snapshot", "snap")
.describeAs("Schematic commands for saving/loading areas")
.registerMethods(new SnapshotCommands(worldEdit)).parent().group("brush", "br", "/b", "tool").describeAs("Bind brushes and tools to items")
.registerSubMethods(new WorldEditCommands(worldEdit))
.registerSubMethods(new SchematicCommands(worldEdit))
.registerSubMethods(new SnapshotCommands(worldEdit))
.groupAndDescribe(BrushCommands.class)
.registerMethods(new ToolCommands(worldEdit))
.registerMethods(new BrushOptionsCommands(worldEdit))
.registerMethods(new BrushCommands(worldEdit), new BrushProcessor(worldEdit))
@ -254,7 +251,8 @@ public final class CommandManager {
.register(adapt(new ShapedBrushCommand(new ApplyCommand(), "worldedit.brush.apply")), "apply")
.register(adapt(new ShapedBrushCommand(new PaintCommand(new TreeGeneratorParser("treeType")), "worldedit.brush.forest")), "forest")
.register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y-=1", Mode.RAW_COORD), "Raise one block"), "worldedit.brush.raise")), "raise")
.register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower").parent()
.register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower")
.parent()
.group("superpickaxe", "pickaxe", "sp").describeAs("Super-pickaxe commands")
.registerMethods(new SuperPickaxeCommands(worldEdit))
.parent().graph().getDispatcher();
@ -374,7 +372,7 @@ public final class CommandManager {
final Actor finalActor = actor;
locals.put("arguments", args);
final long start = System.currentTimeMillis();
long start = System.currentTimeMillis();
try {
// This is a bit of a hack, since the call method can only throw CommandExceptions
// everything needs to be wrapped at least once. Which means to handle all WorldEdit

View File

@ -17,7 +17,6 @@ import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
@ -176,17 +175,17 @@ public interface Extent extends InputExtent, OutputExtent {
}
default public void addOres(Region region, Mask mask) throws WorldEditException {
addOre(region, mask, new BlockPattern(BlockID.DIRT), 33, 10, 100, 0, 255);
addOre(region, mask, new BlockPattern(BlockID.GRAVEL), 33, 8, 100, 0, 255);
addOre(region, mask, new BlockPattern(BlockID.STONE, 1), 33, 10, 100, 0, 79);
addOre(region, mask, new BlockPattern(BlockID.STONE, 3), 33, 10, 100, 0, 79);
addOre(region, mask, new BlockPattern(BlockID.STONE, 5), 33, 10, 100, 0, 79);
addOre(region, mask, new BlockPattern(BlockID.COAL_ORE), 17, 20, 100, 0, 127);
addOre(region, mask, new BlockPattern(BlockID.IRON_ORE), 9, 20, 100, 0, 63);
addOre(region, mask, new BlockPattern(BlockID.GOLD_ORE), 9, 2, 100, 0, 31);
addOre(region, mask, new BlockPattern(BlockID.REDSTONE_ORE), 8, 8, 100, 0, 15);
addOre(region, mask, new BlockPattern(BlockID.DIAMOND_ORE), 8, 1, 100, 0, 15);
addOre(region, mask, new BlockPattern(BlockID.LAPIS_LAZULI_ORE), 7, 1, 100, 0, 15);
addOre(region, mask, new BlockPattern(BlockID.EMERALD_ORE), 5, 1, 100, 4, 31);
addOre(region, mask, FaweCache.getBlock(BlockID.DIRT, 0), 33, 10, 100, 0, 255);
addOre(region, mask, FaweCache.getBlock(BlockID.GRAVEL, 0), 33, 8, 100, 0, 255);
addOre(region, mask, FaweCache.getBlock(BlockID.STONE, 1), 33, 10, 100, 0, 79);
addOre(region, mask, FaweCache.getBlock(BlockID.STONE, 3), 33, 10, 100, 0, 79);
addOre(region, mask, FaweCache.getBlock(BlockID.STONE, 5), 33, 10, 100, 0, 79);
addOre(region, mask, FaweCache.getBlock(BlockID.COAL_ORE, 0), 17, 20, 100, 0, 127);
addOre(region, mask, FaweCache.getBlock(BlockID.IRON_ORE, 0), 9, 20, 100, 0, 63);
addOre(region, mask, FaweCache.getBlock(BlockID.GOLD_ORE, 0), 9, 2, 100, 0, 31);
addOre(region, mask, FaweCache.getBlock(BlockID.REDSTONE_ORE, 0), 8, 8, 100, 0, 15);
addOre(region, mask, FaweCache.getBlock(BlockID.DIAMOND_ORE, 0), 8, 1, 100, 0, 15);
addOre(region, mask, FaweCache.getBlock(BlockID.LAPIS_LAZULI_ORE, 0), 7, 1, 100, 0, 15);
addOre(region, mask, FaweCache.getBlock(BlockID.EMERALD_ORE, 0), 5, 1, 100, 4, 31);
}
}

View File

@ -7,6 +7,10 @@ import com.sk89q.worldedit.blocks.BaseBlock;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* @deprecated Just use BaseBlock directly
*/
@Deprecated
public class BlockPattern implements Pattern {
private BaseBlock block;

View File

@ -19,11 +19,14 @@
package com.sk89q.worldedit.util.command.fluent;
import com.boydti.fawe.config.Commands;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.worldedit.util.command.CallableProcessor;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.SimpleDispatcher;
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
import javax.annotation.Nullable;
/**
* A collection of commands.
@ -93,7 +96,7 @@ public class DispatcherNode {
* @return this object
* @see ParametricBuilder#registerMethodsAsCommands(com.sk89q.worldedit.util.command.Dispatcher, Object)
*/
public DispatcherNode registerMethods(Object object, CallableProcessor processor) {
public DispatcherNode registerMethods(Object object, @Nullable CallableProcessor processor) {
ParametricBuilder builder = graph.getBuilder();
if (builder == null) {
throw new RuntimeException("No ParametricBuilder set");
@ -102,6 +105,43 @@ public class DispatcherNode {
return this;
}
/**
* Build and register sub commands with this dispatcher using the
* {@link ParametricBuilder} assigned on the objects registered command aliases {@link com.sk89q.minecraft.util.commands.Command}.
*
* @param object the object provided to the {@link ParametricBuilder}
* @return this object
*/
public DispatcherNode registerSubMethods(Object object) {
return registerSubMethods(object, null);
}
/**
* Build and register sub commands with this dispatcher using the
* {@link ParametricBuilder} assigned on the objects registered command aliases {@link com.sk89q.minecraft.util.commands.Command}.
*
* @param object the object provided to the {@link ParametricBuilder}
* @param processor the command processor
* @return this object
*/
public DispatcherNode registerSubMethods(Object object, @Nullable CallableProcessor processor) {
Class<? extends Object> clazz = object.getClass();
return groupAndDescribe(clazz).registerMethods(object, processor).parent();
}
public DispatcherNode groupAndDescribe(Class clazz) {
Command cmd = (Command) clazz.getAnnotation(Command.class);
if (cmd == null) {
throw new RuntimeException("This class does not have any command annotations");
}
cmd = Commands.translate(clazz, cmd);
DispatcherNode res = group(cmd.aliases());
if (cmd.desc() != null && !cmd.desc().isEmpty()) {
res = res.describeAs(cmd.desc());
}
return res;
}
/**
* Create a new command that will contain sub-commands.
* <p>
@ -114,7 +154,8 @@ public class DispatcherNode {
public DispatcherNode group(String... alias) {
SimpleDispatcher command = new SimpleDispatcher();
getDispatcher().registerCommand(command, alias);
return new DispatcherNode(graph, this, command);
DispatcherNode res = new DispatcherNode(graph, this, command);
return res;
}
/**