Add new option:

Option : Default

EXPERIMENTAL_UNSTABLE_DO_NOT_ENABLE_ULTRA_SUPER_FAST_WORLD_CORRUPTING_AWESOME_DIRECT_ANVIL_QUEUE_MODE:
false
This commit is contained in:
Jesse Boyd 2016-08-20 22:01:43 +10:00
parent 4ddffb197b
commit 3618007052
12 changed files with 320 additions and 43 deletions

View File

@ -150,6 +150,7 @@ public class FaweBukkit implements IFawe, Listener {
private int[] version;
private boolean hasNMS = true;
private boolean playerChunk = false;
/**
* The FaweQueue is a core part of block placement<br>
@ -160,19 +161,23 @@ public class FaweBukkit implements IFawe, Listener {
*/
@Override
public FaweQueue getNewQueue(String world, boolean dontCareIfFast) {
try {
Field fieldDirtyCount = ReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
fieldDirtyCount.setAccessible(true);
int mod = fieldDirtyCount.getModifiers();
if ((mod & Modifier.VOLATILE) == 0) {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(fieldDirtyCount, mod + Modifier.VOLATILE);
}
} catch (Throwable ignore) {}
if (playerChunk != (playerChunk = true)) {
try {
Field fieldDirtyCount = ReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
fieldDirtyCount.setAccessible(true);
int mod = fieldDirtyCount.getModifiers();
if ((mod & Modifier.VOLATILE) == 0) {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(fieldDirtyCount, mod + Modifier.VOLATILE);
}
} catch (Throwable ignore) {}
}
try {
return plugin.getQueue(world);
} catch (Throwable ignore) {}
} catch (Throwable ignore) {
ignore.printStackTrace();
}
// Disable incompatible settings
Settings.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
Settings.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
@ -184,7 +189,14 @@ public class FaweBukkit implements IFawe, Listener {
debug("Fallback placer: " + BukkitQueue_All.class);
debug("=======================================");
debug("Download the version of FAWE for your platform");
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
debug("=======================================");
TaskManager.IMP.laterAsync(new Runnable() {
@Override
public void run() {
MainUtil.sendAdmin("&cNo NMS placer found, see console!");
}
}, 1);
hasNMS = false;
}
return new BukkitQueue_All(world);

View File

@ -263,7 +263,7 @@ public class Fawe {
String versionString = scanner.next().trim();
scanner.close();
this.version = new FaweVersion(versionString);
Settings.DATE = new Date(version.year, version.month, version.day).toLocaleString();
Settings.DATE = new Date(version.year, version.month, version.day).toGMTString();
Settings.BUILD = "http://ci.athion.net/job/FastAsyncWorldEdit/" + version.build;
Settings.COMMIT = "https://github.com/boy0001/FastAsyncWorldedit/commit/" + Integer.toHexString(version.hash);
} catch (Throwable ignore) {}

View File

@ -185,6 +185,9 @@ public class Settings extends Config {
})
public static int DISCARD_AFTER_MS = 60000;
@Comment("Certain doom!")
public static boolean EXPERIMENTAL_UNSTABLE_DO_NOT_ENABLE_ULTRA_SUPER_FAST_WORLD_CORRUPTING_AWESOME_DIRECT_ANVIL_QUEUE_MODE = false;
public static class PROGRESS {
@Comment("Display constant titles about the progress of a user's edit")
public static boolean DISPLAY = false;

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
@ -48,7 +49,7 @@ public class DefaultFaweQueueMap implements IFaweQueueMap {
if (cx == lastX && cz == lastZ) {
return lastWrappedChunk;
}
long pair = (long) (lastX = cx) << 32 | (lastX = cz) & 0xFFFFFFFFL;
long pair = MathMan.pairInt(cx, cz);
FaweChunk chunk = this.blocks.get(pair);
if (chunk == null) {
chunk = this.getNewFaweChunk(cx, cz);
@ -57,15 +58,15 @@ public class DefaultFaweQueueMap implements IFaweQueueMap {
blocks.put(pair, previous);
return previous;
}
this.blocks.put(pair, previous);
chunks.add(previous);
this.blocks.put(pair, chunk);
chunks.add(chunk);
}
return chunk;
}
@Override
public void add(FaweChunk chunk) {
long pair = (long) (chunk.getX()) << 32 | (chunk.getZ()) & 0xFFFFFFFFL;
long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
FaweChunk previous = this.blocks.put(pair, chunk);
if (previous == null) {
chunks.add(chunk);
@ -99,7 +100,7 @@ public class DefaultFaweQueueMap implements IFaweQueueMap {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
try {
if (this.blocks.size() == 0) {
if (this.blocks.isEmpty()) {
return false;
}
synchronized (blocks) {

View File

@ -0,0 +1,90 @@
package com.boydti.fawe.example;
import com.boydti.fawe.object.BytePair;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class NullFaweChunk extends FaweChunk<Void> {
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
public NullFaweChunk(FaweQueue parent, int x, int z) {
super(parent, x, z);
}
@Override
public char[][] getCombinedIdArrays() {
return new char[16][];
}
@Override
public int getBitMask() {
return 0;
}
@Override
public Void getChunk() {
return null;
}
@Override
public void setTile(int x, int y, int z, CompoundTag tile) {
}
@Override
public void setEntity(CompoundTag entity) {
}
@Override
public void removeEntity(UUID uuid) {
}
@Override
public void setBlock(int x, int y, int z, int id, int data) {
}
@Override
public Set<CompoundTag> getEntities() {
return new HashSet<>();
}
@Override
public Set<UUID> getEntityRemoves() {
return new HashSet<>();
}
@Override
public Map<BytePair, CompoundTag> getTiles() {
return new HashMap<>();
}
@Override
public CompoundTag getTile(int x, int y, int z) {
return null;
}
@Override
public void setBiome(int x, int z, BaseBiome biome) {
}
@Override
public FaweChunk<Void> copy(boolean shallow) {
return this;
}
}

View File

@ -267,11 +267,11 @@ public class MCAChunk extends FaweChunk<Void> {
return 0;
}
int j = FaweCache.CACHE_J[y][z & 15][x & 15];
int id = idLayer[j];
int id = idLayer[j] & 0xFF;
if (FaweCache.hasData(id)) {
byte[] dataLayer = data[layer];
if (dataLayer != null) {
return (id << 4) + dataLayer[j];
return (id << 4) + getNibble(j, dataLayer);
}
}
return id << 4;
@ -376,7 +376,7 @@ public class MCAChunk extends FaweChunk<Void> {
int j = FaweCache.CACHE_J[y][z & 15][x & 15];
idsLayer[j] = (byte) id;
byte[] dataLayer = this.data[layer];
dataLayer[j] = (byte) data;
setNibble(j, dataLayer, data);
}
@Override

View File

@ -92,7 +92,7 @@ public class MCAFile {
}
public MCAChunk readChunk(int cx, int cz) throws IOException {
int i = (cx << 2) + (cz << 7);
int i = ((cx & 31) << 2) + ((cz & 31) << 7);
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))) << 12;
int size = (locations[i + 3] & 0xFF) << 12;
NBTInputStream nis = getChunkIS(offset);
@ -119,13 +119,13 @@ public class MCAFile {
}
public int getOffset(int cx, int cz) {
int i = (cx << 2) + (cz << 7);
int i = ((cx & 31) << 2) + ((cz & 31) << 7);
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF)));
return offset << 12;
}
public int getSize(int cx, int cz) {
int i = (cx << 2) + (cz << 7);
int i = ((cx & 31) << 2) + ((cz & 31) << 7);
return (locations[i + 3] & 0xFF) << 12;
}
@ -239,7 +239,7 @@ public class MCAFile {
}
private void writeHeader(int cx, int cz, int offsetMedium, int sizeByte) throws IOException {
int i = (cx << 2) + (cz << 7);
int i = ((cx & 31) << 2) + ((cz & 31) << 7);
raf.seek(i);
raf.write((offsetMedium >>> 16) & 0xFF);
raf.write((offsetMedium >>> 8) & 0xFF);
@ -247,9 +247,26 @@ public class MCAFile {
raf.write(sizeByte);
}
public void flush() {
final HashMap<Integer, Integer> offsetMap = new HashMap<>(); // Offset -> <byte cx, byte cz, short size>
public void close() {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void flush() {
boolean modified = false;
for (MCAChunk chunk : getCachedChunks()) {
if (chunk.isModified()) {
modified = true;
break;
}
}
if (!modified) {
return;
}
final HashMap<Integer, Integer> offsetMap = new HashMap<>(); // Offset -> <byte cx, byte cz, short size>
forEachChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
@Override
public void run(Integer cx, Integer cz, Integer offset, Integer size) {
@ -265,7 +282,11 @@ public class MCAFile {
int nextOffset = 8192;
try {
for (int count = 0; count < offsetMap.size(); count++) {
int loc = offsetMap.get(nextOffset);
Integer loc = offsetMap.get(nextOffset);
while (loc == null) {
nextOffset += 4096;
loc = offsetMap.get(nextOffset);
}
int offset = nextOffset;
short cxz = MathMan.unpairX(loc);
int cx = MathMan.unpairShortX(cxz);
@ -286,6 +307,9 @@ public class MCAFile {
}
} else {
newBytes = getChunkBytes(cx, cz);
if (newBytes == null) {
System.out.println("This shouldn't be null?");
}
}
}
if (newBytes == null) {
@ -312,7 +336,7 @@ public class MCAFile {
nextOffset2 += nextSize;
}
System.out.println("Writing: " + cx + "," + cz);
writeSafe(start, newBytes);
writeSafe(start, newBytes);
if (offset != start || end != start + size) {
System.out.println("Header: " + cx + "," + cz + " | " + offset + "," + start + " | " + end + "," + (start + size) + " | " + size + " | " + start);
writeHeader(cx, cz, offset >> 12, newSize);

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.example.NullFaweChunk;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal;
@ -14,11 +15,23 @@ import java.util.UUID;
public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, MCAChunk, MCAChunk, MCAChunk> {
private final FaweQueue parent;
private FaweQueue parent;
private final boolean hasSky;
private final File saveFolder;
public MCAQueue(FaweQueue parent) {
super(parent.getWorldName(), new MCAQueueMap());
this.parent = parent;
((MCAQueueMap) getFaweQueueMap()).setParentQueue(parent);
hasSky = parent.hasSky();
saveFolder = parent.getSaveFolder();
}
public MCAQueue(String world, File saveFolder, boolean hasSky) {
super(world, new MCAQueueMap());
((MCAQueueMap) getFaweQueueMap()).setParentQueue(this);
this.saveFolder = saveFolder;
this.hasSky = hasSky;
}
@Override
@ -87,7 +100,9 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, MCAChunk, MCAChunk,
@Override
public void refreshChunk(FaweChunk fs) {
// Nothing
if (parent != null && !(fs instanceof MCAChunk) && !(fs instanceof NullFaweChunk) && parent instanceof NMSMappedFaweQueue) {
((NMSMappedFaweQueue) parent).refreshChunk(fs);
}
}
@Override
@ -101,18 +116,18 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, MCAChunk, MCAChunk,
}
@Override
public FaweChunk getFaweChunk(int x, int z) {
return getFaweQueueMap().getFaweChunk(x, z);
public FaweChunk getFaweChunk(int cx, int cz) {
return getFaweQueueMap().getFaweChunk(cx, cz);
}
@Override
public File getSaveFolder() {
return parent.getSaveFolder();
return saveFolder;
}
@Override
public boolean hasSky() {
return parent.hasSky();
return hasSky;
}
@Override
@ -147,4 +162,18 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, MCAChunk, MCAChunk,
public int getEmmittedLight(MCAChunk sections, int x, int y, int z) {
return sections.getBlockLight(x, y, z);
}
@Override
public void startSet(boolean parallel) {
if (parent != null) {
parent.startSet(parallel);
}
}
@Override
public void endSet(boolean parallel) {
if (parent != null) {
parent.endSet(parallel);
}
}
}

View File

@ -1,45 +1,159 @@
package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.example.IFaweQueueMap;
import com.boydti.fawe.example.MappedFaweQueue;
import com.boydti.fawe.example.NullFaweChunk;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MathMan;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class MCAQueueMap implements IFaweQueueMap {
private FaweQueue queue;
private Map<Long, MCAFile> mcaFileMap = new ConcurrentHashMap<>();
private NullFaweChunk nullChunk;
private boolean isHybridQueue;
public void setParentQueue(FaweQueue queue) {
this.queue = queue;
this.nullChunk = new NullFaweChunk(queue, 0, 0);
this.isHybridQueue = queue != null && !(queue instanceof MCAQueue) && (!(queue instanceof MappedFaweQueue) || ((MappedFaweQueue) queue).getFaweQueueMap() != this);
}
private MCAFile lastFile;
private int lastFileX = Integer.MIN_VALUE;
private int lastFileZ = Integer.MIN_VALUE;
public MCAFile getMCAFile(int cx, int cz) {
int mcaX = cx >> 5;
int mcaZ = cz >> 5;
if (mcaX == lastFileX && mcaZ == lastFileZ) {
return lastFile;
}
long pair = MathMan.pairInt(lastFileX = mcaX, lastFileZ = mcaZ);
lastFile = mcaFileMap.get(pair);
if (lastFile == null) {
if (mcaFileMap.containsKey(pair)) {
return null;
}
try {
lastFile = new MCAFile(queue, lastFileX, lastFileZ);
} catch (Exception e) {
e.printStackTrace();
return lastFile = null;
}
mcaFileMap.put(pair, lastFile);
}
return lastFile;
}
@Override
public Collection<FaweChunk> getFaweCunks() {
return null;
final List<FaweChunk> chunks = new ArrayList<>();
for (Map.Entry<Long, MCAFile> entry : mcaFileMap.entrySet()) {
MCAFile file = entry.getValue();
if (file != null) {
chunks.addAll(file.getCachedChunks());
}
}
return chunks;
}
@Override
public void forEachChunk(RunnableVal<FaweChunk> onEach) {
for (FaweChunk chunk : getFaweCunks()) {
onEach.run(chunk);
}
}
private FaweChunk lastChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@Override
public FaweChunk getFaweChunk(int cx, int cz) {
return null;
if (cx == lastX && cz == lastZ) {
if (nullChunk == lastChunk) {
nullChunk.setLoc(queue, lastX, lastZ);
}
return lastChunk;
}
lastX = cx;
lastZ = cz;
try {
MCAFile mcaFile = getMCAFile(cx, cz);
if (mcaFile == null) {
return lastChunk = null;
}
lastChunk = mcaFile.getChunk(cx, cz);
if (lastChunk != null) {
return lastChunk;
}
} catch (Throwable ignore) {
ignore.printStackTrace();
}
if (isHybridQueue) { // Use parent queue for in use chunks
lastChunk = ((MappedFaweQueue)queue).getFaweQueueMap().getFaweChunk(cx, cz);
if (lastChunk == null) {
System.out.println("Will work this out later.");
}
return lastChunk;
}
nullChunk.setLoc(queue, lastX, lastZ);
return lastChunk = nullChunk;
}
@Override
public void add(FaweChunk chunk) {
throw new UnsupportedOperationException("Not supported");
}
@Override
public void clear() {
mcaFileMap.clear();
if (isHybridQueue) {
queue.clear();
}
}
@Override
public int size() {
return 0;
int size = mcaFileMap.size();
if (isHybridQueue) {
size += queue.size();
}
return size;
}
@Override
public boolean next() {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
lastFileX = Integer.MIN_VALUE;
lastFileZ = Integer.MIN_VALUE;
if (!mcaFileMap.isEmpty()) {
Iterator<Map.Entry<Long, MCAFile>> iter = mcaFileMap.entrySet().iterator();
if (iter.hasNext()) {
MCAFile file = iter.next().getValue();
iter.remove();
file.flush();
file.close();
return true;
}
}
if (isHybridQueue) {
boolean value = queue.next();
return value;
}
return false;
}
}

View File

@ -31,7 +31,6 @@ public class PlotSquaredFeature extends FaweMaskManager {
private void setupBlockQueue() {
try {
// If it's going to fail, throw an error now rather than later
new FaweLocalBlockQueue(null);
QueueProvider provider = QueueProvider.of(FaweLocalBlockQueue.class, null);
GlobalBlockQueue.IMP.setProvider(provider);
HybridPlotManager.REGENERATIVE_CLEAR = false;

View File

@ -23,6 +23,7 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.jnbt.anvil.MCAQueue;
import com.boydti.fawe.logging.LoggingChangeSet;
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
import com.boydti.fawe.object.FaweLimit;
@ -254,6 +255,9 @@ public class EditSession implements Extent {
this.originalLimit = limit;
this.limit = limit.copy();
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), fastmode, autoQueue);
if (Settings.QUEUE.EXPERIMENTAL_UNSTABLE_DO_NOT_ENABLE_ULTRA_SUPER_FAST_WORLD_CORRUPTING_AWESOME_DIRECT_ANVIL_QUEUE_MODE) {
this.queue = new MCAQueue(queue);
}
queue.addEditSession(this);
this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), bus, event, Stage.BEFORE_CHANGE);
this.bypassHistory = (this.extent = wrapExtent(bypassAll, bus, event, Stage.BEFORE_REORDER));

View File

@ -127,6 +127,7 @@ public final class CommandManager {
checkNotNull(worldEdit);
checkNotNull(platformManager);
INSTANCE = this;
this.worldEdit = worldEdit;
this.platformManager = platformManager;
this.exceptionConverter = new WorldEditExceptionConverter(worldEdit);